feat(wire): #31 · Hello capability discovery + the five evolution rules#212
Merged
Conversation
Add the additive `SignerRequest::Hello` -> `SignerResponse::Hello(HelloInfo)` capability-discovery request to the frozen wire, plus the in-repo rules and registry that govern how the contract may grow. The keystone the x402 chain (#32/#34) and the dapp-origin variant (#198/#204) register new kinds against. - deckard-contract: `HelloInfo { spec_version, capabilities, impl_name }` and a new `capabilities` module — the single source of truth for the registry (SPEC_VERSION 2026-07-07, `core`, `mcp.v0.1`) and the `hello_info()` builder every implementation answers from. - daemon + MCP mock: answer `Hello` from that one builder (parity by construction). The daemon arm reads no state, so it replies identically in every state incl. Locked, revealing capability names only. - MockSigner grows a matching `hello()` so the contract mock shares the parity. - Tests: E1 shape, E2 byte-identity of existing frames (golden-pinned), E3 unknown-variant rejected loudly (the compat valve), E4 unknown struct key ignored; plus a daemon-socket test proving Hello answers while Locked and the daemon survives a bad frame having signed nothing. - docs/build/40-wire-evolution.md: the five rules + the capability registry. Additive only: no existing frame changes, no dependency changes. Implements #31
This was referenced Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements #31 — wire-contract evolution:
Hellocapability discovery + the five evolution rules. One additive request on the frozendeckard-contractwire, plus the in-repo rules + registry that govern how the contract may grow. This is the keystone the x402 chain (#32 → #34) and theProposalOrigin::Dappvariant (#198 / #204) register their new kinds against.An old daemon that predates the variant fails to decode it and returns the existing frame-decode error — that rejection is the backward-compat valve, and it already ships. No existing frame changes.
How it maps to #31's in-scope checklist
Hello+HelloInfoindeckard-contract; answered in every daemon state incl.Locked(the daemon arm reads noself.state); reveals capability names only — no state, policy, or key material.core,mcp.v0.1) — in code (crates/deckard-contract/src/capabilities.rs, the single source of truth) and as thename · status · since · defining doctable in the new build doc.docs/build/40-wire-evolution.md(indexed indocs/build/README.md).Helloshape —spec_versionmatches^\d{4}-\d{2}-\d{2}$,capabilities ⊇ {core, mcp.v0.1}.Balancedata frame; the round-trip fixtures were extended withHello, every prior assertion unchanged).Err, no panic (CBOR + JSON), and at the socket the daemon repliesmalformed_request, keeps serving, and signs nothing.deny_unknown_fields).impl_name.Single-source parity
The daemon (
IMPL_SIGNERD), the MCP acceptance mock (IMPL_MOCK), and the contractMockSigner::hello()all build their answer from onecapabilities::hello_info(), sospec_version+capabilitiescan never drift between implementations — onlyimpl_namediffers. Pinned byhello_info_is_single_sourced,hello_matches_the_single_source_registry, and the daemon-socket test.Open question — deferred (not auto-closing #31)
#31 asks whether
HelloInfoshould also carry the daemon's active chain id (leaning yes). I did not include it: the normative in-scope text says "capability names only — no state," chain id is state, and a wrong-chain client is already refused at firstProposewithDeny{chain_mismatch}. It can be added additively later — precisely by these rules (a new field an old client ignores per E4) — if we decide first-contact chain detection is worth the state it exposes. Flagged in40-wire-evolution.md; easy to flip if you'd prefer it in now.Definition of done (evidence)
cargo fmt --all --check— clean.just check— green (clippy-D warningson default,--features tray, and--features dev-signerd-bin).TMPDIR=/tmp cargo test --workspace— green (430 passed, 2 pre-existing ignored).Cargo.toml/Cargo.lockuntouched).Balanceself-comparison in E2) are all fixed in this branch.Contract + daemon + client/test work only; no GPUI app views touched.