Skip to content

spike(056-c1): cutover vl/app to @void-layer/codec@0.1.0 (WASM canonical)#301

Open
ignromanov wants to merge 6 commits into
developfrom
spike/056-c1-codec-cutover
Open

spike(056-c1): cutover vl/app to @void-layer/codec@0.1.0 (WASM canonical)#301
ignromanov wants to merge 6 commits into
developfrom
spike/056-c1-codec-cutover

Conversation

@ignromanov
Copy link
Copy Markdown
Owner

@ignromanov ignromanov commented Jun 5, 2026

T-P3-C1 — vl/app codec cutover to `@void-layer/codec@0.1.0`

Replaces the app's local TS codec wire pipeline with the published `@void-layer/codec` (Rust→WASM canonical TLV + Brotli wire). Closes the headline remaining item of spec-056 Phase 3 (Tranche C) — the byte-identity-vs-deployed proof, dogfooding the published package in the real app. Decoupled from publish per decision D1 (publish already shipped; frozen oracle gates byte-identity in codec CI).

What changed

  • `encode.ts` / `decode.ts` → delegate to `encodeInvoiceWire` / `decodeInvoiceWire`; camelCase↔snake_case adapter + `Uint8Array`↔base64url at the feature boundary. Public barrel signatures unchanged → 25 consumers untouched.
  • Deleted (subsumed by WASM canonical): `tlv-map`'s encode role via `app-dict.ts`, `chain-dict.ts` (phf dicts now live in the WASM, byte-identical).
  • Kept (layers above the wire, not owned by the package): `parse-hash`, `og-preview`, `eip712`, `security` (magic dust / salt / encode-side domain-separator), `content-hash`, URL assembly.

Gates

Gate Result
Byte-identity vs frozen oracle (`v4-codec.json`, 46 vectors) ✅ 46/46 encode + 46/46 round-trip — CI-verified
Full suite ✅ CI-verified (1 pre-existing `BelowFoldSections` flake present on develop)
Perf (vitest bench, develop baseline) ✅ encode −9%, decode −15% — faster than TS; zero hot-path regress
WASM cold-init (~37ms one-time) ✅ neutralized via idle warm-up on /create mount
Security co-review (Shade) ✅ PASS-with-conditions — domain-separator relocation TS→WASM proven byte-identical; false-accept closed by construction

CI fix (a14506d)

The original `oracle.test.ts` used a hardcoded absolute path (`/Users/ignat/code/vl/codec/...`) that passed locally but failed in CI with ENOENT, causing the entire test file to error on load — producing `(0 test)` and silently skipping all 46 byte-identity assertions. Fixed by vendoring the frozen oracle into `fixtures/v4-codec.json` and resolving via `import.meta.url + fileURLToPath + path.join`. The oracle is `frozen: true` per decision 2026-05-29-codec-d1-frozen-vectors-oracle — a checked-in copy cannot drift.

Shade conditions

  • C1 (resolved): replaced a fake-green Type-253 test (malformed `uint32BE` payload died before reaching the spoof path) with a real domain-separator integrity test pinning `checksum mismatch` (`CodecError::ChecksumMismatch`). Forward-compat (unknown-odd tags ignored) covered at the Rust level.
  • C2 (resolved): `security.ts validateSecurity` marked encode-side-only (dead on decode path — WASM owns decode-time verification; must not be re-wired).

Follow-ups (non-blocking)

  • F2: `shared/lib/tlv-codec` retained — `security.ts` still imports `derivePRNG`/`writeVarInt`. Inline (2 fns) or keep — defer.
  • F3: `@void-layer/types` `ChainId` union cast in the adapter (runtime-safe via WASM raw-varint path; type-level note).

Generated with Claude Code

Adds the published packages consumed by the T-P3-C1 codec cutover spike.
No production code changed in this commit.
…pter

Replaces encode.ts/decode.ts with thin camelCase↔snake_case adapters
over encodeInvoiceWire/decodeInvoiceWire. Deletes app-dict.ts, chain-dict.ts
(subsumed by WASM phf dicts — byte-parity confirmed in Phase 0).

shared/lib/tlv-codec kept: security.ts (KEEP list) still needs derivePRNG +
writeVarInt for domain separator computation.

Oracle test (oracle.test.ts): 46/46 frozen-vector round-trips pass via pkg
directly; encode-decode.test.ts (36) + hardening (8) pass via new adapters.

Spike finding: app-layer validateSecurity (domain separator JS check) dropped
— WASM validates TLV structure but does not run the app-layer integrity check.
hardening.test.ts line 185: error message changed from "Type spoofing" to
WASM-internal message; assertion relaxed to .toThrow() (security invariant
still holds — malicious payload still rejected).

Full suite: 2844/2847 pass; 1 failure is BelowFoldSections timeout (pre-existing
parallel-run flake, passes in isolation — unrelated to codec).
…eSecurity encode-only

- hardening.test.ts: drop groupedDeflate (ESLint unused-vars, Fix 3)
- security.ts: add NOTE comment on validateSecurity — encode-side only
  after @void-layer/codec cutover; WASM decode path owns domain-separator
  verification and must not be re-wired to call this (Fix 4)
void_layer_codec.wasm incurs a ~37ms cold-init on the first codec call.
Add scheduleWasmWarmup() to src/features/invoice-codec/lib/wasm-warmup.ts:
fires a throwaway encodeInvoiceWire call via requestIdleCallback (setTimeout
fallback for Safari) so the WASM is instantiated before the user clicks
"Generate Link". Mirrors the lazy-web3-provider.tsx and LandingContent.tsx
idle-load pattern.

Wire into CreateWorkspace via a mount-once useEffect (dynamic import so the
warm-up module is not in the main chunk). /pay skipped — decodeInvoice fires
immediately on mount so there is no idle window to exploit.
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
voidpay Ready Ready Preview, Comment Jun 6, 2026 12:39am

…tion

Replace hardcoded absolute ORACLE_PATH (/Users/ignat/...) with a
relative resolution via import.meta.url + fileURLToPath + path.join,
pointing at the new fixtures/v4-codec.json checked-in copy.

The frozen oracle (decision 2026-05-29-codec-d1-frozen-vectors-oracle)
is declared frozen:true and immutable — a vendored copy cannot drift.
Source-of-truth: void-layer/codec packages/codec/vectors/v4-codec.json.

Fixes: ENOENT in CI that caused oracle.test.ts to error on load,
producing (0 test) and silently skipping all 46 byte-identity assertions.
…e total guard + fix decode doc

Finding 1 (P1): add third describe block in oracle.test.ts that converts each
roundtrip vector through toAppInvoice → encodeInvoice (exercises toPackageInvoice
adapter). All 18 vectors pass byte-identical. Fix misleading comment on the existing
direct-encodeInvoiceWire block (no adapter called there). Add total-guard tests
(empty string + undefined) for Finding 2 coverage.

Finding 2 (P2): restore explicit guard in encodeInvoice — throws
'Invoice total is required for encoding' before mapping, so silent ?? '0'
fallback is unreachable on bad input.

Finding 3 (P2): rewrite decodeInvoice JSDoc to state reality — domain-separator,
canonical ordering, and TLV structure validation are performed inside the WASM
decoder; the former app-layer validateSecurity is encode-side only and intentionally
not on this path.
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