docs: describe the on-disk shape of an emitted NWSync tree #77

Merged
archvillainette merged 1 commits from docs-nwsync-blob-format into main 2026-07-31 11:00:49 +00:00
Owner

Documents what nwsync emit --out DIR actually produces, so a zone can be checked by hand.

The trap this removes: a blob's filename is the SHA-1 of the resource's original bytes, but the file on disk is NWCompressedBuffer framing — a 24-byte NSYC header then a zstd frame. sha1sum <blob> therefore never matches the name it is sitting under. The doc records the recipe that does match:

tail -c +25 <blob> | zstd -dc | sha1sum

Also notes the tree layout, that the uncompressed length is a little-endian uint32 at offset 12, and the rough 4:1 compression ratio on hak content.

Verified two ways: against a real emit of a 250 MB hak (2296 blobs, 59 MB on disk against 249 MB of resources), and against internal/nwsync/compressedbuf.go, where the header is written as []uint32{blobMagic, blobVersion, algorithmZstd, uint32(len(data)), zstdHeaderVer, zstdDictionary} — confirming field 3 at offset 12.

Docs only, no behaviour change. Falls out of the investigation in #76; that fix is not in this PR.

🤖 Generated with Claude Code

Documents what `nwsync emit --out DIR` actually produces, so a zone can be checked by hand. The trap this removes: a blob's filename is the SHA-1 of the resource's *original* bytes, but the file on disk is NWCompressedBuffer framing — a 24-byte `NSYC` header then a zstd frame. `sha1sum <blob>` therefore never matches the name it is sitting under. The doc records the recipe that does match: ``` tail -c +25 <blob> | zstd -dc | sha1sum ``` Also notes the tree layout, that the uncompressed length is a little-endian `uint32` at offset 12, and the rough 4:1 compression ratio on hak content. Verified two ways: against a real emit of a 250 MB hak (2296 blobs, 59 MB on disk against 249 MB of resources), and against `internal/nwsync/compressedbuf.go`, where the header is written as `[]uint32{blobMagic, blobVersion, algorithmZstd, uint32(len(data)), zstdHeaderVer, zstdDictionary}` — confirming field 3 at offset 12. Docs only, no behaviour change. Falls out of the investigation in #76; that fix is not in this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
archvillainette added 1 commit 2026-07-31 10:51:26 +00:00
Blob filenames are the SHA-1 of a resource's original bytes, but the file on
disk is NWCompressedBuffer framing: a 24-byte NSYC header then a zstd frame.
Hashing the file directly is the first thing anyone tries when checking a zone
by hand, and it never matches. Record the layout and the one-line recipe that
does match, plus where the uncompressed length lives in the header.

Verified against a real emit and against internal/nwsync/compressedbuf.go.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
xtul approved these changes 2026-07-31 10:55:07 +00:00
archvillainette merged commit 7437653f14 into main 2026-07-31 11:00:49 +00:00
archvillainette deleted branch docs-nwsync-blob-format 2026-07-31 11:00:50 +00:00
Sign in to join this conversation.