Skip to content

Seam conformance: the harness registry, the drift definition, and a derived tier table - #146

Merged
jothimani-rajendran merged 3 commits into
mainfrom
claude/seam-conformance-and-harness-registry
Sep 13, 2026
Merged

jothimani-rajendran merged 3 commits into
mainfrom
claude/seam-conformance-and-harness-registry

Conversation

@jothimani-rajendran

Copy link
Copy Markdown
Collaborator

What this changes

The three obligations the 2026-09-13 owner decision ("policies test the seam, not the vendors") created, each as its own commit and none of them needing a vendor token to build:

  1. harness.py + data/harness.json — the vendor registry the a11y pack paid for, moved out of prototypes/a11y-guard/scenarios/scenarios.json: argv per vendor, the model flag and the position it must go in, what voids a run, Codex's trust gating, and Windows file ownership.
  2. conformance.py — the definition of the difference that condemns this layer, so "then agentseam is half cooked" is testable rather than quotable.
  3. tier_table.py + agentseam tier-table — the enforcement table derived from the matrix instead of hand-maintained in each consumer's instructions.

No matrix row, capability or basis changed. Nothing here claims a new measurement.

Claim check

  • No capability claim is widened without a mechanism behind it — no MATRIX cell is touched; tier_table only reads enforcement_level(), which is already basis-capped
  • Any new/changed MATRIX row carries a verified record — no rows added or changed
  • Payload shapes come from a primary source — data/harness.json was generated from prototypes/a11y-guard/scenarios/scenarios.json rather than retyped, so the recorded prose (Codex trust inheritance, the --full-auto rename between 0.150.1 and 0.154.0, Windows file ownership) arrives verbatim from the runs that established it. Agent ids were remapped to canonical matrix ids (codexcodex_cli, claudeclaude_code), and a test asserts every harness row is a known matrix row.

Checks

  • pytest -q passes — 1656 passed, 4 skipped (1615 on main; +41 from the three new test files)
  • ruff check . and ruff format --check . pass — both clean, fixed per-rule rather than by a blanket --fix
  • Runtime path is still stdlib-only — the new modules import only json/pathlib via the existing _data.load
  • Commits are signed off

Notes for the reviewer

Two defects I introduced and caught, both by running cases rather than reading the diff:

  • conformance.classify short-circuited on agreement before checking capability, so two vendors that cannot enforce — which will always return the same thing — reported as AGREED. An untested policy reading as a passing one is precisely the papering-over the module exists to forbid. Capability is now settled first, and test_unanimity_among_vendors_that_cannot_enforce_is_not_agreement pins the order.
  • test_the_word_drift_is_not_reused_for_this_concept was written as a fragile occurrence-count and asserted the wrong arithmetic. Rewritten to state the intent directly: the word may appear in the docstring, never in the code.

Worth your judgement — the derived table disagrees with the hand-written one on every row they share. Against the four rows in the chock-family instructions: claude_code derives fail_mode: open / basis: live-run where the table says fail-closed / vendor-docs; cursor derives configurable / live-run-partial against fail-closed / vendor-docs; devin derives block+rewrite / open against n/a; and copilot derives unadapted with no hook surface at all against T3 / hook + CI. The claude_code fail-open reading matches the witnessed run. But the two tables' Fail mode columns may not be asking the same question — the hand-written one is captioned "where each agent reading this file is actually stopped", which could mean the control fails closed rather than the vendor's hook. Worth settling what that column means before anything regenerates from this.

Purity. tier_table refuses to render a column it does not own, so T3 / hook + CI / CI only cannot leak into the engine; a test asserts no consumer vocabulary reaches the output or the module body.

The cli.py split. cli.py sat at exactly the 300-line budget, so the read-only verbs moved to cli_report.py — split by activity, the remedy the budget test names. No behaviour changed, and since the suite does not exercise parser dispatch I re-ran matrix, matrix --evidence, doctor and both tier-table forms through the CLI by hand.

Still needs your machine, unchanged by this PR: the three witness-skeleton.json gaps (pre_tool/escalate, prompt_submit, stop) — all three are --agent claude_code, so no other vendor's tokens are involved.


Generated by Claude Code

Owner decision, 2026-09-13: vendor knowledge belongs in the seam, not in a
prototype. prototypes/a11y-guard/scenarios/scenarios.json holds an `agents` map
that is a vendor adapter registry in all but name -- argv per vendor, the model
flag plus the position it has to go in, what voids a run, how Codex gates its
sandbox on trust recorded outside the workspace, and that a file the agent
creates on Windows is owned by an account the harness cannot read.

None of that is inferable and all of it was paid for by losing runs. Eleven
Codex runs were voided by a throwaway CODEX_HOME carrying no trust entries;
`--full-auto` stopped existing between two minor versions. Left in a prototype,
the next pack rediscovers each at the same price.

Generated from that file rather than retyped, so nothing was lost in
transcription, and keyed by canonical matrix ids -- a row whose agent the matrix
does not know is now a test failure rather than a lookup that quietly misses.

The module's invariant is a refusal: an agent with no recorded row gets
NoHarnessError, never a guessed command line. A guess is the failure mode worth
designing against because its output is indistinguishable from a real result.
The same discipline covers the hooked arm -- codex_cli has no established one,
and asking for it raises with the recorded reason instead of silently falling
back to the unhooked argv and measuring the wrong thing.

void_markers is that rule aimed at output: it names evidence the agent was
PREVENTED from working, which is not an agent that looked and chose to do
nothing. The first measured nothing; the second is the data point. The caller
applies the gate, since it only discriminates for a run that changed no files.

17 tests, including that no invocation is hardcoded in the module and that a
prompt containing braces survives (placeholders are replaced, never formatted).
ruff and ruff format clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
The 2026-09-13 decision says a policy is tested against the seam and the seam
against the vendors, once -- and that if drift remains, agentseam is half cooked.
That rule could be quoted but not enforced, because nothing said which
differences count. Not all of them do: copilot failing open where others fail
closed is a true property of copilot, and the matrix says so out loud.

The line drawn here: a policy's verdict must be identical across every vendor
that CAN reach it, and where a vendor cannot, the shortfall is reported rather
than papered over. A verdict differing between two vendors the matrix says are
equally able has no explanation in the world, so it is this layer leaking a
dialect into a policy's result. SEAM_GAP is that call, and is_seam_gap() is the
one-line form a CI gate can hold.

Named divergence, not drift, on purpose: staleness.DRIFTED already means a vendor
shipped a new version since a row was recorded. Same English word, unrelated
question, and this track has lost time to that kind of collision before. A test
asserts the word stays out of the code here.

Two refusals carry the honesty. An unrecorded vendor is never excused -- treating
it as "cannot enforce" would let any divergence be waved through by the absence
of evidence, which is the papering-over the rule forbids; capable() raises where
it would otherwise have to answer False. And capability is settled BEFORE
agreement: two vendors that cannot enforce will always return the same thing, and
an earlier revision of this file reported that as AGREED -- an untested policy
reading as a passing one. Caught by running the cases rather than by reading the
diff, and the regression test says why it must stay in that order.

14 tests. ruff and ruff format clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
Third obligation of the 2026-09-13 decision: if the seam owns vendor conformance,
the per-agent enforcement table is its output, not a thing kept in step by hand
in each consumer's instructions. A hand-written copy drifts silently and in the
direction that flatters -- nobody notices a table still claiming last month's
tier, and a table is exactly where a reader goes to avoid reading the code.

The grade column is why this is worth building rather than tidying: it is capped
by basis, so a row resting on vendor docs cannot print `enforced` however
confident its cell reads. A hand-written table has no such mechanism. Rendering
the derived table against the hand-written one in the chock-family instructions
disagrees on every row they share, which is the argument stated as a result.

What it deliberately will not emit is the consumer's own column. T3, `hook + CI`
and `CI only` are chock's vocabulary for how chock wires a control; agentseam
does not know them and must not learn them. It renders the columns it owns and a
consumer joins its wiring column on -- asking for a column this table does not
own is a refusal, not a blank cell. A test asserts no consumer vocabulary
reaches either the output or the module body.

An agent with no hook surface prints n/a rather than a weak fail mode: there is
nothing there to fail, and saying so keeps the absence visible.

cli.py was exactly at the 300-line review budget, so the read-only verbs moved to
cli_report.py. Split by activity, which is the remedy the budget test names: these
three report on evidence, everything left writes to a machine, and a verb that
only prints is safe to run anywhere. No behaviour changed -- matrix, matrix
--evidence and doctor were each re-run through the CLI after the move, since the
suite does not exercise parser dispatch.

10 tests for the table. 1656 passed, 4 skipped. ruff and ruff format clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
@jothimani-rajendran
jothimani-rajendran marked this pull request as ready for review September 13, 2026 22:52
@jothimani-rajendran
jothimani-rajendran merged commit f6ae973 into main Sep 13, 2026
16 checks passed
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.

2 participants