Skip to content

feat: CAP-Tree v0.3 HTTP binding — content-addressed object host#45

Open
twilson63 wants to merge 4 commits into
mainfrom
feat/cap-tree-v0.3-host
Open

feat: CAP-Tree v0.3 HTTP binding — content-addressed object host#45
twilson63 wants to merge 4 commits into
mainfrom
feat/cap-tree-v0.3-host

Conversation

@twilson63

Copy link
Copy Markdown
Owner

Summary

Makes ZenBin the first conformant CAP-Tree v0.3 host — content-addressed object storage, tree read endpoints, refs-chain enforcement, and discovery — alongside (not replacing) the existing v0.2 pages API. Implements the PRD in plan-prd.md (spec: https://github.com/twilson63/cap-tree).

  • Vendored cap-tree-core (src/vendor/cap-tree-core/, MIT, source-commit header) — all canonicalization/hashing/verification comes from the reference library; swap to npm once cap-tree-core@0.3.0 is published.
  • Storage (src/storage/capTreeDb.ts): objects / tree-index / refs LMDB environments; immutable content-addressed objects; atomic refs-chain head advance (fork-safe).
  • Host-side validation (HB § 5) in ObjectService: envelope + structural checks, genesis owner match, parent resolution, verifyRootChain for non-genesis/merge roots, refs target + owner checks + chain extension. Merge roots are not policy-policed.
  • Routes: POST/GET /v1/objects (signed publish / open retrieve, immutable cache), /v1/trees reads (refs, refs/history, roots, roots/history, resolve), /v1/reviews query, /.well-known/cap-tree.json discovery. Objects consume page quota 1:1.
  • Errors: 13 CAP-Tree codes; 422 bodies carry errors[]; 409 carries currentSeq/currentHash recovery info.
  • Also includes a proxy fix (use undici's own fetch so the dispatcher version matches) and the PRD progress update.

Test plan

  • 429/429 tests pass (27 files), including 4 new suites: cap-tree-objects, cap-tree-refs, cap-tree-reads, cap-tree-lifecycle
  • All 8 spec test vectors + vector blob round-trip byte-exactly at their stated hashes
  • Policy-violating merge accepted (201) — "host MUST NOT police policy" regression test
  • Refs conflicts/gaps → 409 with recovery info; full history retrievable
  • v0.2 suite unchanged and green; tsc --noEmit clean
  • No new runtime dependency beyond the vendored cap-tree-core

🤖 Generated with Claude Code

twilson63 and others added 4 commits June 10, 2026 16:49
Real root cause of the proxy 502s (UND_ERR_INVALID_ARG): the code passed
an npm-undici `Agent` as the `dispatcher` to Node's **built-in** global
`fetch`. Built-in fetch validates the dispatcher against its own bundled
undici's Dispatcher class; an Agent from the npm `undici` package is a
different class when the two undici versions differ, so it is rejected
with UND_ERR_INVALID_ARG — before any lookup/connector code runs. That is
why #42 (lookup forms) and #43 (connector override) both failed with the
exact same error, and why it worked locally (local Node's bundled undici
matches npm undici 6.26).

Fix: call undici's own `fetch` (imported from the same package as Agent),
so dispatcher and fetch are guaranteed the same version. SSRF validation
and connector IP-pinning are unchanged.

Verified locally end-to-end (undici fetch + pinned dispatcher + full
response body read): https/http public hosts return 200; SSRF targets
remain blocked. tsc + build clean; proxy.test.ts 52/52.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Makes ZenBin a conformant CAP-Tree v0.3 host alongside the existing v0.2
pages API (nothing migrated). Implements the PRD in plan-prd.md.

- Vendor cap-tree-core (twilson63/cap-tree core/, MIT) into
  src/vendor/cap-tree-core; add DOM to tsconfig lib for WebCrypto types.
  All canonicalization/hashing/verification comes from the library.
- Storage (src/storage/capTreeDb.ts): objects, tree-index, refs LMDB
  environments; immutable content-addressed objects; atomic refs-chain
  head advance via transactionSync (fork-safe). config.capTree.maxObjectBytes.
- ObjectService (src/services/objectService.ts): host-side validation
  (HB § 5) — envelope + structural checks, genesis owner match, parent
  resolution, verifyRootChain for non-genesis/merge roots, refs target +
  owner checks + chain extension. Merge roots are NOT policy-policed.
- Routes: POST/GET /v1/objects (signed publish / open retrieve, immutable
  cache), /v1/trees reads (refs, refs/history, roots, roots/history,
  resolve), /v1/reviews query, /.well-known/cap-tree.json discovery.
  Objects consume page quota 1:1 via reserve/release.
- Errors: 13 CAP-Tree codes; 422 bodies carry errors[]; 409 carries
  currentSeq/currentHash recovery info.
- Tests: cap-tree-objects (vectors round-trip byte-exact, idempotency,
  tamper/parent/owner rejections, oversize, policy-violating merge
  accepted), cap-tree-refs (chain enforcement, conflict/gap → 409,
  non-owner → 403, history), cap-tree-reads (roots/history/resolve/
  reviews/discovery), cap-tree-lifecycle (build → publish → clone →
  verify via API-only resolver). setup.ts cleans the new content-addressed
  envs so fixed-hash objects don't leak across files.

All § 8 acceptance criteria pass: 429/429 tests green, tsc --noEmit and
production build clean, v0.2 suite unchanged. No new runtime dependency
beyond the vendored cap-tree-core.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Status → Implemented (a39d5f7). New § 11 records sequencing/acceptance
completion (re-verified: 429/429 tests, typecheck clean), deviations
(vendored cap-tree-core, dedicated capTreeDb.ts), and open items
(stretch goals, npm swap, post-deploy conformance).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rash-heal

- Swap the vendored cap-tree-core copy for the published npm package
  (cap-tree-core@0.3.0) and delete src/vendor/cap-tree-core — one
  implementation, no drift.
- rootHistory now accepts a cursor so next_cursor is actually consumable;
  GET /v1/trees/{treeId}/roots/{hash}/history takes ?cursor=.
- publishRefs heals the extend-then-store crash window: re-publishing a
  refs object that is already the chain head but unstored succeeds and
  stores it instead of 409ing against itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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