Skip to content

Let a host gate on what a run did, not just what it claims - #207

Merged
shanev merged 2 commits into
mainfrom
feat/ready-answer-validator
Aug 4, 2026
Merged

Let a host gate on what a run did, not just what it claims#207
shanev merged 2 commits into
mainfrom
feat/ready-answer-validator

Conversation

@shanev

@shanev shanev commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Why

ready_metadata_validator is handed only model-written metadata. A host can therefore check the model's claims about its work, but never the work — which is enough for "assert nothing you did not support" and not enough for "do not answer without consulting the data".

That gap has a concrete cost. A downstream host shipped an answer reading "I don't have enough of your conversation with X available" on a corpus holding 15,333 matching messages, having never called an accessor. Its metadata-only validator saw an answer citing nothing, found nothing to reject, and passed it.

What

  • ready_answer_validator — optional, receives ReadyAnswerState (metadata, content, iteration, calls made, successful calls). Purely additive; ready_metadata_validator is unchanged and still supported. Both run when both are supplied, and violations from either revoke readiness identically.
  • Trace ABI v8 → v9startup gains optional ready_gates, naming the gates the run armed.

On the ABI bump

Enforcement here is opt-in and defaults to off, so a host that never passes policy_hints runs with ready_violations and contract_violations permanently inert — and emitted a trace identical to a fully gated run. One embedder shipped months in that state while its benchmark suite passed hints and measured the enforced configuration. No test could fail, because nothing recorded which system was running.

That is precisely the silent degradation UPGRADING.md exists to document, and it follows the v7 → v8 precedent (that bump was also additive — a new heartbeat event).

Embedders should assert on ready_gates in whatever verifies their production config, and treat an unexpectedly empty array as a misconfiguration rather than a default.

Verification

1261 passed, 3 skipped. Includes the v8 → v9 fixture/helper rename and a new test pinning the ready_gates schema.

🤖 Generated with Claude Code

shanev and others added 2 commits August 3, 2026 20:23
`ready_metadata_validator` receives only model-written metadata, so a host
can verify the model's claims about its work but never the work itself.
That is enough for "assert nothing you did not support" and not enough for
"do not answer without consulting the data" -- a behavioural rule needs
what the engine observed, not what the answer says about itself.

Add `ready_answer_validator`, called with a `ReadyAnswerState` carrying the
metadata plus answer content, iteration, and call counts. Both hooks run
when both are supplied and violations from either revoke readiness the same
way, so the older hook keeps working unchanged.

Trace ABI v8 -> v9: `startup` now reports `ready_gates`, the gates the run
actually armed. Enforcement is opt-in and defaults to off, so a host that
never passes policy_hints runs with ready_violations and
contract_violations permanently inert -- and until now emitted a trace
indistinguishable from a fully gated run. One embedder shipped for months
in that state while its benchmarks passed hints and measured the enforced
configuration; nothing could fail, because nothing recorded which system
was running.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ABI is cross-language and the fixture corpus is a shipped artifact, so
bumping the Python constant alone left three consumers on v8: the TypeScript
relay's envelope check and startup schema, the golden NDJSON the Deno tests
compare byte for byte, and the CI step asserting distributions bundle the
exact fixture filenames.

Teach the relay's startup schema about ready_gates, move every v8 envelope
literal and fixture path to v9, and reformat step.py.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shanev
shanev merged commit b119e8b into main Aug 4, 2026
10 checks passed
@shanev
shanev deleted the feat/ready-answer-validator branch August 4, 2026 00:38
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