Skip to content

Guard against silent de-vendoring of module crates, and re-vendor tinydocs #5559

Description

@senamakel

Summary

The TinyWallet module migration is, as far as I can measure, already complete — signing runs in the module, and the heavy gates (key, tx, client, asset, x402) are shed from the shipped build. What is missing is not more migration but a guard: the crate was silently de-vendored and inlined once before (3ee5a3cad), nothing would catch it happening again, and tinydocs is in exactly that state right now.

Problem / Context

First, the part that is done, recorded so nobody re-opens it as if it were incomplete. On 90dabbb5b the host takes:

tinywallet = { path = "vendor/tinywallet", default-features = false,
  features = ["btc","evm","solana","tron","keccak","net","wire","eip712","abi","tx-codec"], optional = true }

against a crate whose default is ["btc","evm","solana","tron","keccak","net","key","asset","client","tx","x402","wire","eip712","abi"]. So key, asset, client, tx and x402 are already dropped. tx-codec rather than tx is the load-bearing choice: tx is the only thing that pulls bitcoin and its native secp256k1 C build, while tx-codec gives the verification half (recompute_txid, verify_contract, digest, attach_signature) with only sha2. OpenHuman signs through the module over k256, so it never links bitcoin.

The web3 gate now sheds 5 crates, down from 25 — the whole secp256k1 / elliptic-curve / coins-bip cohort left when signing moved in-module. What remains (bech32, keccak, ripemd, sha3, tinywallet) is the deliberate residue: the wire contract, address validation, and transaction verification. Per AGENTS.md, the host is supposed to keep "RPC endpoint resolution, transaction assembly and broadcast, key custody". The three production tinywallet::key::derive call sites are all behind #[cfg(test)], annotated "Test-only: production derives inside the wallet module."

So the risk here is regression, not incompleteness. On 2026-08-12, commit 3ee5a3cad ("refactor: run tiny domains as TinyBus modules") removed the vendor/tinywallet submodule and inlined ~3,700 lines of crate source into src/openhuman/web3/wallet/primitives/, rewriting every crate:: path and collapsing the crate's granular chain gates onto OpenHuman's single web3 gate. That was collateral damage from a larger change, not a decision — the Cargo.toml comments and AGENTS.md were left describing the crate-based design, so code and docs contradicted each other for a day.

That is not a cosmetic problem. An inlined copy of a shared crate is a silent fork. Four real fixes accrued in OpenHuman's copy that no other host ever saw, including a key-derivation bug where a SLIP-10 path segment already carrying the hardening bit was OR-ed with it again, so m/44'/501'/2147483648' and m/44'/501'/0' derived the same key. It was restored in #5533 / tinywallet#16 / tinywallet#17.

Nothing prevents a recurrence, and the same failure is live elsewhere today: tinydocs has no vendor/tinydocs directory, no .gitmodules entry and no dependency declaration, while four separate Cargo.toml comment blocks still describe it as one — including # After cloning: git submodule update --init vendor/tinydocs, an instruction that cannot work. Its spec types are inlined at src/openhuman/tools/impl/document/{types.rs, format/spec, format/error}.

Scope

In scope

  • A CI guard asserting that every crate the manifest comments describe as vendored is actually a .gitmodules submodule with a matching path dependency. The check is cheap and would have caught 3ee5a3cad on the PR that introduced it.
  • Restore tinydocs to a vendored submodule + default-features = false path dependency, matching what the comments already claim, and diff the inlined copy against upstream first so any fixes that accrued locally go upstream rather than being discarded.
  • Confirm and document that TinyWallet's remaining host-side surface is intentional, so the residue is not mistaken for unfinished work.

Not in scope

  • Moving verification into the module. digest / attach_signature / signature_hex are deliberately on the codec side — exactly what a host doing its own k256 signing over a returned digest needs.
  • tinymemory — tracked separately, and genuinely incomplete.

Implementation note

Prefer verify_contract over verify_transfer at any new call site: the latter is a substring scan over the hex that a decoy field or a substituted amount defeats.

Acceptance criteria

  • Vendoring guard — CI fails when a crate described as vendored in a manifest comment is missing from .gitmodules or from the dependency list. Guard is proven by a red run against 3ee5a3cad's shape.
  • tinydocs re-vendored — submodule restored, taken with default-features = false for the wire contract, inlined sources under src/openhuman/tools/impl/document/ deleted.
  • No fixes lost upstream — the inlined tinydocs copy is diffed against the crate and any local fixes are landed in the tinydocs repo before deletion.
  • No dependency regressionscripts/kernel-floor.sh and scripts/assert-shed.sh confirm re-vendoring does not re-add docx-rs / ppt-rs / pdf-extract or their tails to the product graph.
  • TinyWallet residue documentedAGENTS.md states which host-side surface is deliberate (wire contract, address validation, tx-codec verification, RPC resolution / broadcast / custody) so it is not re-litigated.
  • Diff coverage ≥ 80% — the implementing PR meets the changed-lines coverage gate when code changes are involved.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

priority: p2Soon. Real but survivable — a rough edge, a gap, a thing that will bite later.

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions