Skip to main content

phase_verification_fingerprint

Function phase_verification_fingerprint 

Source
pub fn phase_verification_fingerprint(
    evidence_root: &Path,
    phase: PhaseId,
) -> Option<u64>
Expand description

A content fingerprint of the phase’s {phase:02}-VERIFICATION.md, or None when no such artifact exists under evidence_root (999.79, 35-05).

What it is for. Nothing deletes, dates or invalidates the artifact, and devflow start --phase N --force checks out a branch that still carries the PREVIOUS run’s committed copy. That re-run is mid-arc by construction, so its first Validate failure would find the stale artifact, read it as a verdict, and dispatch a --gaps-only pass against zero matching plans — gating unresolvably. Comparing this value against the one recorded at the start of the run distinguishes “the Validate agent authored this during this run” from “this was inherited”.

Why the algorithm is written out rather than borrowed from std. This value is persisted by one process (devflow start) and compared by a later one (devflow advance), so it must mean the same thing in both. std::collections::hash_map::DefaultHasher explicitly does NOT guarantee a stable output across toolchain versions, so an operator who upgraded Rust mid-phase would see every artifact read as “changed” — which is the fail-OPEN direction, dispatching gaps-only exactly where a full execute was correct. This is FNV-1a/64, fixed by these two constants and nothing else.

No security property is claimed. This is change detection over a planning document that is already committed to the repository. It is not collision-resistant and must never be used to authenticate anything; an adversary who can write the artifact can already write whatever verdict they like into it.

§Companion: phase_verification_mtime_nanos

Content alone cannot see an IDEMPOTENT rewrite (WR-06, 35-REVIEW): a Validate agent that re-authors byte-identical content on a later cycle produces the same fingerprint as an artifact nobody touched, and the consumer then classifies its own agent’s work as inherited. The mtime is the second input that separates “unchanged because inherited” from “unchanged because idempotent”; it is read from the same resolved path and returns None on exactly the same “no artifact” condition, so the two are always consistent about whether an artifact exists.