Skip to content

feat(contracts): freeze MCP tool schemas + COM2 wire/attestation format (ADR-0020 complete) - #226

Merged
NickFlach merged 1 commit into
mainfrom
feat/adr-0020-freeze-lanes
Jul 15, 2026
Merged

feat(contracts): freeze MCP tool schemas + COM2 wire/attestation format (ADR-0020 complete)#226
NickFlach merged 1 commit into
mainfrom
feat/adr-0020-freeze-lanes

Conversation

@NickFlach

Copy link
Copy Markdown
Collaborator

Completes ADR-0020: the two deferred v1-freeze lanes, mirroring the proven ABI-golden discipline (#206–211). Design attacked pre-implementation by a 2-lens adversarial panel (21 findings, 4 blockers — all folded in).

Lane C — contracts/wire/v1.golden (COM2 wire + attestation)

  • Guest ring compiler-measured by user/wire_probe.c (the .abi_ents pattern): framing, opcodes, Lamport params, CRC8 poly/init, reply-auth geometry, FSYN/FSYP sizes+offsets, attestation KATs derived from shared macros — the emitters in swarm_svc.c now use the same macros the probe measures, so the golden freezes the code path, not a transcription.
  • Host ring extracted from the live qos_bridge.py constants (now hoisted and used in the real parser/verifier paths). The twin rule + MUST_TWIN set turn guest↔host drift — previously guarded only by a code comment — into a red diff. host:kat:ping_frame freezes byte order + CRC span in one measured number.
  • Teeth: guest -DSWARM_MAGIC_OVERRIDE recompile + host QOS_WIRE_TEETH twin-mismatch, both asserting rc==1 exactly plus the specific mutated marker (exit 1 is reserved for diffs; operational errors exit 2 — an inverted teeth-check must not pass on a crash).

Lane B — contracts/mcp/v1-tools.json (22 tools)

  • Freezes name + inputSchema; descriptions and result-dict shapes deliberately excluded (recorded in _meta — doc honesty fixes must stay cheap; result shapes belong to the ADR's machine-readable agent docs item).
  • Normalizes away pydantic's volatile title/description keys; pins mcp==1.28.1/pydantic==2.13.4/pydantic-core==2.46.4 in requirements-mcp-gate.txt and the golden _meta, with an importlib self-check (GENERATOR SKEW, rc 2) so a wrong-environment regen cannot be committed silently.
  • Teeth live in the extractor (production qos_mcp.py ships zero test code): changed-value AND added-name mutations both proven caught.
  • New pinned-pip CI job (pip cache + retries); the wire lane extends the stdlib-only abi-golden job. Selftests run before gates in both.
  • Pre-freeze fix: qos_society_boot_n(qseeds: list)list[str].

Verification (local WSL)

All four gates+selftests green; kernel build green; keyadmit/replyauth/qsubmit-replyauth behavioral gates green after the host-constant refactor; ci-smoke-latency green (0.05s, +24 boosts); full ci-smoke PASSED; abi golden unaffected.

Follow-ups for the maintainer

  • Add wire-golden steps' job + mcp-schema to branch-protection required checks.
  • Optional: retrofit the header-comment block onto contracts/abi/v1.golden.
  • The audit_entry_t actor-reserve decision remains open per the ADR (deliberately untouched).

🤖 Generated with Claude Code

…format; ADR-0020 complete

The two deferred v1-freeze lanes from ADR-0020, mirroring the ABI golden
discipline (#206-211): committed goldens, human-only regen, check-only
gates, teeth-before-gate CI ordering.

Lane C — contracts/wire/v1.golden (79 entries, guest+host twin rings):
- user/wire_probe.c: compiler-measured guest ring (.abi_ents pattern) —
  framing, opcodes, Lamport params, CRC8 poly/init, reply-auth geometry
  (nonce/tag/key/body lens), FSYN/FSYP sizes+offsets, and attestation
  KATs PACK8-derived from SHARED macros (a hand-typed KAT would freeze
  the probe's copy, not the emitter's — panel blocker)
- user/swarm.h + user/swarm_svc.c: the wire literals hoisted to macros
  and used at the emitter sites (mechanical, value-preserving; the
  _Static_assert ties QSUBMIT_BODY_OK to QC_RESULT_LEN)
- user/fsyn.h: FSYN/FSYP frames extracted from fieldsyncd.c,
  self-contained, MAC_COVERED==offsetof(tag) statically asserted
- scripts/qos_bridge.py: host constants hoisted (CRC8 params, attest
  grammar heads, reply-auth lens) and used in the live code paths — the
  host ring is extracted from the REAL parser, closing the guest<->host
  drift gap that was previously only a code comment; twin rule + a
  MUST_TWIN set make one-sided OR coordinated drift a red diff;
  host:kat:ping_frame freezes byte order + CRC span in one number
- scripts/extract-wire.py: exit 1 RESERVED for diff/twin (2 for
  operational errors — an inverted teeth-check must not pass on a
  crash); QOS_WIRE_TEETH perturbs the TWINNED host magic; emit refused
  under teeth; header comments stripped in check

Lane B — contracts/mcp/v1-tools.json (22 tools, name+inputSchema):
- scripts/extract-mcp-schema.py: FastMCP list_tools introspection;
  recursively strips title/description inside schemas (pydantic's
  highest-volatility output — descriptions are deliberately NOT frozen:
  doc honesty fixes must stay cheap); _meta pins mcp==1.28.1 +
  pydantic==2.13.4 + pydantic-core==2.46.4 with an importlib version
  self-check (GENERATOR SKEW, rc 2, rejected by the selftest as a pass)
- teeth live in the EXTRACTOR (production qos_mcp.py carries zero test
  code): =del mutates an existing tool's schema (changed-VALUE — the
  abi_probe lesson), =add appends a bogus tool
- qos_mcp.py: qseeds list -> list[str] (pre-freeze fix; bare list is the
  most version-churn-prone schema rendering)
- requirements-mcp-gate.txt + Makefile venv (WSL python is PEP-668
  externally-managed) + new pinned-pip ci.yml job with pip cache

.gitattributes: contracts/** text eol=lf (the ABI golden was already
CRLF-smudged in Windows working trees).

Verified locally (WSL): all four gates+selftests green (teeth assert
rc==1 exactly AND the specific mutated marker); kernel build green;
keyadmit/replyauth/qsubmit-replyauth behavioral gates green after the
qos_bridge refactor; ci-smoke-latency green (0.05s, +24 boosts); full
ci-smoke PASSED; abi golden gate+selftest unaffected.

Follow-ups for the maintainer (recorded in the ADR): add the new job
names to branch-protection required checks; optional abi-golden header
retrofit. The audit_entry_t actor-reserve call remains open per the ADR.

ADR-0020: all three lanes complete.

Co-Authored-By: Claude Fable 5 <[email protected]>
@NickFlach
NickFlach merged commit 7908005 into main Jul 15, 2026
26 checks passed
@NickFlach
NickFlach deleted the feat/adr-0020-freeze-lanes branch July 15, 2026 03:56
NickFlach added a commit that referenced this pull request Jul 15, 2026
…, rebirth-proof IPC (#227)

VERSION 0.5.0 -> 0.5.1; CHANGELOG [Unreleased] -> [0.5.1] with this
cycle's entries appended (#219-#226: ADR-0023 IPC rebirth re-wiring,
the ADR-0022 I/O-priority-boost latency epic, the ADR-0020 MCP + wire
freeze lanes completing the v1 contract freeze, and the fix sweep).

Co-authored-by: The Hand <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
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