Skip to content

feat(web): add skill tree hash spec, shared vectors, and read-only sweep - #262

Merged
dirtybits merged 3 commits into
mainfrom
feat/skill-tree-hash-spec
Nov 4, 2026
Merged

dirtybits merged 3 commits into
mainfrom
feat/skill-tree-hash-spec

Conversation

@dirtybits

@dirtybits dirtybits commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

What this does

Phase 1, PR 1 of .agents/plans/skill-evals-and-packages.plan.md (the plan file is new in this PR).

  • docs/SKILL_TREE_HASH.md — the written rule for a skill version's fingerprint (agentvouch-tree-v1). It documents what computeTreeHash already does, so no stored hash changes. It also covers path rules, the file manifest, how a client checks a download, finding codes, and known gaps.
  • Shared test vectors — packages/agentvouch-protocol/test-vectors/tree-hash.json (10 vectors, 9 invalid paths) and tree_hash_reference.py, an independent stdlib Python implementation that produced the expected values.
  • web/__tests__/lib/treeHashVectors.test.ts — the production computeTreeHash against every vector.
  • npm run db:tree-hash-sweep (web/scripts/tree-hash-sweep.ts, logic in web/lib/treeHashAudit.ts) — read-only audit of stored versions: one SELECT (compiled and checked offline in tests) plus Blob reads. It does not call the download routes, because they record download events and change install counts. It also checks that skill_versions.content (what /raw serves for SKILL.md) equals SKILL.md in the stored tree.
  • AGENTS.md — keeps the shorter task index and links package work to the spec. Detailed integrity rules live in docs/AGENT_REFERENCE.md.

Verified

  • npm run format:check, npm run lint, npm run typecheck: pass.
  • Web vitest: 157 files, 1477 tests pass. CLI vitest: 16 files, 119 tests pass. (Run with Node 24.22.1. In the cloud workspace, github-skill-discovery-route.test.ts fails twice unless GITHUB_TOKEN is unset, because the workspace sets that variable; this PR does not touch that test.)
  • python3 packages/agentvouch-protocol/test-vectors/tree_hash_reference.py: all vectors pass.
  • Mutation check: switching computeTreeHash to locale-aware sorting, code point sorting, or NFC-normalized paths makes the vectors fail.
  • Sweep setup paths: missing DATABASE_URL, bad options, and an EXPECTED_DATABASE_HOST mismatch all exit 2 before any query.
  • next build --webpack (with mocked Google Fonts, because the workspace cannot reach fonts.googleapis.com): compiled and typechecked, then stopped at the /sitemap.xml prerender without DATABASE_URL, as recorded in earlier plans. Vercel is the build gate.

Not verified

  • The sweep has not run on production data yet. It needs DATABASE_URL and BLOB_READ_WRITE_TOKEN. The CLI download check (next PR) should ship only after the sweep shows zero mismatches.

Findings recorded in the plan

  • Upload accepts a tree where one path is also a folder of another path (docs and docs/a.md); such a tree cannot be installed. The sweep reports it as path_conflict; the fix is planned for the next PR.
  • ingestTarArchive enforces the upload limits (200 files, 5 MB) while mirror sync stores up to 512 files and 8 MB, so /raw?path= and /zip would fail for a large mirrored tree. The sweep will show whether any exist.

Generated by Claude Code

Review follow-up (2026-11-04)

Signed merge 51718c7 resolves the instruction conflict against current main. AGENTS.md is 1,135 words versus 5,295 in the previous manual (79% shorter). All 35 named safeguards and approval boundaries are preserved in the root/companion structure. Independent review and documentation-link checks passed. Python passed 10 vectors and 9 invalid paths; focused Vitest passed 91 tests. No production sweep was run.

Phase 1, PR 1 of .agents/plans/skill-evals-and-packages.plan.md.

- docs/SKILL_TREE_HASH.md: normative agentvouch-tree-v1. It documents what
  computeTreeHash already does (no stored hash changes), plus path rules,
  the file manifest, client download checks, and known gaps.
- packages/agentvouch-protocol/test-vectors/: 10 vectors and 9 invalid
  paths, with a stdlib Python reference that produced the expected values.
- web/__tests__/lib/treeHashVectors.test.ts: production computeTreeHash
  matches every vector.
- web/lib/treeHashAudit.ts and web/scripts/tree-hash-sweep.ts
  (npm run db:tree-hash-sweep): read-only audit of stored versions. One
  SELECT plus Blob reads; it never uses the download routes, which record
  download events.
- AGENTS.md: list the spec as a source of truth.

Verified: format:check, lint, typecheck, web vitest (157 files, 1477
tests), CLI vitest (16 files, 119 tests), Python vector check, and a
mutation check (locale sort, code point sort, and NFC paths each fail the
vectors). next build --webpack compiled and typechecked, then stopped at
the /sitemap.xml prerender without DATABASE_URL.

Not verified: the sweep has not run on production data.
D1-D11 and D14 approved with the recommended defaults. D12 stays off. D13: no evaluation model spending yet, so Phase 2 uses mock runs only. The owner runs the production sweep and merges every PR.
@dirtybits
dirtybits merged commit a5a9798 into main Nov 4, 2026
3 checks passed
dirtybits added a commit that referenced this pull request Nov 4, 2026
Phase 1, PR 2 of .agents/plans/skill-evals-and-packages.plan.md.
Follows #262 (merged).

CLI:
- New src/lib/integrity.ts (agentvouch-tree-v1). skill install and
  skills update check every download before they write: a tree against
  tree_hash, and a single SKILL.md against its manifest entry and the
  manifest against tree_hash. On a mismatch the CLI re-reads the skill
  once (a new version can be published during the download), then stops
  and writes nothing.
- Stop before any download or payment when the skill has no published
  tree_hash, so a paid install cannot take the payment and then refuse
  to write.
- Hash and write the exact /raw bytes. response.text() dropped a
  leading byte order mark.
- Read downloads with the mirror limits (512 files, 8 MB).
- Install metadata records tree_hash_algorithm and tree_hash_verified_at.
- The CLI passes the shared tree-hash vectors.

Web:
- GET /api/skills/{id}/versions/{version}/archive serves one stored
  version, with the same access rules as /archive.
- Upload rejects a file/folder path conflict ("docs" and "docs/a.md")
  with a 400, and putSkillTree rejects it too. Mirror sync skips such a
  skill, so it cannot fail the daily mirror cron.
- Read stored trees with the mirror limits, so /raw?path= and /zip can
  serve a mirrored tree above the upload limits.

Docs: docs/SKILL_TREE_HASH.md, web/public/skill.md (2.3.0), the CLI
README, and the plan.

Verified: format:check, lint, web and CLI typecheck, web vitest (166
files, 1613 tests), CLI vitest (18 files, 173 tests), Python vectors.
next build --webpack compiled and ran TypeScript, then stopped at the
/sitemap.xml prerender without DATABASE_URL.

Not verified: the production sweep, and a live fetch from the new
version route. Merge only after the sweep shows zero mismatches.

This branch was successfully deployed

1 active deployment
Preview — 51718c7f Deployed Nov 4, 2026 by vercel[bot]
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