Skip to content

fix: E01 contract review — claims vs observations, conditional channel, at-rest trust - #415

Merged
TheAmericanMaker merged 4 commits into
mainfrom
fix/e01-contract-review
Sep 18, 2026
Merged

TheAmericanMaker merged 4 commits into
mainfrom
fix/e01-contract-review

Conversation

@TheAmericanMaker

Copy link
Copy Markdown
Member

Corrective follow-up to #414 for E01 (#399), per the maintainer's review. Do not merge until the maintainer has reviewed the handoff on #399. Merging #414 did not close E01; E02/E03 remain blocked and E09 stays on hold.

What this changes

1. Status. "Frozen" → "candidate contract; E01 acceptance pending" in the contract, README, implementation plan, and code comments. The decision record now lists five questions (D1–D5) the maintainer must answer before #399 closes.

2. Claims vs observations. Three layers are kept apart on every proof: the claim (collector, result, exit_code, check — caller text on the tool path), the attestation (provenance.attested_by ∈ adapter | host-tool-result | caller, adapter-set, unknown-field on every input), and the derived authority (proofAuthority → observed only with an observed collector and an observing attestation). Relabelling a caller-reported record host-observed never elevates it — the test pins this for every collector value. proofDischarges refuses claimed proofs under the default verified policy. The qualifying host-tool-result path is specified without CodeCartographer executing anything: a host-side ingestion entry the model's tools cannot reach, configured where agent tools cannot write; the host payload supplies command/cwd/exit code/output digest/tool_call_id; pairing rules are enforced (host-tool-result ⇒ host-observed + tool_call_id; adapter never attests host-observed; snapshots never host-tool-result). Claimed records are retained and disclosed. cooperative is a separate, operator-set, request-unselectable policy, labelled on every result and not authorized for the pilot (D5).

3. MCP elicitation stays conditional. VERIFIED_ACCEPTANCE_INTEGRATIONS (empty) is the only source of support; acceptanceChannelSupported refuses any host/client pair not in it, whatever the client advertises or the adapter asserts. The integration check's four required observations (presentation, acceptance, rejection/cancellation, stale/mismatched response) are documented. Unverified paths stop at needs-human-acceptance. The claim is session-attested, not human identity. Nothing here approves the channel (D1/D2).

4. Channel trust ≠ at-rest trust. Approvals carry assurance and storage.boundary at mint; receipts carry client. classifyAcceptance is verified only with a bound receipt, the (host, client, channel) triple in the current registry, the verified policy, and a reader-side CurrentStorage { host-enforced, enforced_since } whose epoch precedes decided_at. A real UI decision in an agent-writable namespace is cooperative; a forged record spelled host-enforced/verified_integration: true stays cooperative under boundary none or a later epoch (so enabling a boundary later cannot launder it); a record may not label itself verified over storage.boundary: none. The same-user-filesystem caveat is kept and is not used to satisfy the stronger requirement. No credential/token/signature system; Pi guards untouched.

Verification (on 92b034a, Linux, Node v22.22.3)

Step Result
node --test tests/engineering-contract.test.mjs 21 pass, 0 fail
mutation: proofAuthority trusts the collector label 2 tests fail; reverted
npm run build exit 0
npm test 969 pass, 0 fail
git diff --check; hygiene scan clean

Fixtures: +2 valid (caller-reported proof, cooperative approval), +14 negative (132 total); tests +3.

Independent review

Round A (on b787ca1, opus, findings-only): met demands 1 and 3; 2 and 4 partial — eleven findings with concrete triggers (host-tool-result reachable by the model, boundary-toggle laundering, self-reported verified_integration, unenforced pairing rules, doc/code table drift, wording). All folded into 92b034a except two that are the maintainer's to answer and are now D3/D4/D5 sub-questions. Round B (on 92b034a, sonnet): all nine tightenings verified closed by probe; no findings; nothing classifies verified against the contract's own empty registry.

Open for the maintainer (contract § Decision record)

D1 MCP elicitation on a named verified host/client pair? D2 Pi host-native? D3 storage-boundary mechanism, where its declaration and enforced_since live, boundary-before-first-write? D4 observed-evidence path: must E05's entry be demonstrably unreachable by the model and its hook config outside agent-writable roots? D5 is cooperative permitted at all, and do honest agent-claimed records discharge equally there?

Refs #399, #398

🤖 Generated with Claude Code

TheAmericanMaker and others added 2 commits September 18, 2026 01:32
…l, at-rest trust

Corrects the candidate contract merged in #414 on the maintainer's
sequencing and trust findings. E01 (#399) is not closed by that merge;
E02/E03 stay blocked and E09 stays on hold.

- Status: "frozen" becomes "candidate contract; E01 acceptance pending"
  in the contract, README, implementation plan, and code comments; the
  decision record now lists the five questions (D1–D5) that keep #399
  open.
- Claims vs observations: attestation is three-way (adapter,
  host-tool-result, caller). proofAuthority derives observed/claimed
  from collector AND attestation, so relabelling a caller-reported
  record host-observed never elevates it; proofDischarges refuses
  claimed proofs under the default `verified` policy. The
  host-tool-result path (a host hook delivering the tool's actual exit
  code/output to a host-side ingestion entry, E05) is specified without
  CodeCartographer executing anything. Claimed records are retained and
  disclosed.
- Assurance policy: `verified` is the only meaning of verified;
  `cooperative` is a separate operator-set policy, never selectable by
  a request, labelled on every result, and not authorized for the pilot.
- Conditional channel: VERIFIED_ACCEPTANCE_INTEGRATIONS (empty) is the
  only source of support; acceptanceChannelSupported refuses any
  host/client pair not in it, whatever the client advertises; the
  integration check's four required observations are documented;
  receipts carry verified_integration.
- Channel vs at-rest trust: approvals carry assurance and the storage
  boundary at mint; classifyAcceptance is verified only with a bound
  receipt, verified integration, verified policy, and a host-enforced
  boundary at mint and now — a real UI decision in an agent-writable
  namespace is cooperative. A record may not label itself verified over
  an unprotected boundary. Pi guards unchanged; no credential system.

Fixtures: +2 valid (caller-reported proof, cooperative approval),
+7 negative; tests +3 (21 total); full suite 969 pass.

Refs #399

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ndidate

Independent review of b787ca1 found the tightening below; all folded in
with fixtures and tests. Two of its questions belong to the maintainer
and are recorded as D3/D4/D5 sub-questions in the decision record.

- host-tool-result is pinned: only a host-side ingestion entry the
  model's tools cannot reach, configured where agent tools cannot write,
  qualifies; the record requires tool_call_id from the host payload and
  a host-observed collector; the adapter never attests a host-observed
  check; a snapshot is never a tool result.
- The receipt names the client; classifyAcceptance re-derives the
  integration from the current registry (de-verification downgrades old
  approvals) and takes CurrentStorage with enforced_since — an approval
  decided before the boundary was continuously enforced stays
  cooperative however its storage field is spelled, so enabling a
  boundary later cannot launder a forged record. Malformed storage
  context fails closed.
- Presentation discloses a candidate that could not bind a verified
  acceptance; reviewer-separation wording names the review's author, not
  the host; provenance.source is documented as part of the claim;
  channel comments carry the "until registered" qualifier; doc field
  tables match the code again.

Refs #399

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TheAmericanMaker and others added 2 commits September 18, 2026 02:04
…ments

The maintainer's counterexample: while the namespace is unprotected, an
agent pre-writes a request/approval pair whose issued/decided times
post-date the epoch at which protection will later be enabled. Against
92b034a classifyAcceptance returned verified, because the epoch check
compared the trusted enforced_since with decided_at — a timestamp inside
the forged record. Reproduced, then fixed without trusting any other
timestamp or flag in the writable record set:

- CurrentStorage gains `protection`, the host's out-of-namespace account
  of the whole history: continuous-since-initialization |
  enabled-after-initialization | interrupted | imported-history. Only the
  first makes any record eligible for verified; the others, and an
  omitted value, classify cooperative. The decided_at/enforced_since
  comparison is demoted to a consistency check that can only lower trust.
- The contract states the initial policy — protection before the
  namespace's first write, never lapsed; existing unprotected records
  never become verified; an interruption is permanent; imported history
  is untrusted — and records the remaining mechanism (where the
  initialization marker and lapse history live, how a lapse is detected,
  how a fresh namespace is initialized) as D3, not solved by the epoch.
- D4's unreachable ingestion entry and protected configuration are
  requirements: HostCapabilities.tool_result_path (protected |
  unprotected | none) and attestationForHostObservation, which yields
  host-tool-result only for protected. The same protection-history rule
  is stated to govern proof files.
- A "what the code proves / what the host must enforce" table.

Tests: the exact counterexample under each protection history (RED
against the previous logic: 2 failures with the check disabled), and the
tool-result-path rule. 23 targeted, 971 full suite.

Refs #399

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion-history rule (review consistency items)

ACCEPTANCE_REQUIRED_RECORDS and the doc's acceptance table stated the pre-fix
"host-enforced now" rule; both now name continuous-since-initialization. The
proof-file corollary is recorded as an E06 requirement in the proves/enforces
table; the declaration-provenance sentence names protection and
tool_result_path; an undeclared protection history gets an honest reason;
TOOL_RESULT_PATHS is pinned; attestationForHostObservation accepts an
undeclared path as the doc says.

Refs #399

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@TheAmericanMaker
TheAmericanMaker merged commit 54a76dc into main Sep 18, 2026
6 checks passed
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