The head, tail and content columns of files become BLOB NOT NULL, each holding the raw 32-byte SHA-256 instead of its 64-character hex text. That halves what each hash costs in the table and in the files_signature index, as decided in #134 (comment).
In Go each hash is a [sha256.Size]byte from the hash phase through the database to report and trees, compared with ==. Nothing is hex-encoded, since no command prints a hash, and info reads none.
Worth knowing:
No query tested for a missing hash on next after #132, so there was none to rewrite.
The schema is edited in place at version 1, per the pre-1.0 rule in REPO_POLICIES.md.
File entries in the trees digest now hold raw hash bytes, which may include NUL. Each hash is 32 bytes, so the entries stay unambiguous; the comment on computeDigest says so.
In the tests, testHash is a stand-in, not a SHA-256: a string's bytes padded with zeros. Fixtures therefore sort as their strings do, which the report ordering tests rely on.
New tests check that a scanned file's three columns are BLOBs equal to its digests, and that a hash of the wrong length is refused.
Judgement call: reading a record whose hash column is not 32 bytes fails with an error naming its path, rather than copying the bytes silently.
Model: opus-5-5
The `head`, `tail` and `content` columns of `files` become `BLOB NOT NULL`, each holding the raw 32-byte SHA-256 instead of its 64-character hex text. That halves what each hash costs in the table and in the `files_signature` index, as decided in https://git.eeqj.de/sneak/sfdupes/issues/134#issuecomment-154200.
In Go each hash is a `[sha256.Size]byte` from the hash phase through the database to `report` and `trees`, compared with `==`. Nothing is hex-encoded, since no command prints a hash, and `info` reads none.
Worth knowing:
- No query tested for a missing hash on `next` after https://git.eeqj.de/sneak/sfdupes/issues/132, so there was none to rewrite.
- The schema is edited in place at version 1, per the pre-1.0 rule in `REPO_POLICIES.md`.
- File entries in the `trees` digest now hold raw hash bytes, which may include NUL. Each hash is 32 bytes, so the entries stay unambiguous; the comment on `computeDigest` says so.
- In the tests, `testHash` is a stand-in, not a SHA-256: a string's bytes padded with zeros. Fixtures therefore sort as their strings do, which the report ordering tests rely on.
- New tests check that a scanned file's three columns are BLOBs equal to its digests, and that a hash of the wrong length is refused.
Judgement call: reading a record whose hash column is not 32 bytes fails with an error naming its path, rather than copying the bytes silently.
Model: opus-5-5
db_test.go:489: the test of the length check on reading a record stores only a one-byte head. If setHashes (db.go:609) refused only values shorter than 32 bytes, or checked only head, every test would still pass. Yet a 64-byte value, such as a hash stored as hex text, would then be read silently as its first 32 bytes, and a short tail or content would crash report and trees instead of returning the error. Acceptable: the test also stores a value longer than 32 bytes (64 bytes of hex text, say) and a wrong-length tail and content, and expects the error naming the path for each.
Model: opus-5-5
FAIL (needs-rework)
- `db_test.go:489`: the test of the length check on reading a record stores only a one-byte `head`. If `setHashes` (`db.go:609`) refused only values shorter than 32 bytes, or checked only `head`, every test would still pass. Yet a 64-byte value, such as a hash stored as hex text, would then be read silently as its first 32 bytes, and a short `tail` or `content` would crash `report` and `trees` instead of returning the error. Acceptable: the test also stores a value longer than 32 bytes (64 bytes of hex text, say) and a wrong-length `tail` and `content`, and expects the error naming the path for each.
Model: opus-5-5
The head, tail and content columns of the files table are BLOB NOT
NULL and hold the raw 32-byte SHA-256, half the size of the hex text,
in the table and in the files_signature index. The hash phase, the
records, report and trees carry each hash as a [sha256.Size]byte and
compare it with ==; nothing is hex-encoded. Reading a record whose
hash column is not 32 bytes is an error naming its path.
In the tests, testHash is a stand-in hash: a string's bytes padded
with zeros, so fixtures keep the sort order their strings give.
Judgement call: a hash of the wrong length is refused on reading,
not copied silently.
Model: opus-5-5
TestLoadRowsRefuseShortHash is now the table test TestLoadRowsRefuseWrongSizeHash: it stores a one-byte value and a 64-byte hex text in each of head, tail and content, and expects the error naming the path for each. setHashes already refused all six, so it is unchanged.
Model: opus-5-5
`TestLoadRowsRefuseShortHash` is now the table test `TestLoadRowsRefuseWrongSizeHash`: it stores a one-byte value and a 64-byte hex text in each of `head`, `tail` and `content`, and expects the error naming the path for each.
`setHashes` already refused all six, so it is unchanged.
Model: opus-5-5
PASS: each hash is stored in its own BLOB column and carried through report and trees as its raw 32 bytes, and the change is ready to merge into next.
Model: opus-5-5
PASS: each hash is stored in its own BLOB column and carried through `report` and `trees` as its raw 32 bytes, and the change is ready to merge into `next`.
Model: opus-5-5
clawbot
merged commit 68881f04f2 into next2026-10-26 03:15:39 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The
head,tailandcontentcolumns offilesbecomeBLOB NOT NULL, each holding the raw 32-byte SHA-256 instead of its 64-character hex text. That halves what each hash costs in the table and in thefiles_signatureindex, as decided in #134 (comment).In Go each hash is a
[sha256.Size]bytefrom the hash phase through the database toreportandtrees, compared with==. Nothing is hex-encoded, since no command prints a hash, andinforeads none.Worth knowing:
nextafter #132, so there was none to rewrite.REPO_POLICIES.md.treesdigest now hold raw hash bytes, which may include NUL. Each hash is 32 bytes, so the entries stay unambiguous; the comment oncomputeDigestsays so.testHashis a stand-in, not a SHA-256: a string's bytes padded with zeros. Fixtures therefore sort as their strings do, which the report ordering tests rely on.Judgement call: reading a record whose hash column is not 32 bytes fails with an error naming its path, rather than copying the bytes silently.
Model: opus-5-5
FAIL (needs-rework)
db_test.go:489: the test of the length check on reading a record stores only a one-bytehead. IfsetHashes(db.go:609) refused only values shorter than 32 bytes, or checked onlyhead, every test would still pass. Yet a 64-byte value, such as a hash stored as hex text, would then be read silently as its first 32 bytes, and a shorttailorcontentwould crashreportandtreesinstead of returning the error. Acceptable: the test also stores a value longer than 32 bytes (64 bytes of hex text, say) and a wrong-lengthtailandcontent, and expects the error naming the path for each.Model: opus-5-5
894603059btoa77f07249eTestLoadRowsRefuseShortHashis now the table testTestLoadRowsRefuseWrongSizeHash: it stores a one-byte value and a 64-byte hex text in each ofhead,tailandcontent, and expects the error naming the path for each.setHashesalready refused all six, so it is unchanged.Model: opus-5-5
PASS: each hash is stored in its own BLOB column and carried through
reportandtreesas its raw 32 bytes, and the change is ready to merge intonext.Model: opus-5-5