PathRegistration.prNarHash and PathInfo.piNarHash carry "a valid nix-formatted hash" as bare Text through registration and the SQLite round-trip; producer discipline (every writer formats via formatNixHash) holds the invariant the type does not state. Since the decoded-comparison change, readers decode-first with a text fallback, but the proof still does not travel with the value.
Typing the field as a decoded hash (or a spelling-pinned newtype) makes registration and the push gate total by construction and removes the fallback. It interacts with widening parseNixHash beyond sha256:nix-base32 for foreign caches (#27) - the newtype should land with or after that widening so the DB read path has one story for legacy rows.
From the #85 audit (store and cache subsystems).
PathRegistration.prNarHashandPathInfo.piNarHashcarry "a valid nix-formatted hash" as bareTextthrough registration and the SQLite round-trip; producer discipline (every writer formats viaformatNixHash) holds the invariant the type does not state. Since the decoded-comparison change, readers decode-first with a text fallback, but the proof still does not travel with the value.Typing the field as a decoded hash (or a spelling-pinned newtype) makes registration and the push gate total by construction and removes the fallback. It interacts with widening
parseNixHashbeyond sha256:nix-base32 for foreign caches (#27) - the newtype should land with or after that widening so the DB read path has one story for legacy rows.From the #85 audit (store and cache subsystems).