Skip to content

Close the model-approval gate's boot hole, and test the chain at its joins - #777

Merged
xmap merged 2 commits into
mainfrom
worktree-language-model-gate-boot
Sep 6, 2026
Merged

Close the model-approval gate's boot hole, and test the chain at its joins#777
xmap merged 2 commits into
mainfrom
worktree-language-model-gate-boot

Conversation

@xmap

@xmap xmap commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Item 3 of the brain-arc follow-ups. Two commits, one knot.

The defect

deps.py documents a deliberate two-layer posture: the make_*_kernel primitives default to disarmed stubs so an integration test never seeds what it does not exercise, and the fail-loud requirement lives one layer up, in build_kernel's Postgres branch, which raises when a factory a real deployment must bind is missing.

language_model_lookup had its first half and never got its second. The obligation is recent: until seed_agent started checking a seeded Agent's model, the seeds appended directly and no seeded agent was gated at all, so a missing lookup was genuinely harmless. Arming that gate created the obligation, and nothing discharged it.

The stub does not weaken this gate, it removes it. AlwaysApproved answers every identity with an Approved entry, so define_agent and seed_agent both keep passing and nothing records that no catalog was consulted.

Three docstrings said the settled posture was permissive. The kernel field's cited "the spend_lookup opt-in posture" as authority, and spend_lookup is the one field in the family with no default at all plus a named place in this same guard. Reading half that precedent is the plausible route to the gap.

The second half

Seeding an LLM-brained Agent reaches its verdict through five links: seed the catalog streams, project them into proj_agent_language_model_summary, drain so the rows are visible, read them, gate on the answer. Every link had a test. Nothing crossed a join.

The adapter's integration test fills the read model by hand-written INSERT, so it proves the SQL reads a correct table and cannot see whether anything fills it. The drain covering this projection was asserted nowhere: both architecture guards read main.py and assert about main.py.

That matters more after commit 1, which is the honest argument for doing both together. Before, a broken chain was quiet, because the stub approved everything. Now the gate is guaranteed armed, so a broken chain refuses boot, and the two agents that declare real Anthropic models are exactly the ones refused.

Verification

Mutation, both directions:

  • Dropping the projection from register_agent_projections fails two of the three new tests while the architecture guard and the adapter integration test both stay green. That is the gap stated as an experiment.
  • Swapping the real adapter back to the stub fails exactly the refusal test.
  • Disabling the boot guard fails exactly its own new test and nothing else.

That second mutation also showed the end-to-end test passes under the stub on its own, so its docstring now says it is only meaningful paired with the refusal test, rather than letting a later reader take it for an independent check.

1,377 integration + 52,350 unit and architecture passing.

Known gap, not closed here

No CI check asserts that main.py binds this factory, or the financial pair either. Deleting the binding is caught at boot, not in the suite.

🤖 Generated with Claude Code

xmap and others added 2 commits September 6, 2026 11:48
The lookup family has a two-layer posture that deps.py states in prose:
the make_*_kernel primitives default to disarmed stubs so an integration
test never seeds what it does not exercise, and the fail-loud requirement
lives one layer up, in build_kernel's Postgres branch, which raises when a
factory a real deployment must bind is missing.

language_model_lookup had its first half and never got its second. The
obligation is recent: until seed_agent started checking a seeded Agent's
model, the seeds appended directly and no seeded agent was gated at all,
so a missing lookup was genuinely harmless. Arming that gate is what
created the Layer B obligation, and nothing discharged it.

The stub does not weaken this gate, it removes it. AlwaysApproved answers
every identity with an Approved entry, so define_agent and seed_agent both
keep passing and nothing anywhere records that no catalog was consulted. A
disarmed gate and an approving one are indistinguishable from the outside,
and this gate is the only place the facility's model-provenance constraint
is enforced. So the absence stops startup instead of reading as agreement.

Operationally this costs nothing: main.py binds the factory in source, not
configuration, so no operator can leave it unset. The guard fires only if
that binding is deleted, which is what it is for.

Three docstrings claimed the settled posture was permissive. The kernel
field's said it "mirrors the spend_lookup opt-in posture", citing as
authority for permissiveness the one field in the family with no default
at all and a named place in this same guard. Reading half that precedent
is the plausible route to the gap, so all three now state both halves.

Verified by mutation: disabling the guard fails exactly the new test and
nothing else. 52,318 unit + architecture passing.

Not covered, and deliberately left for the chain test: no CI check asserts
that main.py binds this factory, or the financial pair either. Deleting
the binding is caught at boot, not in the suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seeding a LanguageModel-brained Agent reaches its verdict through five
links: seed_language_models appends the catalog streams, the projection
turns those events into proj_agent_language_model_summary rows,
drain_projections advances the bookmark so the rows are visible,
PostgresLanguageModelLookup reads them, and seed_agent's gate consumes the
answer. Every link had a test. Nothing crossed a join.

The adapter's own integration test is the clearest case: it fills the read
model by hand-written INSERT, so it proves the SQL reads a correct table
and cannot see whether anything fills it. The drain covering THIS
projection was asserted nowhere, because both architecture guards read
main.py and assert about main.py, which can show a drain call sits between
the two seeds but not that it reaches the table the gate will read.

So the whole sequence could break with a green suite. Dropping the
projection from register_agent_projections is the one-line version, and
until now it failed nothing while making a fresh boot refuse both shipped
agents that declare real Anthropic models.

Three tests, reproducing the composition root's real sequence with the
REAL adapter bound, which build_postgres_deps otherwise leaves at the
always-approved stub: the chain admits CautionDrafter; the same kernel
REFUSES when the drain is removed, which is what makes the drain
load-bearing rather than incidental; and the drain fills the specific
identity the gate asks for, so a failure names the broken link.

Verified by mutation, both directions. Dropping the projection from the
registry fails two of the three while the architecture guard and the
adapter integration test both stay GREEN, which is the gap stated as an
experiment. Swapping the real adapter back to the stub fails exactly the
refusal test. That second mutation also shows the end-to-end test passes
under the stub on its own, so its docstring now says it is only meaningful
paired with the refusal test rather than letting a later reader take it
for an independent check.

Adds a language_model_lookup passthrough to build_postgres_deps; the
binding had no way in before.

1,377 integration + 52,350 unit and architecture passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/infrastructure
  deps.py
  kernel.py
  apps/api/src/cora/infrastructure/ports
  language_model_lookup.py
Project Total  

This report was generated by python-coverage-comment-action

@xmap
xmap merged commit b10e3a4 into main Sep 6, 2026
19 checks passed
@xmap
xmap deleted the worktree-language-model-gate-boot branch September 6, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant