Skip to content

feat: pin-to-contract from the per-call view — the console closes the loop#44

Merged
quantumCF merged 3 commits into
mainfrom
console/pin-to-contract
Jul 23, 2026
Merged

feat: pin-to-contract from the per-call view — the console closes the loop#44
quantumCF merged 3 commits into
mainfrom
console/pin-to-contract

Conversation

@quantumCF

Copy link
Copy Markdown
Contributor

Wave A PR-3, completing the console program: every scored candidate moment in the per-call view can mint the portable regression contract.

  • POST /calls/<subject>/pin — serve's one write action, delegating to the existing fleet machinery (ingest → discover → contract_from_candidate); no contract-minting logic lives in the server. Trust preflight, mint refusals, and registry writes keep their CLI semantics: any refusal is a 4xx with reason and never a partial artifact.
  • Fail-closed identity binding: the form carries the score record's evidence_sha256 (sidecar rebuilt since render → refuse); the recording is re-scanned and the moment's onset must reproduce exactly (file changed on disk → refuse).
  • Security posture for the first write route: bearer/cookie auth; same-origin fence failing closed on missing Origin/Referer; every accept and refusal audit-logged; plain-HTML form works without JS.
  • A sealed decision cannot be silently re-judged: re-pin with the same decision is idempotent; re-pin with a different decision refuses (409) — the response never confirms a write that didn't happen.
  • Naming honesty (R10): "Production health" → "Suite health" everywhere (route-compat kept); nav reads Calls · Suite health · Failure clusters · Failure records · Release readiness.
  • Feed header shows "N contracts protecting this agent" from the fleet registry's contracts table. 15 tests in tests/test_serve_pin.py; THREAT-MODEL/SELF-HOST/WORKSPACE docs updated; llms-full regenerated.

Independently verified by a fresh reviewer with its own fixtures and a live curl-driven server: happy path re-verified through contract verify (signed, PASS), unauthenticated/CSRF-forged/injected/oversized requests all refused with zero artifacts (dir snapshots), duplicate-pin idempotency, audit entries for both outcomes, loopback + read-only GETs unchanged, full suite green except the two known machine-environmental failures. The verifier's one adversarial find (changed-decision re-pin returned a false confirmation) is fixed in the second commit with its regression test.

Spec: hotato-growth/research/CONSOLE-WAVE-A-SPEC.md (R9–R11)

https://claude.ai/code/session_015njkxtoAKioqTPT2k14xFr

… loop (Wave A PR-3)

R9: POST /calls/<id>/pin, serve's first and only write route. Delegates to
the existing fleet machinery (ingest_recording -> discover ->
contract_from_candidate): human label + sealed .hotato bundle + registry
registration in one atomic step; refusals mirror the CLI (4xx with reason,
no artifact) for NOT_SCORABLE/ERROR calls, bad candidate refs, stale
evidence_sha256 bindings, changed recordings (re-scan must reproduce the
onset), and trust-preflight refusals. Auth = the same bearer/cookie check
as every view; CSRF fence = SameSite=Strict cookie + same-origin
Origin/Referer check on cookie-authenticated POSTs (bearer needs none);
every attempt lands one append-only audit line. Per-call pin forms are
plain HTML POST (work without JS; fetch enhancement shows results inline);
the /calls feed header shows 'N contracts protecting this agent' counted
from the fleet registry's contracts table.

R10: 'Production health' -> 'Suite health' everywhere it surfaces (title,
heading, nav, docs, JSON view id suite_health); /health + /production
routes unchanged. Nav reads Calls · Suite health · Failure clusters ·
Failure records · Release readiness; scenario matrix becomes a Release
readiness drill-in.

R11: a finalized (COMPLETE/DEGRADED) session's per-call view surfaces the
exact 'hotato production export-regression' command for that session.

Docs (WORKSPACE/SELF-HOST/THREAT-MODEL/llms) updated + llms-full rebuilt;
CHANGELOG additive; 14 new tests in tests/test_serve_pin.py.
The fleet API reconciles a re-pin of the same candidate by reusing its
sealed bundle; pin.py echoed the REQUESTED decision, so a re-pin with a
different decision returned 200 confirming a write that never happened.
Read back the sealed decision and refuse the mismatch loudly.

Found by the fresh adversarial verifier beyond the shipped test coverage.

Claude-Session: https://claude.ai/code/session_015njkxtoAKioqTPT2k14xFr
@github-actions

Copy link
Copy Markdown

hotato turn-taking eval

8 of 8 scenarios pass. 0 fail. No regression.

scenario expect yielded time to yield talk over result
01-hard-interruption yield yes 0.50s 0.50s pass
02-backchannel-mhm hold no - 1.57s pass
03-filler-start yield yes 0.65s 0.56s pass
04-correction yield yes 0.50s 0.50s pass
05-telephony-8khz yield yes 0.50s 0.50s pass
06-double-talk yield yes 1.05s 1.05s pass
07-echo-bleed hold no - 3.00s pass
08-rapid-turn-taking yield yes 0.50s 0.50s pass

Regressions

None.

Reproducible timing measured locally from call audio. Swap the bundled self-test step for your own captured recordings to gate on your agent. github.com/attenlabs/hotato

@quantumCF
quantumCF merged commit 51f1d0d into main Jul 23, 2026
15 checks passed
@quantumCF
quantumCF deleted the console/pin-to-contract branch July 23, 2026 22:50
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