Skip to content

entropy: in-tree rANS codec, int4-rans256-g0 container format, offline tools - #671

Merged
JustVugg merged 6 commits into
JustVugg:devfrom
monotophic:entropy/rans-codec-e1
Jul 28, 2026
Merged

entropy: in-tree rANS codec, int4-rans256-g0 container format, offline tools#671
JustVugg merged 6 commits into
JustVugg:devfrom
monotophic:entropy/rans-codec-e1

Conversation

@monotophic

Copy link
Copy Markdown
Contributor

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic
(We/our = the joint work; me/my = @monotophic's own hardware and containers).

What this is

The first deliverable of the transport-layer build declared on #651
(follow-through on #594): a dependency-free C99 rANS codec (c/rans.h,
header-only), the int4-rans256-g0 container record format, and the
offline tools to mint, verify, and document it. No engine inference path
is touched
β€” colibri.o compiles byte-identical to base; everything here
is codec + tools + tests + docs, useful standalone and consumable by any
tier (the CUDA capacity tier included β€” one codec, every consumer, no
external dependency).

  • Codec: scalar + vectorized batch decode (AVX-512 F+BW and NEON arms),
    each carrying the i4-precedent runtime envelope β€” first-use round-trip
    selftest (with machine-checked renorm-band coverage) and env
    kill-switches. Vector arms are byte-identical to scalar by contract and
    by test β€” this is a codec: no tolerance, only identity.
  • Format: per-tensor records under original safetensors names (256
    round-robin-interleaved rANS streams, GPU/threadgroup-friendly), the
    shared table embedded per-shard in __metadata__, and a mandatory
    format stamp
    β€” entropy-coded sizes are data-dependent, so no
    byte-arithmetic inference exists; unstamped tensors can never be
    misread (refuse-rather-than-guess, same philosophy as formats: self-describing container stamp (TRUST-VERIFY-REFUSE) + FORMATS.md registry (#524)Β #529).
  • Tools: repack_rans.py (deterministic: two runs byte-identical;
    positive per-row geometry verification; crash-evident multi-shard
    manifest) and rans_verify.py (TRUST-VERIFY-REFUSE: a named refusal
    class for every corruption class, never a crash β€” fuzz-hardened).
  • Docs: docs/int4-rans256-g0.md is complete enough that a third-party
    reader AND writer can be built from the doc alone (independently
    demonstrated during review).

Measured

ratio / throughput
Real-corpus repack (2 shards, 5.4 GB, GLM-5.2 int4) 0.7305 (27.0% smaller incl. framing); full-corpus census anchor 0.763
Decode, Zen 5 AVX-512 (32T, pure C) 20.2 GB/s nibble-out (10.1 GB/s packed), 3.0Γ— scalar
Decode, M-series NEON (12T, pure C) 5.0 GB/s nibble-out (2.5 GB/s packed), 1.5Γ— scalar
Decode, Metal (prototype, prior work) 24.3 GB/s single-dispatch warm median
Encoder reproduces the proven prototype bitstream byte-for-byte (offsets + payload)

Capstone matrix

requirement decisive evidence
engine untouched colibri.o byte-identical base-vs-branch; diff = new files + Makefile/test wiring only
lossless, always round-trip property suite (random/adversarial/real tensors) + 4,907-mutant structured fuzz under ASan+UBSan: zero memory errors, zero arm divergence
vector = scalar, bit-exact byte-identity across arms on every fuzz-accepted record + real chunks, on both silicons
refuse, never guess named-refusal battery (25+ classes incl. u64-wraparound, decompression-bomb bounds, hostile headers) with C/Python refusal parity as a tested property
deterministic containers two-run byte-identity + stable-sort table construction + cross-implementation (C vs pure-Python) byte-identity
third-party consumable reference parser + decoder built from the docs alone during review, decoding real records byte-exact
Review + hardening detail

Built under a two-reviewer gate (blind validator + deep audit, independent
harnesses). The hardening round closed everything found: non-wrapping
header validation + amplification bounds (E_OVERSIZE), corrected encoder
scratch bound (+E_SCRATCH), E_SYMBOL_UNCODABLE pre-scan, never-crash
verifier (hostile-header suite: zero tracebacks), positive 2-D geometry
verification (g64/g128 refused by name β€” this PR scopes v1 to per-row int4
deliberately), E_NSTREAMS/E_UNALIGNED guards, big-endian #error,
crash-evident repack manifest. The fuzzer ships as make fuzz-rans
(seeded, sanitizer-built, non-gating). Suite: make check +227-test Python
battery; gcc-13 -Wall -Wextra -Wpedantic -Wshadow clean; the AVX-512
arm's first silicon run passed the full suite with the envelope exercised
both ways.

Scope notes: v1 targets per-row int4 expert tensors (the census's 0.763
container class); g64-class and scale-array coding are documented future
rounds with their own (weaker) payoff cases. Engine integration (loader +
CPU streaming decode, then Metal batched decode) follows as separate PRs β€”
this one is deliberately inert: format + codec + tools, reviewable and
usable on their own.

Durable vs current-state: format, codec, envelope, and refusal semantics
are durable; throughput figures are calibrations at (Zen 5 Strix Halo /
M5 Max, 2026-07-28, dev fa599e0 base) and the ratio at (GLM-5.2 int4
per-row container, 2-shard sample vs 372 GB census).

Dependency-free C99 single header (same shape as st.h/quant.h: all-static,
tests include it directly), three layers:

- scalar stream codec: ryg_rans-style 32-bit-state byte-renormalized
  encode/decode over the 16-nibble alphabet, ported unchanged from the
  measured prototype round, plus a checked decode that enforces the
  invariants every genuine encoder output satisfies (initial state in
  [L,256L), exact byte consumption, final state == L) so validators can
  refuse corruption without ground-truth bytes;

- chunk record: n_symbols/packed_bytes/stream_offsets[257] header, derived
  round16 padding, 256 round-robin-interleaved streams per tensor.
  TRUST-VERIFY-REFUSE reader: every malformation class gets its own named
  error (truncation, count mismatch, offset malformations, short streams,
  nonzero padding, trailing bytes), no partial acceptance;

- batched decode arms: scalar (branchy, mirrors the reference), scalar_bf
  (closed-form renorm -- the SIMD algebra kept testable on any host), NEON
  (16 streams/group, early per-lane loads, vqtbl freq/start lookups, fused
  vuzp repack; ~1.15x scalar_bf single-thread on an M-series host, and the
  G=8 variant that measured 0.88x is why the width is 16), AVX-512 F+BW
  (16 lanes, one vpermd per table lookup, vpmovqb packed store; ported from
  the prototype kernel measured at 8.7 GB/s batched on Zen 5).

Vector arms are byte-identical to scalar by contract -- this is a codec,
there is no tolerance -- and each carries the quant.h-style envelope:
compile-time ISA gate, first-use round-trip selftest that disables a
failing arm loudly, env kill-switch (RANS_NEON=0 / RANS_AVX512=0), and
RANS_PATH=<arm> forcing that refuses rather than silently downgrades.
The selftest table mixes freq=1 and freq=3 rare symbols deliberately:
power-of-two frequencies keep floor(log2 x) on a rigid lattice that never
visits some multi-byte renorm bands (measured directly -- a sabotaged
renorm threshold passed every comfortable-table test), so the off-lattice
f=3 group is what makes the selftest actually bite.
repack_rans.py mints the entropy tier from per-row int4 expert shards:
corpus-wide header index (a tensor and its .qs sidecar can live in
different shards), ONE global table from the pooled nibble histogram
stamped byte-identical into every output shard (decode stays shard-local),
every record round-trip-verified byte-exact BEFORE its shard is written,
and deterministic output (sorted orders, sort_keys stamps, no timestamps
-- two runs diff clean). Writer-side geometry guard mirrors the fp8 tool's
discipline: a tensor at the per-group-64 byte signature (weight/scale
ratio exactly 32) or without a confirmable per-row .qs is refused by name,
never silently coded under this format's identity.

rans_verify.py is the TRUST-VERIFY-REFUSE validator: stamp layer (the
colibri.fmt stamp is MANDATORY here -- entropy-coded sizes are
data-dependent, no byte-arithmetic inference exists, so the stamp is the
only dispatch signal, not a cross-check), table layer (JSON shape, freq
sum, prefix start, slot banding, crc32), record framing, per-stream
decode invariants, and a deterministic re-encode pin. One named refusal
class per corruption; exit 0 only on full trust.

rans_format.py is the shared reference module: table construction
(largest-remainder quantization, unchanged from the measured prototype),
record build/parse, minimal deterministic safetensors i/o, and a
pure-Python codec fallback.  builds tools/librans_c.* (a thin
exported-symbol bridge over rans.h, same optional-accelerator shape as
tools/libiq3): with it the tools use the C codec, without it they emit
identical bytes far more slowly -- the e2e test pins the two
implementations byte-equal.
test_rans.c (wired into TEST_BINS): stream round-trip property suite over
random and adversarial inputs (all-zero, all-max, single-symbol-freq=M,
15-symbol boundary, empty/odd/edge lengths, low-resolution and rare-symbol
tables), checked-decode refusal semantics including an enumerated
single-bit-corruption sweep (a corruption that silently PASSes the checked
decode is a verifier hole, so it is asserted impossible, not sampled),
record framing round trip at the format's real N=256 plus small-N shapes,
the full named-refusal battery, and the batched-arm identity sweep: every
compiled arm (scalar, scalar_bf, NEON here; AVX-512 on x86 builds) must be
BYTE-identical to the packed reference on the whole suite. The rare-symbol
case exists because a deliberately sabotaged renorm threshold passed every
other case: power-of-two-frequency tables keep the decoder's state off the
multi-byte-refill bands entirely (measured), so the f=3 off-lattice group
is what makes this suite able to bite. Envelope semantics are asserted
too: kill-switches drop the vector arms from selection, and a forced
unavailable arm is an error, never a silent downgrade.

test_rans_repack.py (unittest, skips without numpy): synthetic per-row
int4 fixtures with a cross-shard .qs sidecar; end-to-end byte-exact round
trip through real shard files; .qs raw pass-through; MANDATORY-stamp and
per-shard-table metadata shape; writer determinism (two runs diff clean,
AND a forced pure-Python run emits bytes identical to the C-codec run);
the verifier's corruption battery (payload flip, count mismatch, offset
break, truncation, dirty padding, dropped stamp, dropped table, wrong
table crc, freq-sum break, dangling stamp -- each refused by name); and
the writer-side geometry refusals (g64 signature, missing scales, empty
selection).
…t claimed)

The complete wire contract a third-party consumer needs: safetensors
container shape (original tensor names, U8 record blobs, raw .qs
sidecars), the chunk record byte layout with derived round16 padding, the
256-stream round-robin interleave and why it makes wide decode
output-coalesced, the per-stream codec including the verifiable
encoder-output invariants, and the per-shard table-in-metadata blob with
its crc field and generation id.

The load-bearing section is the MANDATORY stamp: unlike every existing
format, entropy-coded byte counts are data-dependent, so no
byte-arithmetic inference can identify this format -- the colibri.fmt
stamp is the only dispatch signal, and a future engine read path must gate
on it BEFORE the existing size-formula inference, which stays untouched.
Scope is per-row int4 v1 (the per-group-64 class is excluded with its
rationale), and the registry row proposes the NAME only: the numeric fmt
ordinal is deliberately left for the maintainer to assign.
…er bound, never-crash validator

Review findings (one blocker, four MAJOR): the codec core survived a
4,907-mutant ASan/UBSan fuzz with zero memory errors and zero arm
divergence, but the untrusted-input edges around it did not hold. All
fixes, each with its regression pinned:

- parse hardening: the packed_bytes check is now non-wrapping
  (n/2 + (n&1) β€” the additive ceil form accepted n_symbols=UINT64_MAX with
  packed_bytes=0), and an amplification bound refuses any header claiming
  more symbols than payload_len*8*M_max could encode under ANY admissible
  table (E_OVERSIZE) β€” the decompression-bomb surface E2's loader would
  have inherited, refused before anything sizes buffers from n_symbols.
  C and Python refuse identical bytes with identical classes, and that
  parity is now a TESTED property (same-bytes battery through both
  implementations), not a documented intention.

- encoder bound: the old per-stream scratch rule (n + n/2 + 64) was
  arithmetically false for freq=1 symbols at scale_bits >= 13 (a symbol
  costs up to scale_bits bits), so a legitimate rare-symbol-heavy tensor
  refused as out-of-memory. Correct bound (ceil(n*scale_bits/8)+4+slack),
  and bound exhaustion is now E_SCRATCH β€” a logic failure, never conflated
  with the allocator. Bulk-freq=1 input round-trips at scale_bits 13/14/15.

- named encode refusals: input containing a value > 15 or a symbol with
  table frequency zero refuses as E_SYMBOL_UNCODABLE via a pre-scan,
  instead of burning the scratch buffer into a misdiagnosed E_NOMEM; the
  stream primitive masks to the nibble alphabet so no input bytes can index
  past freq[16] (ASan-verified).

- rans_verify.py's "never crashes" is now enforced, not promised: the
  shard header shape is validated by name (object-ness, entry shape,
  data_offsets bounds against the file, str->str metadata), record-size
  allocations refuse as E_NOMEM instead of raising MemoryError, and
  per-tensor/per-shard catch-alls convert anything unexpected into a named
  E_INTERNAL refusal. The review round's six traceback classes all print
  REFUSE lines now.

- test vacuum: make test-python builds the ctypes bridge first, the e2e
  C-vs-Python byte-identity pin skips LOUDLY if the bridge is somehow
  absent, and a bridge-presence assertion pins that the default run
  actually used the C codec.

- geometry guard exactness: 2-D weights get positive per-row verification
  from the shape fields; flattened tensors at ratio 64 β€” exactly the
  per-group-128 signature, byte-indistinguishable from per-row I=128 β€”
  refuse as E_GEOMETRY_AMBIGUOUS instead of being silently stamped with
  geometry the ratio cannot prove.

- n_streams is validated in every public entry (E_NSTREAMS; the ctypes
  bridge pins the format's 256) β€” no division by zero, and the generic
  decode path can no longer return RANS_OK with untouched output. Record
  buffers must be 4-byte aligned (E_UNALIGNED) and the offsets table is
  accessed via memcpy on the parse/write side; the little-endian
  precondition is a compile-time #error and documented.

- quantize_freq: stable argsorts (exact fractional ties now break by
  symbol index on every host β€” contract 4's cross-host clause) and a
  provable-termination precondition (m >= present symbols, else ValueError).

- multi-shard repack is crash-evident: a non-empty output directory
  refuses without --force, and repack-manifest.json is written LAST as the
  completion marker β€” an interrupted set can no longer masquerade as done.

- the selftest's renorm-band coverage is machine-checked (the fixture
  fails the arm if multi-byte refills stop occurring) and the suite gained
  the same assertion β€” the one load-bearing claim that was previously an
  author assertion. The review fuzzer is adopted as tests/fuzz_rans.c
  (make fuzz-rans, ASan+UBSan, seeded/bounded; not a test gate).

- docs: the encoder renorm emission bound (x_max formula) makes a
  third-party WRITER doc-buildable; the >=4-bytes-per-stream validity rule,
  the amplification bound, and header-integer endianness are stated.

Sabotage meta-check re-run on the final tree: a t15 off-by-one in the NEON
arm still fails both the identity suite and the first-use selftest.
Engine object still byte-identical to base.
@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic
(We/our = the joint work; me/my = @monotophic's own hardware and containers).

@ZacharyZcR β€” the in-tree record schema is concrete: this PR. Your
requirements list from the 6Γ—5090 work, mapped against it as shipped:

your requirement status in this PR
independently decodable tensor/expert records (aggregate archives hit a CUDA boundary) met by design β€” per-tensor records under original safetensors names, each self-contained (own stream offsets; shard-local table). No aggregate archive exists in this shape.
per-record original size, encoded size, codec bound, shape, truncation validation met β€” the verifier enforces all of it as named refusal classes (non-wrapping count checks, an amplification bound, per-stream truncation, table CRC), fuzz-hardened, with C/Python refusal parity as a tested property.
CPU decoder for the streamed transport case met β€” in-tree, dependency-free; scalar + NEON + AVX-512 (10.1 GB/s packed measured on Zen 5, 32T).
optional pointer-batch GPU decoder for compressed-VRAM format-ready by design β€” the 256-stream round-robin interleave exists precisely for descriptor-batch GPU dispatch (24.3 GB/s measured on the Metal prototype of this exact construction). A CUDA port is close to line-for-line and needs no external codec.
exact model/traversal identity incl. placement order order-identity dissolves under name-addressed random access β€” no consumer needs traversal order anymore, which we'd argue is the point of the portable shape. Model identity: names + shapes + the mandatory per-tensor format stamp. Container-level identity (digest/stamp of the whole artifact) is deliberately NOT duplicated here β€” that is #529's machinery, and when it lands it applies to these shards like any others.
alignment permitting direct reads without a second staging copy workable today with the same aligned-window read your sidecar loader uses (one read, offset delta, no second copy); records are 16-byte aligned internally. Pre-registered trade, decided by your data: if your A/B shows the aligned-window pattern costs materially versus true 4 KiB tensor alignment, we add an --align option to the repack tool β€” a shard-layout change only, the record wire format does not move.
fail-fast, never silently substituting a missing tier shared philosophy β€” the stamp is the only dispatch signal (entropy sizes admit no byte-arithmetic inference), so unstamped or malformed tensors refuse rather than guess. Tier-substitution policy lives in the consumers; ours will match yours.

Your validation offer is exactly what we'd like this PR to carry into
review: packing, complete-record verification, direct loading, and the
6Γ—5090 A/B against the 110 GB sidecar β€” run against v1 as it stands. If it
surfaces a real defect, that's what review is for; the alignment question
above is the one open trade and your A/B is its designated decider.

(Throughput figures are calibrations at their stated hosts/dates β€”
E1_SILICON_RESULTS in the PR evidence; ratio 0.7305 on a 2-shard real-corpus
sample vs the 0.763 full-corpus census anchor.)

@ZacharyZcR

Copy link
Copy Markdown
Contributor

@monotophic Thanks for mapping the requirements to concrete code. I reviewed the actual v1 scope and want to separate what the 6x5090 host can validate now from what needs the consumer PR.

What is testable in this PR:

  • deterministic repack and complete-record verification on the real GLM shards;
  • corruption/truncation refusal and C/Python parity;
  • record-size distribution and the real cost of aligned-window direct reads;
  • whether 16-byte record alignment is sufficient in practice or a 4 KiB --align layout materially improves direct-read throughput.

What is not yet testable as a capacity-tier A/B:

  • this PR has no CUDA pointer-batch decoder or Colibri loader/dispatch path, so there is no rANS-backed GPU tier to compare with cuda: add experimental lossless compressed expert tierΒ #651's 110 GB DietGPU sidecar;
  • v1 deliberately supports per-row int4 and refuses g64, while current Colibri conversion defaults and the newer public GLM container are g64. The old per-row checkpoint can exercise v1, but that result would not establish coverage for the current default container;
  • fail-fast tier substitution remains a consumer property, not something this inert format PR can demonstrate;
  • until formats: self-describing container stamp (TRUST-VERIFY-REFUSE) + FORMATS.md registry (#524)Β #529's container identity lands, names + shapes prevent traversal coupling but do not by themselves prevent attaching same-shaped records from the wrong checkpoint. The first consumer still needs an external whole-model digest/manifest check.

So my review plan is:

  1. validate the phase-1 format/tooling claims independently on the per-row GLM source;
  2. use the resulting record offsets/sizes to settle 16-byte vs 4 KiB alignment;
  3. reserve the 6x5090 throughput/capacity comparison for the CUDA consumer PR, where identical placement, routed replay, decode-time CPU/GPU windows, and fail-fast behavior can actually be measured.

That does not block a deliberately inert codec/format PR from standing on its own. It just keeps β€œformat-ready for GPU dispatch” distinct from β€œGPU capacity tier validated.” I will post the packing/verification/alignment results here when that host run is complete.

@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic
(We/our = the joint work; me/my = @monotophic's own hardware and containers).

@ZacharyZcR β€” this is the review split we wanted; the
testable-now list matches what the PR claims. Three
responses on the three substantive points:

g64 coverage β€” deliberate scope, chosen on census numbers. The
744G-nibble census measured per-row int4 at 0.763 corpus-wide but
g64-class at ~0.890 β€” better quantizers make less-compressible codes, and
on g64 the scale arrays are 12.3% of the stream (vs 0.13% per-row), so a
worthwhile g64 round is really a different design that adds scale-array
coding. v1 targets the container class where the payoff is proven; the
PR's scope notes acknowledge that as does your framing. The g64 extension
is deferred work, to be built when its (weaker) case is worth
its complexity.

The wrong-checkpoint identity gap β€” agreed, and here's where each layer
lands.
Container identity proper is #529's machinery (open, CI-green;
when it lands these shards get stamped like any others). Interim and
consumer-side: the repack tool already emits a per-run manifest
(crash-evidence, from the hardening round) β€” we're growing it with
optional per-tensor content digests as a tool-layer commit on this PR
(record wire format untouched; includes a retro-manifest mode so
already-minted shards can be covered by hashing in place), and the first
consumer PR ships the whole-model manifest check at load. So: #529 =
identity of the artifact; manifest digest = the external byte-level
verification you're pointing at, each with a concrete home.

Alignment β€” your experiment remains the designated decider, as
pre-registered above: if the record offsets/sizes show aligned-window
reads paying materially vs a true 4 KiB layout, --align lands in the
repack tool, wire format unmoved either way.

Looking forward to the per-row host run β€” the phase-1 validation you've
scoped is the strongest external evidence this PR could carry, and the
capacity-tier A/B waiting for the consumer PR is the right sequencing on
our side of the ladder too (the loader/dispatch consumer is in build now).

…heck

Per-record validation proves a record is A well-formed artifact of this
format; it cannot prove it is THE record a given mint run produced β€” a
well-formed record swapped in from another checkpoint passes every
per-record check (the JustVugg#671 review point). Close that at the build layer:

- repack_rans.py records, per output shard, a `records` map β€” original
  tensor name -> sha256 of the emitted record bytes exactly as written β€”
  hashed inline while the bytes are already in hand (no second read). The
  record wire format is untouched: the manifest is a sidecar file, still
  deterministic (sorted keys, no timestamps), still the completion marker.

- `--manifest-only <dir>` retro-generates the manifest for already-minted
  directories by hashing shards in place, no re-encoding. It preserves
  every field of an existing manifest and only recomputes the digest maps,
  so retro output is byte-identical to mint output for the same shards
  (tested byte-for-byte). It lives in the WRITER deliberately: the
  manifest is the writer's completion/provenance artifact, and
  rans_verify.py stays side-effect-free β€” a tool pointed at a stranger's
  download must never write into it.

- rans_verify.py checks each record's bytes against its digest whenever a
  manifest with digests sits next to the shards, BEFORE record decode
  (the swap case is exactly what the later checks are blind to). Named
  refusals: E_DIGEST_MISMATCH (bytes differ from the mint run),
  E_DIGEST_MISSING (digests exist but not for this shard/tensor β€” a
  record the mint never produced), E_MANIFEST_MALFORMED (a manifest that
  exists but cannot be parsed is evidence of tampering, refused rather
  than treated as absent). No manifest, or a digest-less manifest from an
  older mint, is note-and-proceed β€” never an error. Never-crash holds.

- tests: digest round-trip green with "manifest digests checked" pinned;
  tamper bite (one flipped payload byte in the shard file, manifest
  untouched -> E_DIGEST_MISMATCH); retro equivalence (byte-identical
  manifest over a minted dir; from-scratch retro reproduces the digest
  map); backward compat (stripped digests -> note + green); corrupt
  manifest -> E_MANIFEST_MALFORMED without traceback; foreign shard ->
  E_DIGEST_MISSING. The per-record corruption battery now drops the
  manifest first β€” that layer must hold even when an attacker removes the
  whole-artifact evidence. Mint determinism (manifest included) already
  pinned by the existing two-run byte compare.

Build integrity (these bytes came from that mint run) vs container
identity (the stamp/registry lineage) is documented in
docs/int4-rans256-g0.md; the engine-side load check ships with the
consumer PR.

Whole-file layer (micro-addendum, same round): each manifest shard entry
also carries `sha256` β€” the complete .safetensors file bytes, hashed while
streaming the write before the atomic rename (retro mode hashes files in
place; retro-over-minted stays byte-identical to mint). The file hash
subsumes what the record map cannot see β€” .qs sidecars, headers, padding β€”
closing the scale-swap gap; the record map stays for granular diagnosis.
Verify checks the file hash FIRST (cheapest whole-artifact gate,
E_SHARD_DIGEST_MISMATCH), then the per-record layer, continuing past a
file-level mismatch so record digests localize in-record damage. Tests:
.qs-region tamper bites as E_SHARD_DIGEST_MISMATCH with NO record-level
refusal (the exact gap, demonstrated), record tamper trips both layers,
retro identity and mint determinism re-proven, degraded manifests
(no digests at all / file-hash-only) note-and-proceed.

Validator delta-3 fix (same commit): manifest entry shapes are now
type-validated unconditionally BEFORE the digest-evidence scan β€” an entry
whose only digest fields are malformed-typed (sha256 as a number, records
as a list, an entry that is not an object) previously zeroed the evidence
scan and was silently classed as a digest-less older mint instead of
refusing. Wrong-typed digest fields are malformation regardless of whether
valid evidence remains elsewhere; both validator corpses are in the shipped
battery (E_MANIFEST_MALFORMED, no TRUST line, zero tracebacks). Retro
--manifest-only also warns on stderr when `source` provenance is
unknowable, so the loss is visible in output, not just by field absence.
@monotophic

Copy link
Copy Markdown
Contributor Author

Authored by Fable 5 in Claude Code, analysis in partnership with @monotophic
(We/our = the joint work; me/my = @monotophic's own hardware and containers).

Pushed cc4a589 β€” the manifest-digest commit promised above, landing the
interim whole-artifact verification @ZacharyZcR's review pointed at. Record
wire format untouched; the commit is tools/tests/docs only (engine object
still byte-identical to base).

What it adds:

  • repack-manifest.json now carries two digest layers: a whole-file
    sha256 per shard (covers .qs sidecars, headers, padding β€” the parts no
    per-record check can see) and a per-tensor sha256 of each record's bytes
    (localizes damage to a tensor). Hashed while streaming the write β€” no
    second read.
  • rans_verify.py checks both layers when present: file gate first
    (E_SHARD_DIGEST_MISMATCH), then per-record
    (E_DIGEST_MISMATCH/E_DIGEST_MISSING). Manifest absent or digest-less
    β†’ note-and-proceed (older mints stay loadable); manifest present but
    damaged β†’ refuse (E_MANIFEST_MALFORMED) β€” a damaged integrity artifact
    is evidence, not noise. Manifest deletion remains the inherent sidecar
    gap; that's the consumer/identity layer's job (formats: self-describing container stamp (TRUST-VERIFY-REFUSE) + FORMATS.md registry (#524)Β #529 lineage + the
    loader check arriving with the consumer PR).
  • --manifest-only <dir>: retro-manifests already-minted output by
    hashing in place β€” no re-encode. Retro over a minted dir reproduces the
    mint-time manifest byte-for-byte (tested). If your host run has already
    repacked, one command covers those shards with digests after the fact.

Verification: tamper bites demonstrated for both layers (including a
.qs-region flip that trips only the file gate β€” the scale-swap case,
asserted with zero record-level noise); two-run mint determinism includes
the manifest; retro-vs-mint byte identity; full suite green. Independent
blind re-validation covered the same claims with its own hashing and
header parser before this push.

(Digest fields are sidecar-file additions β€” nothing about record layout,
table serialization, or stamps moved; v1 as frozen.)

@JustVugg
JustVugg merged commit a3a5a75 into JustVugg:dev Jul 28, 2026
10 checks passed
@monotophic
monotophic deleted the entropy/rans-codec-e1 branch July 28, 2026 21:02
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.

3 participants