Skip to content

[E01] Freeze v1 engineering record and approval contracts #399

Description

@TheAmericanMaker

Context and scope

Part of the incremental CodeCartographer engineering evolution. Planned, not shipped. Read the agent handoff, vision/decisions, record contract, and implementation plan. Documentation baseline PR #410 is merged at bbdf6b1a8b3bc348aa9e8f20a409c66df087af13. Follow this issue's prerequisite gates before starting.

Host-executed/framework-tracked; preserve analysis state ABI, both Pi analysis guards, and current synthesis confirmation gates. Ordinary in-place changes accept zero external references. No implicit source execution, provider spend, GitHub write, release/deployment, or private-data publication. E01 owns schema/API/authority decisions; dependent workers consume its merged contract rather than inventing another.

Tracking: #398

Blocked by: None; ready after the documentation PR is merged.

Objective: give downstream agents one reviewed, executable contract, including an honest host-approval boundary.

Depends on: none. Read: docs/engineering/record-contract.md, core/types.ts, core/utils.ts, core/status.ts, core/secrets.ts, core/synthesis.ts, existing guard and closure tests.

Files: create core/engineering/types.ts, core/engineering/validation.ts, core/engineering/index.ts, tests/engineering-contract.test.mjs, tests/fixtures/engineering/v1/; update docs/engineering/record-contract.md and the minimal core/index.ts export when needed.

Steps:

  1. Pin JSON envelopes, ID/path grammar, required fields, schema-version behavior, enum spellings, action/result shapes, and canonical digest inputs from the design contract. Explicitly enumerate required records for acceptance.
  2. Write fixture tests for valid/minimal records and rejection of unknown versions, absent bindings, duplicate IDs, traversal, invalid states, cross-change links, and malformed proof/review records; run RED.
  3. Implement pure validators with structured error results. They validate data, never run tools or write project state. Keep JSON examples valid and independently parseable.
  4. Threat-model human approval and host identity. Specify a host-controlled receipt path not mintable through an ordinary agent tool call, plus unsupported-host behavior. Document the cooperative same-user-filesystem limitation, replay binding, and what is actually authenticated.
  5. Have the approval contract independently reviewed; freeze it in this document with examples and negative cases, then run GREEN and full gates.

Acceptance: a downstream implementer can consume the merged schemas and public operation signatures without inventing fields; malformed data is rejected deterministically; no approve: true agent payload becomes human acceptance. If the trusted receipt design remains unresolved, keep E01 open and explicitly block E06/E07. Schema fixtures alone do not close the issue.

Out of scope: storage, command execution, MCP registration, UI, auto-approval, or a custom credential system.

Required verification and handoff

  • Run the named RED/GREEN tests, npm run build, npm test, and git diff --check; record actual results, not historical counts.
  • Inspect current source and dependency PRs first. All new paths are proposed until their owning issue lands.
  • Get independent review on the exact candidate; stop on missing authority or unresolved security design.
  • Attach commit/PR, changed paths, observed proof, remaining limits, compatibility notes, and the next eligible issue.
  • Keep shared barrel/registration/invariant edits small and coordinate them; do not absorb unrelated work.
  • This issue does not authorize implementation of the later reuse/team/release backlog.

Activity

  1. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Candidate: PR #414, reviewed commit dcf964f9733deb79844872a52efe81d5d3071dbd (branch feat/e01-engineering-contract, from ee091ac). Not merged; no tag, release, or version bump.

    Changed paths: core/engineering/{types,ids,digest,validation,index}.ts; core/index.ts (+1 export); docs/engineering/record-contract.md (rewritten as the normative contract), docs/engineering/README.md, docs/engineering/implementation-plan.md (E01 status line); tests/engineering-contract.test.mjs; tests/fixtures/engineering/v1/ (generator, 22 valid, 97 invalid). Nothing under .codecarto/, mcp-server/, or extensions/ changed.

    Verification on dcf964f (Linux, Node v22.22.3):

    • RED: with no core/engineering/index.ts, the targeted test failed ERR_MODULE_NOT_FOUND (0/1, exit 1). Three mutation checks (disable unknown-field, trust every channel, skip digest recompute) each turned the suite red (2/2/1 failures) and were reverted.
    • GREEN: node --experimental-strip-types --disable-warning=ExperimentalWarning --test tests/engineering-contract.test.mjs → 18 pass, 0 fail. npm run build → exit 0. npm test → 966 pass, 0 fail (baseline 948 at ee091ac). git diff --check clean.

    Independent review: two fresh-context, findings-only rounds. Round 1 on aff4d98: 1 blocking (the operation API had no action creating the candidate snapshot that record-proof/record-review bind to), plus unknown-field bypass via prototype names (in → Object.hasOwn), no authority rule for caller-spelled collector, ambiguous consumed-nonce semantics, unvalidated receipt inputs, trusted channel accepting authenticated: none, and shapes downstream would have invented. 143fb76 closes all eleven (adds capture-candidate, adapter-set attested_by, checkCandidateFreshness, ChangeResults/StatusResult/CheckResult, transition tables, 24 h TTL cap, 15 fixtures). Round 2 on 143fb76 re-probed each item against live code: no blocking or should-fix findings; two doc nits fixed in dcf964f.

    What the contract settles: IDs <prefix>_<24 hex>; repo-relative path grammar; canonical JSON + sha256 with the exact digest inputs (snapshot {coverage, manifest, repository}, attempt inputs {brief_digest, plan_digest, references}, presentation); schema_version: 1 only, unknown fields refused; every enum spelling; required records for acceptance; the nine codecarto_change actions with argument, result, and error shapes; the receipt path (core-issued acr_ request with single-use nonce → host-controlled channel → adapter-minted approval), its rejection table, and what each channel authenticates (a host session, never a person).

    Unresolved / limitations (honestly stated in the contract):

    1. Maintainer decision needed (contract § Decision record): is MCP elicitation — which trusts the connected client to have shown the form — an acceptable pilot channel? The SDK server side (elicitInput, gated on the client's elicitation.form capability) is verified; no client was verified. If no, E06/E07 stay blocked on MCP; Pi's host-native channel is unaffected.
    2. Same-user filesystem: an adapter-minted approval and a hand-written request+approval pair are byte-indistinguishable at rest. The Pi guard (unchanged, per EV-D03) allows agent writes under .codecarto/, which includes .codecarto/engineering/; E08's host policy must deny that or treat at-rest records as cooperative.
    3. On MCP every proof is caller-attested (the server never runs commands); the presentation always discloses this. Only the candidate snapshot is required to be adapter-captured.

    Baseline follow-ups: #412 reproduces at this baseline with the injected GIT_CONFIG_COUNT env (recorded on #412; not touched here). This environment has no GIT_CONFIG_* set, so the counts above are unaffected. #395's Windows-CI policy unchanged.

    Next eligible: E09 (#407) is independent and open. E02 (#400) and E03 (#401) become eligible once #414 merges; both consume core/engineering/index.ts as merged and coordinate their single core/index.ts edit. E06/E07 additionally wait on item 1 above. Suggest leaving this issue open until the maintainer records that decision — schema fixtures alone were not meant to close it.

  2. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Merged: #414 squashed onto main as 65c9fa3316ab29d2c0149404d0c8a0d901d97d9d (on top of #413). Post-merge CI run 35309859616 completed successfully for that exact commit — Node 22, Node 24, and the Windows job all passed (Windows: 966 tests, 962 pass, 0 fail, 4 pre-existing POSIX-only skips).

    E02 (#400) and E03 (#401) are now eligible and consume core/engineering/index.ts as merged. E06/E07 still wait on the MCP-elicitation channel decision recorded in docs/engineering/record-contract.md § Decision record; that decision is what closes this issue.

  3. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Sequencing correction (maintainer): merging #414 does not satisfy the E01 gate. E02 (#400) and E03 (#401) remain blocked until this issue is fully resolved, merged, and closed; my earlier "now eligible" line above is withdrawn. E09 (#407) is on explicit maintainer hold and is not authorized to start regardless of its dependency status.

    The contract as merged is a candidate contract; E01 acceptance pending — the "frozen" wording in the docs and code comments is premature and will be corrected in a follow-up PR that also (a) separates caller-reported proof claims from observed evidence so a collector label alone cannot discharge an obligation, (b) keeps MCP elicitation a conditional proposal tied to a verified host/client integration check, and (c) separates approval-channel trust from at-rest record trust. That PR will not be merged and no dependent work will advance until the maintainer has reviewed its handoff.

  4. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Corrective candidate: PR #415, reviewed commit 92b034a0ec4b5915ea6f3c6ea61118d380bf933f (branch fix/e01-contract-review, from main = 65c9fa3). Not merged; awaiting maintainer review of this handoff. E02/E03 remain blocked until E01 is resolved, merged, and closed; E09 remains on explicit maintainer hold.

    Changed paths: core/engineering/types.ts, core/engineering/validation.ts, docs/engineering/record-contract.md, docs/engineering/README.md, docs/engineering/implementation-plan.md, tests/engineering-contract.test.mjs, tests/fixtures/engineering/v1/ (generator; +2 valid, +14 negative → 132 fixtures). Nothing under .codecarto/, mcp-server/, extensions/, core/synthesis.ts, core/status.ts, or core/index.ts.

    What it does (per the four demands):

    1. Status — "frozen" replaced with "candidate contract; E01 acceptance pending" in the contract, README, plan, and code comments; README now states E02/E03 wait on closure and E09 is on hold.
    2. Claims vs observations — claim (collector/result/…) / attestation (provenance.attested_by ∈ adapter | host-tool-result | caller, adapter-set) / derived authority (proofAuthority) kept apart; a caller-reported record is claimed whatever label it carries (tested for every collector value); proofDischarges refuses claims under the default verified policy; the host-tool-result path is specified (host-side entry unreachable by the model's tools, config outside agent-writable roots, host payload supplies command/cwd/exit/tool_call_id; pairing rules enforced) without CodeCartographer executing anything; cooperative is a separate operator-set policy, never request-selectable, labelled everywhere, not authorized for the pilot.
    3. Conditional channel — VERIFIED_ACCEPTANCE_INTEGRATIONS (empty) is the sole source of support; acceptanceChannelSupported refuses every pair not in it regardless of advertised capability; the integration check's required observations are documented; unverified → needs-human-acceptance; claim is session-attested.
    4. Channel vs at-rest trust — approvals carry assurance + storage.boundary at mint, receipts carry client; classifyAcceptance is verified only with a bound receipt, registry membership now, verified policy, and a reader-side host-enforced boundary whose enforced_since precedes decided_at; a forged record cannot be laundered by enabling a boundary later; a record cannot label itself verified over boundary: none; same-user caveat kept, not used to satisfy the stronger requirement; no credential system; Pi guards untouched.

    Verification on 92b034a (Linux, Node v22.22.3): targeted 21 pass / 0 fail; mutation (proofAuthority trusting the label) → 2 failures, reverted; npm run build exit 0; npm test 969 pass / 0 fail; git diff --check clean; staged content scanned for credentials/home paths — none.

    Independent review: Round A on b787ca1 (findings-only): demands 1 and 3 met, 2 and 4 partial — eleven concrete findings (model-reachable host-tool-result, boundary-toggle laundering, self-reported verified_integration, unenforced pairing rules, table drift, wording). All folded into 92b034a except the maintainer questions below. Round B on 92b034a: all nine tightenings verified closed by probe; no findings; confirmed nothing classifies verified against the contract's own empty registry.

    Decisions that remain yours (contract § Decision record) — none are implied by this PR:

    • D1 MCP elicitation on a specific verified host/client pair — acceptable pilot channel? Which pair is integration-checked first, by whom?
    • D2 Pi host-native on the same terms?
    • D3 Storage-boundary mechanism for the pilot host; where the boundary declaration and enforced_since live so agent tools cannot write them; must the boundary predate the namespace's first write?
    • D4 Observed-evidence path: must E05's ingestion entry be demonstrably unreachable by the model's tools, and its hook configuration outside agent-writable roots, to count as host-tool-result?
    • D5 Is cooperative permitted at all for the pilot; under it, do honest agent-claimed records discharge equally with relabelled ones?

    Until D1–D4 have answers, no acceptance can be verified on any host, and E01 stays open by design. I will not merge #415 or advance dependent work.

  5. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    CI on #415 at 92b034a: test (22), test (24), test-windows, CodeQL, and both Analyze jobs all pass. PR remains unmerged pending your review.

  6. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Counterexample addressed. PR #415 now at 5a8ade3fafa097958da5168a4eff73f56ffe4ed7 (commits 9f0ba64 fix, 5a8ade3 consistency). Still not merged; #399 stays open; E02/E03 blocked; E09 on hold.

    Reproduced first: against 92b034a, a request/approval pair forged under boundary: none with issued_at/responded_at/decided_at chosen to post-date a later protection epoch, plus a supported-integration fixture, returned {"class":"verified"}. The epoch comparison read decided_at from the writable record.

    Fix, within the constraints: no additional timestamp or flag inside the record set is trusted. CurrentStorage (the reader's out-of-namespace context) gains protection ∈ continuous-since-initialization | enabled-after-initialization | interrupted | imported-history. Only the first makes any record eligible for verified; the others and an omitted/unknown value classify cooperative. Nothing in any record or request can carry it (unknown-field on all nine actions; no record shape has it). The decided_at/enforced_since comparison is demoted to a consistency check that can only lower trust.

    Policy stated (contract § Protection before authoritative initialization): the boundary must be enforced before the namespace's first write and never lapse; existing unprotected records never become verified because protection is enabled later; an interruption is permanent for that namespace; imported/restored/hand-edited history is untrusted; the way to an authoritative namespace is a fresh one initialized under protection. The remaining mechanism — where the initialization marker, enforced_since, and lapse history live so agent tools cannot write them; how a lapse is detected; how a fresh namespace is initialized — is recorded under D3 as a host mechanism, not solved by the epoch check.

    D4 as requirements: HostCapabilities.tool_result_path ∈ protected | unprotected | none; attestationForHostObservation yields host-tool-result only for protected (entry unreachable by the model's tools and configuration outside agent-writable roots), otherwise caller. The same protection-history rule is stated to govern proof files, as an E06 requirement.

    Registry still empty; cooperative still unauthorized for the pilot; no E02/E06/E07 code.

    Verification on 5a8ade3 (Linux, Node v22.22.3): focused regression — the exact counterexample under each protection history and under omitted/invalid values — 23 targeted pass / 0 fail (RED against the previous logic: 2 failures with the protection check disabled); npm run build exit 0; npm test 971 pass / 0 fail; git diff --check and hygiene scan clean.

    Independent review of this exact counterexample (on 9f0ba64): reproduced it against the old validator across every protection value (all verified before; all but continuous-since-initialization cooperative after, including undefined/null/"bogus"); confirmed the fix trusts nothing inside the record set, that the epoch comparison is now trust-lowering only, that D3/D4 are recorded as required, and that no E02/E06/E07 logic exists. Verdict: counterexample closed within the constraints. Five consistency items (the ACCEPTANCE_REQUIRED_RECORDS text and the doc's acceptance table still described the pre-fix rule; the proof-file corollary was prose-only; two wording/typing nits) are folded into 5a8ade3.

    What the code proves vs what the host must enforce (contract § of that name):

    • Code proves: no request can carry a decision, attestation, policy, capability, boundary, protection history, or tool-result path; a caller-reported proof is claimed under every label; the registry is empty and refuses every pair; classifyAcceptance is verified only with a bound receipt, current registry membership, the verified policy, and continuous-since-initialization — the forged pre-dated pair, enabled-later, interrupted, imported, and omitted histories all classify cooperative; a record cannot self-label verified over none/false; presentations disclose claimed proofs, weak candidates, the cooperative policy, and an unprotected boundary.
    • Host must enforce (outside the validators' reach): supplying those values from configuration the model cannot write; actually denying agent writes to the namespace; initializing it only after protection and recording the marker/lapse history where agent tools cannot write; reporting protection truthfully; a protected tool-result path; running the integration check; showing the presentation unaltered; and (E06) applying the protection history to proof files.

    Remaining decisions (unchanged, D1–D5), with D3 now carrying the protection-history mechanism and D4 carrying the demonstration of unreachability. Awaiting your review; I will not merge, close, or advance dependent work.

  7. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    CI on #415 at 5a8ade3: test (22), test (24), test-windows, CodeQL, both Analyze jobs pass. Unmerged, awaiting review.

  8. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Merged: #415 squashed onto main as 54a76dc852dd85b65cf560d52e80fa61853d2038 after confirming exact-head checks green at 5a8ade3. Post-merge CI run 35315528306 completed successfully for that commit: test (22), test (24), test-windows all success.

    Scope of the approval (maintainer): the corrective candidate code only. This is not closure of E01 and not a claim that any host integration is verified. #399 stays open; E02/E03 remain blocked; E09 remains on hold; VERIFIED_ACCEPTANCE_INTEGRATIONS remains empty; cooperative remains unauthorized for the pilot.

    Next (maintainer direction): no further expansion of the abstract contract. A bounded feasibility spike against ONE concrete host/client configuration (MCP elicitation as the candidate channel, session-attested), using disposable fixtures, changing no global host configuration, with experimental code kept out of production and no automatic registry entry or issue closure. Results will be reported here.

  9. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Feasibility spike — one host, one client. PR #416 at b36828fd5dedd6089f47ee0e5475852b215ee8f1 (report docs/engineering/spike-claude-code-2026-09-18.md, fixtures spikes/claude-code-2.1.263/). Not merged. Registers nothing; registry empty; cooperative unauthorized; no E02/E05/E06/E07 code; #399 open; E02/E03 blocked; E09 on hold.

    Host inspected: Claude Code 2.1.263, Linux (Fedora, kernel 7.2.4), bubblewrap 0.12.0 + socat present, unprivileged userns OK. MCP client info { name: "claude-code", version: "2.1.263" }. All runs headless in a disposable directory via --settings <file> / --mcp-config … --strict-mcp-config; no global configuration touched; no external provider spend (seven short Sonnet runs on the existing subscription).

    Mechanisms tested and actual results:

    1. Elicitation — client declares elicitation.form even headless; headless elicitInput returned { action: "cancel" } (~3 s), nothing minted. Interactive dialog exists (bundle strings). An Elicitation hook can answer for the user (bundle hook-output schema) — not exercised; hook configuration is therefore part of the boundary. Live human interaction was not performed; the exact steps (accept, reject, cancel/Esc, stale; mismatch is protocol-level) are in the report.
    2. Namespace — permissions.deny on Write/Edit alone was bypassed by python3 -c "open(…).write()" (file on disk). With sandbox.enabled + filesystem.denyWrite, redirect/python/cp/mkdir all failed EROFS while a write one directory up succeeded — OS-enforced. Config files (.claude settings, .claude/hooks, .mcp.json, ~/.claude) are sandbox-protected with no exemption and permission-layer protected for Write/Edit — except in bypassPermissions. No host mechanism attests protection continuity: every acceptance on this host classifies cooperative under the contract until D3 settles a mechanism.
    3. Tool results — PostToolUse and PostToolUseFailure hooks run outside the sandbox and delivered tool_use_id, tool_input.command, tool_response.{stdout,stderr} / error: "Exit code N\n…" into the denyWrite inbox; the model's Bash could neither write the inbox nor make the hook script write (EROFS). Limitations: failures fire PostToolUseFailure (not PostToolUse); exit code arrives as text; success carries no exit-code field.
    4. Honest unsupported — headless → cancel; unregistered pair → needs-human-acceptance; missing sandbox deps → hard failure with failIfUnavailable: true (docs, not exercised); unprotected hook path → caller; unknown history → cooperative.

    Smallest feasible pilot configuration (proposal): user-level or managed settings only, never bypassPermissions: sandbox on (allowUnsandboxedCommands: false, failIfUnavailable: true, denyWrite on the namespace), Write/Edit deny rules, PostToolUse + PostToolUseFailure hooks (matcher Bash) into a host-side ingestion entry writing to the protected inbox, no Elicitation hooks, interactive sessions for acceptance. Yields per session storage_boundary: host-enforced, tool_result_path: protected, human_acceptance: mcp-elicitation (unverified); does not yield protection: continuous-since-initialization.

    Decisions this leaves with you:

    • D1 — run the live check (steps in the report) at an interactive session; I did not simulate it.
    • D3 — accept or reject the candidate continuity mechanism (operator enables the configuration before initialization; adapter writes a hook-delivered init marker into the protected namespace; a SessionStart hook in the same protected source re-checks each session; any gap = permanent interrupted). Without it, verified is unreachable on this host.
    • D4 — accept "user/managed settings + no bypassPermissions" as the definition of protected configuration.
    • D5 — untouched.

    Not covered: macOS/WSL2 (docs only), Windows native, other MCP clients, the desktop app's dialog. Awaiting your review of #416; nothing advances.

  10. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Spike revision — E5 recorded. PR #416 now at 6b34c17f2e570f1a579be9d3279abf3eb8e36b0f (not merged). The first pilot configuration left the ingestion hook script writable from the sandbox (maintainer finding); it is withdrawn. Corrected configuration puts the hook directory and the settings file in denyWrite explicitly with matching deny rules, and the hook is hardened (absolute interpreter, fixed PATH, absolute command paths, nothing sourced).

    E5 results (observed): append/replace/create/chmod/symlink on the hook → Read-only file system; rename its directory → Device or resource busy; overwrite the settings file → read-only; /usr/bin, /usr/bin/sh, and every PATH directory → refused; script and settings hashes unchanged; hook fired for all 13 calls. One finding: the hook directory's parent was writable (it sits under Claude Code's per-user temp root, which the sandbox allows) — so a hook is protected only where an explicit denyWrite or a host-protected location covers it, never by being "outside the working directory".

    Claims now: tool_result_path: protected only for the E5 configuration; storage_boundary: host-enforced per session; protection: continuous-since-initialization still not provided. D3 candidate reworked so the initialization marker is written only by a script that is itself protected; whether a SessionStart hook can see enough of the effective settings to re-check per session is an E02 investigation. D1 live check still owed. Registry empty; cooperative unauthorized; E02/E03 blocked; E09 on hold.

  11. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Revision: E6 (every path the unsandboxed hook writes)

    Second finding of the same class: the E5 hook still wrote hook-err.log and hook-status.log into the parent directory E5 item 7 proved writable; the hook runs outside the sandbox, so a planted symlink turned its own redirect into a write primitive. The E5 hook is withdrawn.

    E6a — the primitive, against the E5 hook (separate disposable root):

    Planted symlink Observed
    hook-err.log → hooks/observe.sh on the next Bash call the hook truncated its own script to 0 bytes — ingestion denial of service
    hook-status.log → <namespace>/inbox/forged.json (alone) inbox/forged.json created inside the evidence namespace with three hook-wrote-0 lines — attacker-chosen path, written by the trusted process

    Corrected hook: every write (payload, stderr, status) inside the namespace; one fresh uniquely named file per event; set -C so each > is O_CREAT|O_EXCL and refuses any symlink, dangling or not (proved locally under this host's /usr/bin/sh); no >> anywhere; absolute interpreter, fixed PATH, absolute commands, nothing sourced.

    E6b — against the corrected hook (observed): symlinks at inbox/planted.json, hook-logs, hook-logs/planted.err → Read-only file system; symlinks at the old log paths planted (parent writable) but never opened — targets untouched; a symlink from the writable cwd into the namespace is refused on the resolved path (confirmed directly with bwrap --ro-bind); script hash intact; 10 inbox files + 20 log files, all hook-written and uniquely named; zero symlinks inside the namespace.

    Requirement, generalized (report § requirement 3, § D4, pilot configuration, E05 note): tool_result_path: protected requires that every path the unsandboxed hook reads, executes, and writes is protected — the script, its directory, its interpreter, every PATH directory, the settings naming it, and every file it writes: payload, error log, status log, temp and lock files — written as fresh uniquely named files with O_CREAT|O_EXCL (or O_NOFOLLOW fixed paths), never through a symlink it did not create. The real E05 ingestion entry has the same exposure for its own error/status output and is bound by the same list.

    Head: 50b45b3. npm run build exit 0; npm test 971/971; npm pack --dry-run shows zero spikes//docs/ entries; git diff --check clean; no private paths. Registry empty; cooperative unauthorized; no E02/E05/E06/E07 code; #399 open; E02/E03 blocked; E09 on hold. Not merged.

  12. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Merged: #416 squashed onto main as ddb4f36f01bdf902a93d7c154fa033465a242cd0 after confirming exact-head checks green at 50b45b3. Post-merge CI run 35320767000 completed successfully for that commit: test (22), test (24), test-windows all success. The spike registers nothing; VERIFIED_ACCEPTANCE_INTEGRATIONS stays empty.

    Maintainer decisions recorded (to be written into the contract's decision record by a follow-up PR): D1 conditional yes — MCP elicitation on the named pair claude-code/2.1.263 + codecarto MCP server, registry empty until the maintainer runs the live check; operator attests no Elicitation/ElicitationResult hooks, adapter cannot verify this, goes in the receipt disclosure. D2 deferred. D3 boundary accepted (E5/E6 configuration, session-level); continuity NOT provided; SessionStart marker is an open E02 investigation. D4 accepted with the full E5/E6 requirement list; re-run E5/E6 wherever the real ingestion entry is placed. D5 no — cooperative stays unauthorized. Consequence: the pilot runs with observed proofs and acceptances that classify cooperative; E06 surfaces that classification rather than refusing. #399 stays open pending the D1 live check; E02/E03 blocked; E09 on hold.

  13. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    Decision record PR: #417 at 5ab5612bfdd45a5501c5b7a321f6529fa8762dfd (docs only, not merged) writes D1–D5 into record-contract.md § Decision record with the stated consequence (observed proofs, cooperative acceptances; E06 surfaces the classification) and the three forward notes (inbox-only record parsing, hook-write retention, per-host O_EXCL proof). Stopping here: #399 stays open for the D1 live check; E02/E03 blocked; E09 on hold; registry empty; no E02/E05/E06/E07 code.

  14. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    D1 live check recorded. Log verified on this machine (5 lines, sha256 cc4bb6651fae…; the 2.1.277 binary landed at 21:28:47Z, one minute before the first initialize). PR #417 now at 955e086298919fce9ca526f02dc05c5e936fb196 and is no longer docs-only: it adds the version-match check (client_version exact; live mismatch → needs-human-acceptance), elicitationDecision (decision from content.decision only; action never authorizes; missing/unknown → invalid), timed-out as its own outcome with acceptanceTtlWithin against the client's observed timeout, ten elicitation fixtures (the three live shapes verbatim), and a contract test for each. D1 is recorded as YES for claude-code/2.1.277 + the codecarto MCP server, conditional on those three items plus the operator attestation on Elicitation hooks; VERIFIED_ACCEPTANCE_INTEGRATIONS stays empty until the entry is added by amendment with the evidence. E5/E6b re-run on 2.1.277: identical results. D2–D5 unchanged. 972 tests green. Not merged; per your direction #399 can close once #417 lands, after which E02/E03 unblock and E09 stays on hold.

  15. TheAmericanMaker commented on Sep 18, 2026

    @TheAmericanMaker
    MemberAuthor

    E01 closed

    #417 merged as b868fd9; post-merge CI green on that exact commit (Node 22, Node 24, Windows, CodeQL ×2).

    The D1 live check was performed by the maintainer at an interactive Claude Code session, and its findings are in the contract. The client identified as 2.1.277, not the 2.1.263 the spike was titled for — the host auto-updated three minutes before the first elicitation. All four required observations were obtained, screen paired against the server log:

    observed
    presentation message shown verbatim with a required Decision field
    accept action: accept, content.decision: accept
    reject action: accept, content.decision: reject
    cancel action: decline, no content
    timeout MCP error -32001 after ~2.5 min, nothing minted

    Three findings came out of that run and are now enforced in code, not documented as advice: exact-version matching (a self-updating client silently staleing a registry entry), timed-out as an outcome distinct from declined, and the decision deriving only from content.decision — line 4 above is a real rejection that an adapter reading action would have minted as an approval.

    Reviewing those changes then surfaced a recurring defect class: a trust rule expressed as a helper that nothing calls. Four instances closed:

    • acceptanceTtlWithin was dead code; the shipped fixture paired a 3600 s window with the 150 s client timeout it must fit inside and still read verified. Now enforced in classifyAcceptance.
    • buildAcceptanceRequest composes an honest presentation, but nothing checked one. A request minted another way could show empty limitations over a caller-reported proof and read verified. Now re-derived and enforced.
    • The first disclosure fix then replaced "trust the adapter" with "trust the reader" — omitting proofs/reviews defaulted them to [] and reopened the same bypass. They are now required for a verified reading; omitting them degrades to cooperative with an explicit reason.
    • Duplicate registry tuples let array order pick the timeout, and client_request_timeout_ms was never type-checked ("999999999", Infinity, [999999999] all coerced past the comparison). Both closed.

    Each has a mutation check that turns the suite red when the enforcement is removed. 973/973 tests pass.

    Decisions recorded (D1–D5): D1 conditional yes for claude-code/2.1.277 + the codecarto MCP server, pending registration; D2 Pi host-native deferred; D3 boundary accepted, continuity not provided by this host; D4 accepted with the E5/E6 requirement list; D5 cooperative unauthorized.

    The honest consequence: with D3 unsolved and D5 no, the pilot runs with genuinely observed proofs and acceptances that classify cooperative. VERIFIED_ACCEPTANCE_INTEGRATIONS stays empty. That is the contract working as designed, not a gap — E06 must surface the classification rather than refuse to proceed.

    Known limitation, documented not enforced: the disclosure check compares lines by exact equality, so a presentation carrying every required line plus contradicting text passes. Reviewing presentation copy is an operator responsibility.

    E02 (#400) and E03 (#401) are now unblocked. E09 (#407) remains on maintainer hold.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions