Repository navigation
feat(merkle): freeze MerkleNode bytes with cross-language conformance vectors - #113
Merged
Merged
Conversation
WHAT: five vectors (no parents, one, shuffled, duplicate, nested payload), each pinning dag-cbor hex and CID string. WHY: freezes the node layout (#112). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WHAT: Rust rebuilds each vector via MerkleNode; Python rebuilds the bytes by hand (it cannot encode links) and checks bytes, CID and the checked decoder. WHY: a layout change must fail CI in both languages (#112). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WHAT: ungate merkle module and re-export; unstable-merkle stays as a deprecated no-op alias; module docs say frozen instead of non-frozen. WHY: bytes are now pinned by cross-language vectors (#112). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WHAT: pre-push, ci.yml and justfile name what each pass proves now that MerkleNode is default; python parity gate named CI-only in the hook. WHY: hook-parity rule after the feature flag moved (#112). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…erkle MerkleNode is on by default now, so "same posture as unstable-merkle" wrongly suggested it was still opt-in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WHAT: exact node map, key order, parent sort/dedup rule, tag-42 link form, CID derivation, payload rule, frozen scope and a who-rejects-what table. WHY: an implementer should not need src/merkle.rs (#112 hardening). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WHAT: proptest permutation/duplication invariance against a spec-derived encoder, decode/re-encode identity, blake3 pin of merkle_vectors.json, and adversarial inputs through the checked decoder with decoder-vs-verify split. WHY: golden vectors alone cannot show order independence or refusals. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WHY: regenerating expected output must not be a quiet way to accept a layout change; MERKLE_VECTORS_REGENERATE=1 is required. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the spec WHAT: envelope frozen, payload frozen only inside the canonical data model; STABILITY and module docs link the wire spec; Python gate cites it, not Rust. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… parents) WHAT: append two vectors; the first five are byte-identical. The spec encoder and the Python gate now implement the minimal array-header rule; the file's BLAKE3 pin is updated consciously in this commit. WHY: MERKLE_WIRE.md §2 specified those headers but no vector exercised them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ctor count WHAT: MERKLE_WIRE.md §2 states 0x80+n/0x98/0x99/0x9a/0x9b; Rust spec encoder and Python helper implement them with boundary tests (23..2^32) and a real 65536-parent node compared to production. §4/§6 scope the 36-byte profile to parents and add a payload-link (raw/SHA-256) counterexample. 'five' -> 'seven'. WHY: PR review round 4 P2s. No vector or production encoding changed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…in the payload Records why plain decoding may normalize parent order and repeats: a node's identity is always the CID of its canonical form. Parents cannot cycle, so a repeated parent carries nothing; back-references belong in the payload as links traversal does not follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Existence, node type and acyclicity of parents are application invariants; traversals keep a visited set. A payload CID is hashed like a parent, so cycle-closing references are stored as non-content links (e.g. a symlink's target path) that parent-edge traversal does not follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removing a Cargo feature breaks manifests that list it, so the no-op alias may only go in a breaking release, and that promise is separate from the frozen MerkleNode API and bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Freezes
MerkleNode's serialized bytes.tests/merkle_vectors.json) pin the exact dag-cbor bytes and CID: no parents, one parent, several parents in shuffled order, duplicate parents, a nested payload.tests/merkle_conformance.rs) and Python (tests/test_content_addressable.py) both reproduce every vector. Python can't encode links, so it builds the node independently and checks byte parity, which makes it a second implementation rather than a copy.MerkleNodeis now part of the default surface.unstable-merklestays as a documented no-op alias, so existing manifests still resolve.unstable-storeis unchanged.No change to
ContentId, the canonical encoder or the dir-tree code. No version bump.Fixes #112
Test plan
payload) fails the Rust gate, and fails the Python gate even when the vectors are regenerated from the altered Rust. Reverted after.--all-features -D warnings, rustdoc, fmt.🤖 Generated with Claude Code