Skip to content

feat: per-call response verification at the proxy - #14

Merged
Mhemd139 merged 3 commits into
spec/per-call-verificationfrom
feat/per-call-verification
Jul 25, 2026
Merged

feat: per-call response verification at the proxy#14
Mhemd139 merged 3 commits into
spec/per-call-verificationfrom
feat/per-call-verification

Conversation

@Mhemd139

Copy link
Copy Markdown
Owner

Implements the v0.2.0 design spec (#13). Stacked on the spec branch - merge #13 first, then retarget or merge this.

What

The proxy now verifies every tools/call response it forwards, not just schemas at list time. The window between two checks - where a server can start lying and every call sails through - is closed.

  • Reference hierarchy (compiled once per baseline load): declared outputSchema -> core fingerprint (intersection of the tool''s baselined probe fingerprints) -> unverifiable, counted as unverified.
  • Only output-side BREAKING classes block: reference field missing, structural retype, forbidden null, pinned value mismatch. Scalar retypes record DEGRADED and forward. Extra fields pass (classifier parity - additionalProperties: false deliberately not enforced).
  • Two-bucket quarantine: sync() owns the schema bucket only, so the in-band tools/list sync on client connect cannot release a response-caught liar. POST /covenant/refresh clears the response bucket; /covenant/status shows each entry''s source.
  • SSE interception: only POST tools/call streams are frame-parsed; only the frame with the matching JSON-RPC id is held (one frame''s latency), notifications stream through; 1 MiB cap -> skipped_large; the GET listen stream is never touched.
  • Failure policy: verifier exceptions log and forward original bytes - the firewall never drops traffic because its own inspection broke.
  • --observe: detect, record, count - never block. WAF monitor/prevention rollout pattern.
  • snapshot now embeds expect pins into the lock (the proxy reads only the baseline); lock re-snapshotted, diff is exactly the pin.
  • New metric: covenant_response_verifications_total{tool, outcome}.

Demo

Start the proxy, restart the upstream with COVENANT_BEHAVIOR_DRIFT=1 (or the new COVENANT_SHEKEL_DRIFT=1 - ILS values still labeled balance_usd, schema and shape identical). The very next call is blocked and the tool quarantined - no refresh, no tools/list, no CI run.

Tests

37 new tests (verifier unit, quarantine buckets, proxy JSON + SSE paths, observe mode, refresh release). Full suite green; ruff and strict mypy clean. Three pre-existing tests had mock upstreams returning bare text against a declared object outputSchema - under this feature that is a genuine violation, so those mocks now honor their own schema.

🤖 Generated with Claude Code

Mhemd139 and others added 3 commits July 26, 2026 01:17
Every forwarded tools/call response is verified against a per-tool reference:
declared outputSchema, else the core fingerprint (intersection of baselined
probe fingerprints). Output-side BREAKING classes (missing field, structural
retype, forbidden null, pinned value mismatch) block the response and
response-quarantine the tool; scalar retypes record DEGRADED and forward.

- covenant/verify.py: pure verifier (Layer 0) - references, tiers, pins
- quarantine: two buckets; sync() owns schema only, refresh clears response
- proxy: JSON + SSE interception (only the matching result frame is held),
  1 MiB verify cap, verifier exceptions forward original bytes
- metrics: covenant_response_verifications_total{tool, outcome}
- cli: covenant proxy --observe; snapshot embeds expect pins into the lock

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ILS amounts still labeled balance_usd: schema, shape, and field name all
identical, only the value lies. The committed pin blocks it per-call.
The proxy reads only the lock, so a pin must live there to be enforceable
per-call. Only change: the expect block on the get_account probe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 23cedf42-c077-4545-a3a9-ff0cbbcdbdcc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/per-call-verification

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Mhemd139
Mhemd139 merged commit 3eee939 into spec/per-call-verification Jul 25, 2026
5 checks passed
@Mhemd139
Mhemd139 deleted the feat/per-call-verification branch July 25, 2026 22:37
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