v0.21.0 Phase 2 Hash-Foundation Review
Result
Phase 2 is complete. std/hash now owns one opaque public state, one Hash capability, one private streaming algorithm, and coherent implementations for every adopted scalar, text, slice, and Vec surface. Target entropy remains a separate standard-internal responsibility. No table, Map, Set, public final hash, custom hasher, or compiler-known hashing behavior entered this phase.
The review found and resolved two design issues during implementation. First, package-only HashState lifecycle methods were initially placed beside their bodies. The source contract model correctly rejected non-private visibility outside index.nct; construction, restart, and finalization contracts now live with the opaque type owner while state.nct contains private bodies only. Second, an early generic raw-scalar helper relied on callers to pass only padding-free built-ins. It was replaced by type-specific scalar helpers in scalars.nct, so that precondition is not an extensible internal contract.
No unresolved Phase 2 correctness or responsibility-boundary finding remains.
State and Algorithm Authority
std/hash/index.nctis the sole declaration authority forHash,HashState, public byte contribution, and package-only lifecycle access.state.nctalone owns seed retention, buffered bytes, algorithm lanes, compression, and finalization. Consumers cannot initialize fields or reproduce the algorithm.- A
HashStatetemplate receives entropy once.restartcreates independent state with the same hidden seed, allowing one Map to compare all keys coherently across lookup and rehash without requesting fresh entropy. - The private implementation buffers eight bytes and uses add/XOR/rotate compression and a separate finalization. No algorithm constant or output is public or normative.
std/internal/hashowns only target seed acquisition. It cannot inspect, construct, restart, or finalizeHashState;std/hashcannot observe syscall details.
Value Encoding and Coherence
booland every current built-in integer contribute their exact initialized fixed-width bytes. Each helper has an exact scalar type, avoiding narrowing conversions and an unsafe generic promise about padding.strcontributes its length and UTF-8 bytes.Stringdelegates to the same borrowed text path, so equal owned and borrowed text use the same encoding.[T]contributes its length and each element throughT impl Hash.Vec<T>delegates to that borrowed view, so equal owning and borrowed sequences use the same component boundaries.- The
Hashprerequisite requires(&Self == &Self): bool. Existing prerequisite expansion supplies equality evidence for generic slices and Vec values fromT impl Hash; hashing does not duplicate an equality-selection rule. - Map and Set remain deliberately non-hashable in v0.21.0.
Ownership, Failure, and Allocation
- HashState contains only fixed-width scalar fields. Restart and finalization use stack values and do not allocate or expose borrows into mutable state.
- Scalar hashing forms readonly byte views over initialized compiler built-ins. Text and sequence hashing use existing readonly views; none transfers or mutates the hashed value.
- Every reachable hashing body calls only fixed-width arithmetic, readonly projection, iteration,
or another
Hashimplementation. It contains no allocator, error, I/O, or target call. - Entropy acquisition occurs only when a package-internal template is created and terminates on failure, preserving the public construction failure policy.
Visibility and Dependency Review
- Public users can construct neither a state nor a final hash. They can only implement
Hashand contribute bytes to a state supplied by the standard library. - Package-only lifecycle declarations remain associated with
HashState; moving them to an internal module would require exposing representation or introducing a dependency cycle. - No new exception was added to the standard root-visibility audit. Implementation sources still cannot declare non-private visibility.
- The reviewed dependency graph records
hashdependencies on onlyinternal/hash,internal/ptr,num,ptr,string, andvec. The entropy module continues to depend only on the Darwin OS adapter and pointer API.
Native Qualification
Four authored standard tests execute through checking, target closure, MIR, MachineProgram, ARM64, Mach-O, and the native test harness. They cover equal primitive/text contributions, streaming write boundaries, seed separation, nested component boundaries, target entropy, and deterministic restart from one hidden seed.
Evidence
cargo test -p nocter-discovery authored_standard_library_is_one_discoverable_declaration_unitcargo test -p nocter-native-session standard_hash_contract_crosses_native_testscargo test --workspace --quietcargo fmt --all --checknode docs/build-docs.jsgit diff --check
All commands passed on 2026-08-30. The full workspace test retained one existing ignored test and reported no failure.