feat: #275 — plant parity dissolved into the type system (wasm tier-3) + #215 B1/B2 re-land#293
Merged
Merged
Conversation
…, web-core shares the cap-mint body Re-lands #215's B1 against current main (the original branch rotted 56 commits behind; protocol.rs had grown +256 lines that the move had to re-port). Extract the broker/worker wire types (backend-client's protocol module) into a standalone pure-serde agentkeys-protocol crate (no reqwest/tokio/aws — compiles to wasm32). agentkeys-backend-client re-exports it as ::protocol, so every existing agentkeys_backend_client::protocol::* path still resolves. agentkeys-web-core (browser/wasm) now aliases the SHARED BrokerCapRequest as CapRequest instead of carrying its own copy. That kills TWO live drifts: ttl_seconds (required u64 native vs Option<u64> browser — the shared type is Option + skip, faithful to the broker's serde default; native callers always send Some, wire byte-identical) and the #76 K10 cap-PoP fields (client_sig/client_nonce/client_ts), which web-core's copy was missing entirely (browser sends None — verified-when-present). web-core must NOT depend on backend-client directly (pulls aws-sdk-sts + tokio + native reqwest via the provisioner; breaks the wasm build): new harness-ci rust-checks gate cargo-checks web-core for wasm32 (default + --features wasm). The wasm32 target itself is pinned in rust-toolchain.toml (single SoT; rustup toolchain install picks it up — no dtolnay action, per the #276 pin rule). Verified: cargo build/test --workspace, clippy -D warnings, fmt, wasm32 checks (default + wasm), dump-protocol-fixtures --check (cap_mint_request.json byte-unchanged), check-backend-fixture-drift.sh, check-web-api-drift.sh.
…pes; CI typechecks against them Re-lands #215's B2 against current main, extended to everything that grew while that branch rotted. ts-rs derives on the daemon's 12 ui_bridge Api* structs + MemoryCategory now generate apps/parent-control/lib/generated/*.ts; daemon.ts imports them and all 8 hand-declared wire interfaces are deleted. A Rust-side field rename is a frontend compile error (rung 2 → rung 3). u64 fields pin #[ts(type=number)]; skip-serialize Options pin #[ts(optional)]. Extended past #215's scope (its own flagged follow-up): - ProposedScope + the catalog Sensitivity generate too; gating becomes a real ScopeGating enum (TS union "auto" | "k11" instead of a bare &'static str). - The protocol crate's WireUserOp / BuildAcceptUserOpResponse / SubmitAcceptUserOpResponse generate too — daemon.ts's three inline UserOp build-response types and ApiSubmitResult are replaced by the shared shapes. Two latent drifts the codegen forced into the open, fixed here: - SubmitAcceptUserOpResponse had drifted from what the broker actually returns (#97 user_op_hash + audit_envelope_hashes, #230 pending) — realigned to the broker's real serialization; the daemon proxies relay it verbatim. - ApiActor's account_address/account_type were ad-hoc serde_json inserts in enrich_actor_account, invisible to any type contract — folded into the struct as proper optional fields. CI (harness-ci rust-checks): git diff --exit-code on the generated dir after cargo test regenerates, plus a NEW frontend gate — wasm-pack build + npm ci + tsc --noEmit — so the bindings AND their consumer typecheck on every PR (apps/parent-control/** added to the PR path filter; npm run typecheck is now fully green in CI for the first time, the core.ts wasm-artifact failures are gone because CI builds the wasm). ts-rs rides the no-serde-warnings feature. Verified: cargo fmt/test/clippy -D warnings (workspace), generated dir diff-clean after regeneration, check-web-api-drift.sh, fixture --check, npm run typecheck green.
…sm tier-3) The plant contract (MASTER_MEMORY_PLANT_ROUTE + ApiMemoryEntry + request/response bodies) moves to the wasm-safe agentkeys-protocol::web_api; ui_bridge re-exports it (daemon-internal code + the fixture-pinning test keep their names; the entry helpers ride an extension trait since inherent impls stay in the defining crate; PlantRequest/PlantResponse take their canonical MasterMemoryPlant* names). agentkeys-web-core exports masterMemoryPlantRoute() + buildMasterMemoryPlantBody() under --features wasm: the body bytes come from serde_json over the daemon's own types compiled into the browser. daemon.ts stops hand-building the plant route/body entirely — it feeds ts-rs-typed entries to the wasm builder and posts the returned JSON verbatim (postJsonBody; re-stringifying would launder the bytes through JS). One code path; violating parity is a compile error. A shared memoized wasm-module loader (lib/client/wasm-module.ts) backs both CoreBackend and the plant path. The daemon.ts half of scripts/check-web-api-drift.sh retires (compile-checked now); the harness half (web-parity-demo.sh's hand-curled body) stays fixture-gated, and the fixture stays pinned to the shared types by the ui_bridge unit test. Phase 6 is at its terminal thinness: the irreducible 'daemon -> cap-mint -> STS -> worker -> S3 reachable on real infra' smoke. Docs: harness/AGENTS.md ladder (rung 3 done), operator-runbook phase 6, root AGENTS.md plant-contract bullet, arch.md crate tree (+agentkeys-protocol). Verified: cargo fmt/test/clippy -D warnings (workspace), wasm32 checks, wasm-pack build of the new exports, check-web-api-drift.sh (harness consumer), check-backend-fixture-drift.sh, fixture --check, npm run typecheck green, generated bindings committed (MasterMemoryPlantRequest/Response.ts).
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.
Summary
Resolves #275 (the phase-6 web-parity tier-3 move) and supersedes #215 — that PR's B1/B2 are the substrate this builds on, but its branch rotted unmergeable (56 commits behind;
protocol.rs+256 lines under the file move,ui_bridge.rs+5403/−873), so the content is re-implemented fresh from currentmainin three commits. The design decisions from #215's Codex adversarial review survived unchanged.The arc: push the daemon↔frontend plant contract down the parity ladder (
harness/AGENTS.md"Parity/wiring checks evolve down a ladder") until the runtime check is only the irreducible wiring smoke.Commit 1 — B1 re-land:
agentkeys-protocol(wasm-safe wire crate)agentkeys-backend-client::protocolinto a standalone pure-serdeagentkeys-protocolcrate (no reqwest/tokio/aws → compiles towasm32).backend-clientre-exports it as::protocol— every existing path still resolves, zero ripple to the MCP server / daemon / broker.agentkeys-web-core(browser) now shares the cap-mint body (CapRequest= alias of the sharedBrokerCapRequest) instead of carrying its own copy. That kills two live drifts: thettl_secondsdivergence refactor: #203 follow-up — agentkeys-protocol wire crate (wasm-safe) + ts-rs frontend bindings #215 originally found (requiredu64native vsOption<u64>browser — unified asOption+ skip, faithful to the broker's#[serde(default)]; native callers always sendSome, wire byte-identical), and a second drift that accumulated while refactor: #203 follow-up — agentkeys-protocol wire crate (wasm-safe) + ts-rs frontend bindings #215 rotted: web-core's copy was missing the Retire the bearer-JWT-only daemon→signer /dev/* path (align to arch §14.2; rescoped from Step 1c) #76 K10 cap-PoP fields (client_sig/client_nonce/client_ts) entirely.aws-sdk-sts+tokio+ nativereqwestvia the provisioner and breaks the wasm build. New CI gate:cargo check --target wasm32-unknown-unknown -p agentkeys-web-core(default +--features wasm). The wasm32 target is pinned inrust-toolchain.toml(single SoT; no dtolnay action, per the ci: pin Rust to 1.96.0 — rust-toolchain.toml is the single source of truth #276 pin rule).Commit 2 — B2 re-land, extended: ts-rs generates the frontend wire types
ui_bridgeApi*structs generateapps/parent-control/lib/generated/*.ts;daemon.tsimports them and all 8 hand-declared wire interfaces are deleted. A Rust-side field rename is now a frontend compile error (rung 2 → 3).u64→#[ts(type = "number")], skip-serializeOptions →#[ts(optional)].ProposedScope+ the catalogSensitivitygenerate too (with a newScopeGatingenum replacing the bare&'static str, so TS gets the"auto" | "k11"union), and the protocolWireUserOp/BuildAcceptUserOpResponse/SubmitAcceptUserOpResponsereplacedaemon.ts's three inline UserOp build-response types +ApiSubmitResult.SubmitAcceptUserOpResponsehad drifted from what the broker actually returns (AuditEnvelope v1 — unified abstract audit message format (Phases B + C + F) #97 addeduser_op_hash+audit_envelope_hashes, Decouple UserOp submission from the broker into an ERC-4337 bundler #230 added thependingvariant) — realigned to the broker's real serialization.ApiActor'saccount_address/account_typewere ad-hocserde_jsoninserts inenrich_actor_account, invisible to any type contract — folded into the struct as proper optional fields.rust-checks):git diff --exit-codeon the generated dir aftercargo testregenerates it, plus a frontend typecheck step (wasm-pack build →npm ci→tsc --noEmit) so the bindings AND their consumer compile on every PR.apps/parent-control/**added to the PR path filter (a frontend-only PR previously skipped the job entirely).npm run typecheckis fully green in CI for the first time — the historicalcore.tswasm-artifact failures are gone because CI builds the wasm.Commit 3 — the #275 delta: dissolve the plant parity check into the type system
ApiMemoryEntry+ request/response bodies) moves toagentkeys-protocol::web_api;ui_bridgere-exports it (daemon-internal code + the fixture-pinning unit test unchanged; the entry helpers ride an extension trait since inherent impls stay in the defining crate).agentkeys-web-corewasm exportsmasterMemoryPlantRoute()+buildMasterMemoryPlantBody(entries)— the body bytes come fromserde_jsonover the daemon's own types, compiled to wasm.daemon.tsstops hand-building the plant route/body entirely: it calls the wasm builder (typed input via the generatedApiMemoryEntry), posting the returned JSON verbatim. One code path; violating parity is a compile error.daemon.tshalf ofscripts/check-web-api-drift.shis retired (compile-checked now); the harness half (web-parity-demo.sh's hand-curled body) stays fixture-gated. Phase 6 is at its terminal thinness: the irreducible "daemon → cap-mint → STS → worker → S3 reachable on real infra" smoke.lib/client/wasm-module.ts) backs bothCoreBackendand the plant path.harness/AGENTS.mdladder section (rung 3 marked done),docs/operator-runbook-harness.mdphase 6, rootAGENTS.md§203 (split-crate + plant-contract bullets),docs/arch.mdcrate tree, plan docdocs/plan/frontend-testability-cli-web-parity.mdcarried over from refactor: #203 follow-up — agentkeys-protocol wire crate (wasm-safe) + ts-rs frontend bindings #215 with updated status.Verification
cargo build/test --workspace✓ ·cargo clippy --workspace --all-targets -- -D warnings✓ ·cargo fmt --check✓cargo check --target wasm32-unknown-unknown -p agentkeys-web-core(default +--features wasm) ✓dump-protocol-fixtures --check✓ (cap_mint_request.jsonbyte-unchanged) ·check-backend-fixture-drift.sh✓ ·check-web-api-drift.sh✓ (harness consumer)npm run typecheck✓ (zero errors, includingcore.ts)What landed / did NOT land
Landed: every #275 scope bullet (wasm bindings for the plant types,
daemon.tsconsumes them, thedaemon.tsdrift-gate half retired, ladder + runbook docs updated) plus the B1/B2 re-land it depends on.Did NOT land: nothing from the #275 scope. From the broader plan doc, Part A (frontend Vitest) + B4 remain future work, unchanged in status (documented in the plan doc).
To test this
dev.sh(it rebuilds the daemon AND the wasm pkg —build_wasmpicks up the new exports automatically)agentkeys-backend-client/agentkeys-protocolare internal-refactor-only on the wire (cap-mint body byte-identical). The next routinesetup-broker-host.sh --ref mainpicks it up.Supersedes #215. Resolves #275.
🤖 Generated with Claude Code