Skip to content

Make fresh ERC-8004 policy executable from MCP alone - #97

Open
thetangstr wants to merge 36 commits into
mainfrom
codex/apple-demo-deploy
Open

Make fresh ERC-8004 policy executable from MCP alone#97
thetangstr wants to merge 36 commits into
mainfrom
codex/apple-demo-deploy

Conversation

@thetangstr

Copy link
Copy Markdown
Owner

Summary

  • encode exact conditional ERC-8004 chain and registry constants in the public invite schema
  • keep all seven tools and v1 compatibility unchanged

Verification

  • MCP build
  • v2 public-server, coordinator, and protocol tests
  • v1 compatibility test
  • live production tools/list schema and health probe

Constraint: Fresh Codex and Claude Code clients must not need blockchain constants in the stakeholder prompt.
Rejected: Adding Sepolia plumbing to the business prompt | it makes the public MCP contract non-portable and easy to mis-specify.
Confidence: high
Scope-risk: narrow
Directive: Keep the public identity-policy schema conditionally exact whenever supported chains or registries change.
Tested: MCP build plus v2 public-server, coordinator, protocol, and v1 compatibility tests.
Not-tested: Live cross-client canaries run after deployment.
Constraint: Claude Code must distinguish stakeholder-authorized local signing from prompt injection without weakening hash or policy checks.

Rejected: Hiding bearer access from the local stakeholder | conflicts with transparent client safety boundaries

Confidence: high

Scope-risk: narrow

Directive: Keep role access out of counterpart channels and logs, while allowing the local stakeholder to audit its use.

Tested: npm run build; targeted public initialization test

Not-tested: live cross-client canary pending
Constraint: Fresh Claude Code must receive informed consent from the local stakeholder prompt, not infer authority from MCP-delivered content.

Rejected: Treating server instructions as authorization | correctly triggers prompt-injection defenses

Confidence: high

Scope-risk: narrow

Directive: Keep initial stakeholder prompts explicit about expected handshake, pinned helper execution, Sepolia registration, and signing scope.

Tested: npm run build; targeted public initialization test

Not-tested: live Sonnet canary pending
Return a narrow pinned-helper action at the exact funded registration boundary so stateless clients do not poll until expiry.

Constraint: Keep the public surface at seven tools and preserve generic v1 behavior.

Rejected: Add a registration MCP tool | It would move local signing authority into the server boundary.

Confidence: high

Scope-risk: narrow

Directive: Keep registration local and express future local steps as explicit machine-actionable coordinator output.

Tested: npm test in packages/mcp-server (286/286).

Not-tested: Live cross-client canary pending production deployment.
Accept the canonical decimal session-opened block before converting provider requests to JSON-RPC hex quantities.

Constraint: V2 discovery carries decimal block strings while Ethereum JSON-RPC responses use hex quantities.

Rejected: Scan from registry creation on every fresh run | It adds unnecessary provider load and weakens the fresh-identity boundary.

Confidence: high

Scope-risk: narrow

Directive: Keep external protocol encodings explicit at RPC boundaries.

Tested: npm test in packages/mcp-server (287/287), plus live reproduction against Sepolia.

Not-tested: End-to-end fresh-agent canary pending production deployment.
Give fresh clients one deterministic state-directory bootstrap so the helper can preserve its fail-closed file-permission boundary.

Constraint: The workflow must remain plugin-free and keep private keys local.

Rejected: Relax private-directory validation | It would weaken signer isolation for the sake of the demo.

Confidence: high

Scope-risk: narrow

Directive: Keep local signer prerequisites explicit in MCP instructions and client allowlists.

Tested: Public v2 server tests 3/3; prior full MCP suite 287/287.

Not-tested: Fresh production canary pending deployment.
Accept checksummed helper output and lower-case it before every identity, funding, and signature binding.

Constraint: The helper emits a standard checksummed address while protocol artifacts require one canonical form.

Rejected: Require fresh agents to guess a lowercase retry | Public errors are intentionally opaque and should not force model heuristics.

Confidence: high

Scope-risk: narrow

Directive: Normalize equivalent public encodings once at the coordinator boundary.

Tested: npm test in packages/mcp-server (287/287).

Not-tested: Fresh production canary pending deployment.
Constraint: Responder invitations are one-time bearer capabilities and fresh agents must retain the first successful acceptance result.

Rejected: Making invitation acceptance idempotent | Replay rejection is a deliberate security property.

Confidence: high

Scope-risk: narrow

Directive: Keep the one-time invitation invariant and teach clients to treat the first success as authoritative.

Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs

Not-tested: Live production canary pending deployment.
Constraint: Waiting and party-ready states are protocol progress, not terminal success.

Rejected: Retrying invitations or treating registration as completion | Invitations are one-time and certification requires both parties plus the checker.

Confidence: high

Scope-risk: narrow

Directive: All nonterminal next responses must carry an explicit continuation signal.

Tested: MCP build; v2 coordinator and public-server tests; fresh-client prompt contract.

Not-tested: Live production canary pending deployment.
Constraint: Fresh agents must not infer the helper policy schema from prose.

Rejected: Adding more schema prose to stakeholder prompts | The server can return the exact role-specific policy object it already validates.

Confidence: high

Scope-risk: narrow

Directive: Treat returned localPolicy bytes as immutable input to the helper policy operation.

Tested: MCP build; v2 coordinator and public-server tests; fresh-client prompt contract.

Not-tested: Live production canary pending deployment.
Constraint: Fresh agents must retry temporary RPC or relay failures without retrying invalid role state or consumed invitations.

Rejected: Treating every internal exception as terminal | It made healthy handshakes fail on one transient read.

Confidence: high

Scope-risk: narrow

Directive: Preserve generic errors while carrying an explicit retryable boolean and delay.

Tested: MCP build and four public-server tests; fresh-client prompt contract.

Not-tested: Live production canary pending deployment.
Constraint: Fresh independent agents can observe an anchor before every ledger and chain projection is durably visible.\nRejected: Treat every coordinator error as retryable | protocol-integrity mismatches must remain terminal.\nConfidence: high\nScope-risk: narrow\nDirective: Preserve the distinction between absent propagation state and explicit binding mismatches.\nTested: npm test in packages/mcp-server (289/289)\nNot-tested: Fresh production canary after deployment
Constraint: Fresh agents must authenticate each role-scoped MCP call while never sharing bearer access with the counterparty or logs.\nRejected: Remove role-scoped access | distinct principals and role isolation require it.\nConfidence: high\nScope-risk: narrow\nDirective: Describe same-server access arguments as required credential use, not stakeholder disclosure.\nTested: agent-handshake-v2-public-server.test.mjs (4/4)\nNot-tested: Fresh production canary after deployment
Constraint: The invite response contains one copyable invitation and one private Initiator capability with different allowed tools.\nRejected: Infer the intended field from token shape | both values deliberately share the same signed capability encoding.\nConfidence: high\nScope-risk: narrow\nDirective: Name initiatorAccess, responderInvitation, and responderAccess explicitly in every autonomous-client instruction.\nTested: agent-handshake-v2-public-server.test.mjs (4/4)\nNot-tested: Fresh production canary after deployment
Constraint: Clockchain represents a submitted but not-yet-anchored ledger record with blockHeight null.\nRejected: Accept null as an integrity value | only a confirmed decimal height may enter receipt verification.\nConfidence: high\nScope-risk: narrow\nDirective: Retry null projection fields, but keep non-null binding mismatches terminal.\nTested: npm test in packages/mcp-server (289/289)\nNot-tested: Fresh production canary after deployment
Advance the dedicated handshake endpoint, join schema, verified bootstrap, and deployment validator to helper 2.1.1 so fresh clients can sign the final evidence shape that production actually emits.

Constraint: MCP, SSM deployment metadata, and client bootstrap must agree on one exact helper release.

Rejected: Continue accepting v2.1.0 | that helper deterministically rejects valid evidence and cannot complete a certificate.

Confidence: high

Scope-risk: moderate

Directive: Deploy only with manifest digest 681f61d4cde2537ec6953b134e8385e6a716c8d889db0f46fd566c10407c9402 and source 8f74f6d953631cbac057426e3540ba73bf607f3b.

Tested: MCP build plus 289 tests; 29 infrastructure tests; git diff --check.

Not-tested: Live endpoint awaits SSM pin update and EC2 restart.
Constraint: systemd executes an out-of-checkout wrapper under /opt/clockchain-mcp.\nRejected: restarting systemd directly after checkout updates | leaves the prior validator installed.\nConfidence: high\nScope-risk: narrow\nDirective: run the deploy-asset installer from the exact checkout before every restart.\nTested: node --test infra/test/deploy-assets.test.mjs; git diff --check\nNot-tested: no additional production restart was needed for this documentation guard.
Constraint: public clients must keep receiving the same generic fail-closed errors.\nRejected: returning internal failure details through MCP | creates an unnecessary protocol oracle.\nConfidence: high\nScope-risk: narrow\nDirective: structured diagnostics may include only the tool name and sanitized error class, never inputs or messages.\nTested: full npm test; focused public-server test; git diff --check\nNot-tested: the production log classification requires one new failed or successful canary after deploy.
Constraint: Claude Code dontAsk requires the emitted shell command to match an allow rule exactly, and zsh rejects unquoted =https arguments.
Rejected: Broaden Bash access | unnecessary and weakens the fresh-agent containment contract
Confidence: high
Scope-risk: narrow
Directive: Keep MCP download instructions byte-aligned with the Claude allowlist.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs; isolated Claude Code sonnet quoted-download probe
Not-tested: Full production cross-client handshake pending deployment
Constraint: Claude Code dontAsk evaluates each emitted Bash shape against the narrow allowlist, and Sonnet followed an MCP semicolon hint by combining downloads.
Rejected: Permit compound Bash | unnecessary and expands the local-authority surface
Confidence: high
Scope-risk: narrow
Directive: Describe every allowlisted Bash action as a separate tool call without shell wrappers or separators.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs; live Sonnet trace isolated the denied compound shape
Not-tested: Full production cross-client handshake pending deployment
Constraint: Sonnet optimized the download and state-directory steps into one four-operator Bash call, which dontAsk correctly denied.
Rejected: Allow compound shell commands | obscures the local-authority boundary and admits unintended command composition
Confidence: high
Scope-risk: narrow
Directive: Each Bash action in MCP instructions must remain ordered, standalone, and byte-aligned with one allow rule.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs; safe live command-shape trace identified curl plus mkdir in the denied compound
Not-tested: Full production cross-client handshake pending deployment
Constraint: Fresh clients must validate exact returned terms without mistaking the canonical terms digest for a raw-text hash.
Rejected: Letting agents infer the digest scheme | it caused a safe but unnecessary live refusal.
Confidence: high
Scope-risk: narrow
Directive: Keep statementDigest defined as SHA-256 over Clockchain canonical full terms.
Tested: MCP build and focused public-server tests, 4/4.
Not-tested: Live cross-client canary follows after deployment.
Constraint: Fresh clients must complete policy, signing, and certificate verification without repository knowledge or guessed JSON shapes.
Rejected: Expanding the stakeholder prompt with CLI mechanics | the MCP should carry executable local actions.
Confidence: high
Scope-risk: moderate
Directive: Every helper payload must remain exact, role-scoped, and free of bearer credentials or private keys.
Tested: MCP build plus focused coordinator and public-server suites, 7/7.
Not-tested: Live Terra-to-Sonnet canary follows after deployment.
Constraint: Claude native sandbox exposes a shared runtime temp root that must never hold reusable handshake state.
Rejected: Reusing or cleaning shared temp paths | would weaken fresh-agent provenance and risk deleting unrelated files.
Confidence: high
Scope-risk: narrow
Directive: Keep manifest and helper asset digests explicit and distinct in all client instructions.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs test/agent-handshake-v2-coordinator.test.mjs; git diff --check
Not-tested: live cross-client canary pending this deployment
Constraint: Fresh ERC-8004 keys begin with no Sepolia gas and must be funded by the host after join.
Rejected: Letting clients infer registration timing | Sonnet safely attempted registration before Clockchain knew which address to fund.
Confidence: high
Scope-risk: narrow
Directive: Keep the join then fund then register gate explicit in both instructions and structured local actions.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs test/agent-handshake-v2-coordinator.test.mjs; git diff --check
Not-tested: live cross-client canary pending this deployment
Constraint: Fresh Codex and Claude Code clients must not infer helper flags or re-encode protocol payloads.
Rejected: More prompt prose | the failing clients needed typed executable arguments, not additional narrative.
Confidence: high
Scope-risk: moderate
Directive: Return exact helper argv and encoded payload for every local action; clients may replace only the absolute state-directory placeholder.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs test/agent-handshake-v2-coordinator.test.mjs; git diff --check
Not-tested: live cross-client canary pending this deployment
Constraint: Codex and Claude Code execute helper actions in separate shell processes where PWD-derived variables are not durable.
Rejected: Persisting a shell variable or client-chosen path | both reintroduced inference and cross-call drift.
Confidence: high
Scope-risk: moderate
Directive: Use the exact session-and-role-scoped HOME path and shell suffix returned by each local action.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs test/agent-handshake-v2-coordinator.test.mjs; git diff --check
Not-tested: live cross-client canary pending this deployment
Constraint: Codex workspace-write intentionally denies the client's home directory.
Rejected: Expanding client home permissions | the signer needs only its fresh workspace and broader access weakens the demo boundary.
Confidence: high
Scope-risk: narrow
Directive: Keep the exact session-scoped state path under PWD and preserve typed helper suffixes.
Tested: npm run build; node --test test/agent-handshake-v2-public-server.test.mjs test/agent-handshake-v2-coordinator.test.mjs; git diff --check
Not-tested: live cross-client canary pending this deployment
Fresh Codex and Claude Code sessions need one isolated session temp root and helper 2.1.2 so pre-registration inspection can precede host funding without exposing or reusing signer state.

Constraint: The public endpoint remains exactly seven tools and private keys never cross MCP.

Rejected: Shared PWD or host temp state | Claude Code redirects sandboxed temporary work and can expose prior per-user runtime state.

Confidence: high

Scope-risk: moderate

Directive: Keep the MCP release pin, helper schema version, bootstrap URL, and deployment validator atomic.

Tested: MCP build and 7 focused v2 tests; 24 deployment asset tests; diff check.

Not-tested: production canary awaits SSM pin update and deployment.
Return a complete pinned-helper command and require byte-for-byte reuse of role access so fresh clients cannot corrupt signed inputs while reasoning over them.

Constraint: Fresh Codex and Claude Code clients must execute the hosted MCP flow without plugins or repository-local state.

Rejected: Continue returning a prefix and suffix for model-side concatenation | live Terra canary proved that model transcription can corrupt a role capability.

Confidence: high

Scope-risk: narrow

Directive: Keep helper commands server-authored and executable verbatim; never require agent-side re-encoding of access or payload bytes.

Tested: npm test in packages/mcp-server (289 tests); node --test infra/test/*.test.mjs (30 tests); git diff --check.

Not-tested: Live production cross-client canary runs pending deployment of this revision.
Constraint: The server may expose a certificate but cannot assert that a client executed local verification.\nRejected: Broad retry fallback | it hides programming and state-corruption failures.\nConfidence: high\nScope-risk: narrow\nDirective: Mark only certificate availability server-side and retry only explicitly classified transient errors.\nTested: npm test (all workspaces and 30/30 infra tests green)\nNot-tested: production cross-client canaries pending deployment
Constraint: Fresh Codex and Claude Code clients must execute one machine-pinned helper command without relying on model transcription of a 64-character digest.
Rejected: Keep the digest duplicated in prose and command | Claude Sonnet fabricated a trailing character and correctly stopped on the apparent mismatch.
Confidence: high
Scope-risk: narrow
Directive: Keep the manifest digest authoritative in exactly one executable instruction location.
Tested: npm test -- test/agent-handshake-v2-public-server.test.mjs
Not-tested: Live cross-client production canary pending deployment.
Constraint: Fresh general-purpose agents must not reconstruct or remember a long bearer capability across waiting turns.
Rejected: Rely on initialization prose alone | Codex used the exact capability repeatedly, then substituted a non-verifiable value after a wait response.
Confidence: high
Scope-risk: narrow
Directive: Echo roleAccess on every successful role-scoped tool response and require the next call to use it verbatim.
Tested: npm test (289 tests passed)
Not-tested: Live cross-client production canary pending deployment.
Constraint: A fresh client must use one stable field name for role authorization from its first join through certificate retrieval.
Rejected: Preserve separate initiatorAccess, responderAccess, and roleAccess as equally authoritative names | General-purpose agents stochastically reconstructed the first token despite valid payload context.
Confidence: high
Scope-risk: narrow
Directive: Keep roleAccess authoritative on invite, acceptance, and every successful role-scoped response; retain legacy aliases only for compatibility.
Tested: npm test -- test/agent-handshake-v2-public-server.test.mjs
Not-tested: Live cross-client production canary pending deployment.
Fresh Codex runs preserved capability claims but occasionally altered the long HMAC signature after several tool calls. The dedicated public endpoint now exposes short opaque handles while retaining and verifying the original signed capability behind the server boundary.

Constraint: Preserve the seven-tool contract, existing signed authorization, generic MCP, and bilateral flows.

Rejected: Continue relying on prompt repetition and long-token echoing | two live fresh-agent runs still corrupted signature bytes.

Confidence: high

Scope-risk: moderate

Directive: Do not expose initiatorAccess or responderAccess on the dedicated public endpoint; roleAccess must remain opaque and process-local.

Tested: npm test -w @clockchain/mcp-server (290/290 pass); focused public-server test (5/5 pass); git diff --check.

Not-tested: Live two-client production canary pending deployment of this commit.
Constraint: The production host rotates short-lived discovery sessions, and an invite can race the expiry boundary.

Rejected: Treating an expired current discovery record as a terminal protocol rejection | the caller has not violated protocol and can safely retry unchanged.

Confidence: high

Scope-risk: narrow

Directive: Preserve terminal failures for malformed or unauthorized invitations; only infrastructure rotation remains retryable.

Tested: npm test in packages/mcp-server (291/291); focused coordinator and public-server tests (9/9); git diff --check.

Not-tested: No second production canary was run because the authorized one-attempt gate has been consumed.
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