Skip to content

core: single-source provider metadata (#19) + resolve config once per call (#15)#33

Merged
ernestprovo23 merged 1 commit into
mainfrom
cluster/core
Jun 9, 2026
Merged

core: single-source provider metadata (#19) + resolve config once per call (#15)#33
ernestprovo23 merged 1 commit into
mainfrom
cluster/core

Conversation

@ernestprovo23

Copy link
Copy Markdown
Member

Core call-path cluster (Wave 2). Two tech-debt items in the provider call path, implemented serially. No changes to council.py, cli.py, transport.py, or adapters/ (owned by parallel clusters).

closes #19
closes #15

#19 — single source of truth for provider metadata (KeyError escape)

Provider metadata was split: env-var names in registry.PROVIDER_ENV_VARS, URLs in adapters.openai_compat.OPENAI_COMPAT_URLS. The two could silently drift; a half-declared OpenAI-compatible provider surfaced as a runtime KeyError in adapters._openai_compat_adapter that escaped the ProviderError handler into the broad except Exception.

  • registry.py is now the single source of truth: OPENAI_COMPAT_PROVIDERS (prefix -> URL + env vars, via a frozen OpenAICompatProvider) and NATIVE_PROVIDERS are the authoritative tables. PROVIDER_ENV_VARS is derived from them, so it can never desync.
  • New RegistryError + _assert_metadata_consistent() runs at import time and fails loudly if adapters.OPENAI_COMPAT_URLS ever drifts from the registry (extra/missing prefix, URL mismatch, or a URL with no env var). The former silent per-call KeyError becomes an immediate, diagnosable startup error.
  • adapters/ was intentionally left untouched (parallel cluster owns it); the import-time guard is the in-bounds mechanism that makes drift impossible to ship.
  • Per-provider edit step documented in the registry module docstring.

#15 — call_model re-read config from disk on every call (caching blocker)

call_model called load_config() per invocation (~13 disk reads + YAML parses in a 4x3 debate + synthesis).

  • call_model gains an optional config param (default None, fully backward compatible). When injected it's used directly; when omitted it falls back to a now-memoized load_config.
  • load_config memoizes by (path, mtime): self-invalidates when the file changes (preserves always-fresh-across-edits behavior), serves repeated same-file calls from memory. clear_config_cache() added for tests/long-lived processes.
  • The memoization removes the per-call disk read without threading config through council.py, so council.py/cli.py/transport.py/adapters stayed untouched. The public call_model signature is unchanged for existing callers (new param is keyword-only, optional).

Tests (79 passed; 68 baseline + 11 new)

🤖 Generated with Claude Code

… call (#15)

#19 — single source of truth for built-in provider metadata
- registry.py now owns OPENAI_COMPAT_PROVIDERS (prefix -> URL + env vars) and
  NATIVE_PROVIDERS as the authoritative tables; PROVIDER_ENV_VARS is derived
  from them so it can never drift.
- Add an import-time _assert_metadata_consistent() guard (RegistryError) that
  fails loudly if adapters.OPENAI_COMPAT_URLS ever drifts from the registry,
  converting the former silent per-call KeyError into an immediate, diagnosable
  startup error. (adapters/ left untouched per cluster ownership.)

#15 — config resolved once / injectable, not re-read per call
- call_model gains an optional config param (backward compatible default None);
  when omitted it falls back to a now-memoized load_config so even repeated
  standalone calls avoid redundant disk reads + YAML parses.
- load_config memoizes by (path, mtime): self-invalidates on file change,
  preserves always-fresh-across-edits behavior; clear_config_cache() for tests.
- council.py/cli.py/transport.py/adapters left untouched: memoization removes
  the per-call disk read without threading config through council.

Tests: single-source/no-drift + import-time guard (url drift, missing url, url
mismatch); injected-config means no load_config; standalone reads disk at most
once over a 13-call burst; full Council.ask hits disk at most once per run.
79 passed (68 baseline + 11 new); ruff check + format clean.
@ernestprovo23 ernestprovo23 merged commit 7fc4ee9 into main Jun 9, 2026
5 checks passed
@ernestprovo23 ernestprovo23 deleted the cluster/core branch June 10, 2026 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant