core/tests/fixtures/crdt/_generate.py
Shay 92ea9ee6f5 feat(vault): lock Delta-CRDT reference contract (ADR-0180 -> Accepted, gate G1)
Establishes the canonical Delta-CRDT reference contract so a future native
(Rust/Zig) backend is gate-G1-eligible under ADR-0196 — the ZC-0 'contract
pinning' slice. No Zig code; ZC-1+ remains gated at G2.

- vault/crdt.py: canonical Python reference (ArenaEntry, Delta, LocalArena,
  merge_kernel, canonical_bytes, delta_hash). Pure content law — content-
  addressed by IEEE-754 bits then provenance; no normalization, no versor
  closure, no global Vault writes.
- ZC-0 contract tests (semilattice C-1..C-5; content ordering / signed-zero /
  NaN bit-addressing; C-7 no-global-write) — all failable (mutation-checked:
  no-dedup breaks C3/C5, arrival-order breaks C1).
- Golden fixture corpus (tests/fixtures/crdt/) regenerated deterministically
  from the reference; single source of truth also emits the Rust expected hex.
- core-rs: Delta::canonical_bytes + test_crdt_hash_parity.rs proving Rust
  produces byte-identical canonical_bytes to the Python reference.
- ADR-0180 -> Accepted: locked contract, byte layout, obligation map, and the
  explicit boundary that no Zig is authorized.

Verification: ZC-0 21 passed, Rust arena+parity 16 passed, architectural
invariants 40 passed, smoke 67 passed. Serving frozen: 7/8 lane SHAs match;
the public_demo miss is a pre-existing wall-clock budget overrun (ADR-0099,
~46-48s > 30s) reproduced identically on clean main — environmental.
2026-05-31 16:25:21 -07:00

157 lines
5.6 KiB
Python

"""Regenerate tests/fixtures/crdt/merge_fixtures.json from the canonical
reference (vault/crdt.py). Run: uv run python tests/fixtures/crdt/_generate.py
The emitted JSON is the *golden* G1 fixture corpus (ADR-0180 / ADR-0196 gate
G1). Changing the canonical form in vault/crdt.py changes these hashes; the
contract tests pin them, so a golden diff is a reviewed, deliberate act.
Versor components use only exactly-f32-representable, exactly-JSON-representable
values (integers, signed zeros, halves) so the corpus round-trips with zero
float ambiguity. NaN / signed-zero *bit*-distinctness is exercised in-code in
test_crdt_content_ordering.py, not here.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parents[3]
sys.path.insert(0, str(_REPO_ROOT))
from vault.crdt import ( # noqa: E402 # pyright: ignore[reportMissingImports]
VERSOR_COMPONENTS,
ArenaEntry,
Delta,
canonical_bytes,
delta_hash,
merge_kernel,
)
_OUT = Path(__file__).resolve().parent / "merge_fixtures.json"
# Rust parity fixture lives under core-rs/tests/fixtures/ (a *subdir* of tests/,
# so cargo does not compile it as a standalone integration-test target).
_RUST_OUT = _REPO_ROOT / "core-rs" / "tests" / "fixtures" / "crdt_parity_expected.rs"
def versor(**components: float) -> list[float]:
"""Build a 32-float versor; unset indices default to 0.0."""
v = [0.0] * VERSOR_COMPONENTS
for idx, value in components.items():
v[int(idx.lstrip("c"))] = value
return v
def entry(versor_vals: list[float], provenance: bytes) -> ArenaEntry:
return ArenaEntry.of(versor_vals, provenance)
def encode_entry(e: ArenaEntry) -> dict:
return {"versor": list(e.versor), "provenance_hex": e.provenance.hex()}
def encode_delta_input(entries: list[ArenaEntry]) -> list[dict]:
return [encode_entry(e) for e in entries]
def build_cases() -> list[dict]:
cases: list[dict] = []
def add(name: str, description: str, delta_entry_lists: list[list[ArenaEntry]]):
deltas = [Delta.from_entries(es) for es in delta_entry_lists]
merged = merge_kernel(deltas)
cases.append(
{
"name": name,
"description": description,
"input_deltas": [encode_delta_input(es) for es in delta_entry_lists],
"expected_merged_entries": [encode_entry(e) for e in merged.entries],
"expected_canonical_bytes_hex": canonical_bytes(merged).hex(),
"expected_delta_hash": delta_hash(merged),
}
)
# 1 — single entry, single delta.
add(
"single_entry",
"One delta, one entry: identity of the canonical form.",
[[entry(versor(c0=1.0), b"a")]],
)
# 2 — duplicate byte-identical entries collapse (idempotence at entry level).
add(
"dedup_within_delta",
"Byte-identical entries collapse to one (join idempotence).",
[[entry(versor(c0=1.0), b"a"), entry(versor(c0=1.0), b"a")]],
)
# 3 — same versor, distinct provenance: BOTH retained (no over-dedup).
add(
"distinct_provenance_retained",
"Same versor under different provenance are distinct content.",
[[entry(versor(c5=2.0), b"left"), entry(versor(c5=2.0), b"right")]],
)
# 4 — three deltas merged; corpus pins the canonical (content-sorted) result.
add(
"three_delta_merge",
"Union of three deltas, content-sorted and deduped.",
[
[entry(versor(c1=3.0), b"z"), entry(versor(c0=1.0), b"a")],
[entry(versor(c2=2.0), b"m"), entry(versor(c0=1.0), b"a")],
[entry(versor(c10=5.0), b"q")],
],
)
# 5 — signed-zero is distinct content (+0.0 bits != -0.0 bits).
add(
"signed_zero_distinct",
"+0.0 and -0.0 have distinct bit patterns -> distinct entries.",
[[entry(versor(c0=0.0), b"p"), entry(versor(c0=-0.0), b"p")]],
)
return cases
def write_rust_fixtures(cases: list[dict]) -> None:
"""Emit the Rust-side expected canonical_bytes hex so core-rs/tests can
assert byte-parity without a JSON parser dependency. Python stays the single
source of truth."""
lines = [
"// @generated by tests/fixtures/crdt/_generate.py — DO NOT EDIT.",
"// Expected canonical_bytes hex per case (mirrors merge_fixtures.json):",
"// the Python-canonical Delta-CRDT G1 contract (ADR-0180 / ADR-0196)",
"// the Rust substrate must reproduce byte-for-byte.",
"// (include!d mid-module, so plain // comments — not //! — are required.)",
"",
"pub const EXPECTED_CANONICAL_BYTES_HEX: &[(&str, &str)] = &[",
]
for case in cases:
lines.append(
f' ("{case["name"]}", "{case["expected_canonical_bytes_hex"]}"),'
)
lines.append("];")
_RUST_OUT.parent.mkdir(parents=True, exist_ok=True)
_RUST_OUT.write_text("\n".join(lines) + "\n")
def main() -> None:
corpus = {
"_comment": (
"Golden Delta-CRDT fixture corpus (ADR-0180 / ADR-0196 gate G1). "
"Regenerate with: uv run python tests/fixtures/crdt/_generate.py"
),
"versor_components": VERSOR_COMPONENTS,
"cases": build_cases(),
}
_OUT.write_text(json.dumps(corpus, indent=2, sort_keys=False) + "\n")
write_rust_fixtures(corpus["cases"])
print(f"wrote {_OUT} ({len(corpus['cases'])} cases)")
print(f"wrote {_RUST_OUT}")
for case in corpus["cases"]:
print(f" {case['name']:30s} hash={case['expected_delta_hash'][:16]}")
if __name__ == "__main__":
main()