Repository navigation
Description
Part of #44 (ADR-0001). Blocks the dapp leg of #186's origin attribution and #187's "Authorized by". Sequenced after #31 — the new enum variant ships under the wire-evolution rules (decoders reject unknown variants; advertise as a Hello capability).
Why: the review card is Deckard's trust product — a card that says "You are sending" when a website asked is a lie. After this, every browser request is attributed to the site that made it: the visible core of the browser demo.
Problem
The bridge already knows which site is asking — the extension sends the origin in an x-deckard-origin header (extension/background.js:31-37) and the bridge keys per-origin sessions on it (crates/deckard-browser-bridge/src/lib.rs:49-102). But the wire cannot carry it for transactions: ProposalOrigin is only App | Agent (crates/deckard-contract/src/rpc.rs:19-24), and both bridge propose calls hardcode App (lib.rs:423, lib.rs:450). Result: a dapp's eth_sendTransaction renders as "You are sending" (activity_view.rs:874-882 falls to Origin::You) — a false human attribution — and the pending rail shows the neutral "Awaiting your approval" header (activity_view.rs:1617, :1761).
Message signing already does this right: SignMessage.origin: String (message_signing.rs:16) flows to the daemon (daemon.rs:905) and renders Origin::Dapp { domain }. This issue brings transactions to parity.
Scope
deckard-contract: addProposalOrigin::Dapp { origin: String }. Additive per Wire-contract evolution: Hello capability discovery + the five evolution rules #31's evolution rules; old decoders reject it loudly (that is the back-compat valve). Match the existing hand-rolled serde pattern (tagged enums break CBOR via ciborium).deckard-browser-bridge: replace both hardcodedProposalOrigin::Appcall sites with the session origin.deckard-signerd: store the origin on the pending record, like message proposals already do.deckard-app: tx payloads with a Dapp origin renderorigin_header/Origin::Dapp { domain }on the review body (activity_view.rs:870-883), the pending rail (activity_view.rs:1609-1618,:1761), the Activity row, and the E3 right rail. The widgets already exist (widgets.rs:547-668) — wire them, don't invent new ones.- Trust invariant: a Dapp-origin request never gets the "you" treatment; the origin string is shown verbatim (
unknown-originshows asunknown-origin, no prettifying).
Non-goals
- Origin verification/attestation, registry, anti-phishing (PRD-05: Per-origin permissions, registry & anti-phishing #48).
- Per-origin policy — evaluation is unchanged; this is attribution only.
- Agent identity strings (Agent identity on the wire + a true per-agent stop (follow-up) #204).
Tests
- Wire round-trip for the new variant + old-decoder rejection (evolution-rule test, Wire-contract evolution: Hello capability discovery + the five evolution rules #31 pattern).
- Admission/evaluate parity: same intent, Dapp vs App origin → same decision.
- Pure mapper unit: Tx payload + Dapp origin →
Origin::Dapp.
Acceptance
- From the fixture dapp,
eth_sendTransactionraises a card attributed to the dapp origin (screenshot on the PR). personal_signand transaction attribution now match for the same origin.- DoD green; before/after screenshots (GUI change).
Activity
feat(wire): #31 · Hello capability discovery + the five evolution rul…
feat(wire): #198 · Dapp origin on the wire — attribute browser transa…
docs(bridge): #202 · ADR 0006 localhost transport + fix stale browser…