pub fn evaluate_now(
process: &Process,
current_phase: ProcessPhase,
) -> AutoTerminateExpand description
Wall-clock-anchored peer of evaluate — pins the now argument
to chrono::Utc::now so every production reconciler tick reads a
single-shape 2-arg call rather than restating the wall-clock
projection at each phase handler.
§Why it exists
Pre-lift the 3-arg evaluate(p, ProcessPhase::X, chrono::Utc::now())
chain was hand-authored at THREE sites past the ★★ PRIME-DIRECTIVE
≥ 2 duplication threshold in tatara-reconciler::phase_machine,
each pairing an ephemeral-lifetime clock check against wall-clock
time inside a handle_<phase> async fn:
handle_running— VERIFY-phase clock check onProcessPhase:: Running; aNowverdict force-transitions toExitingregardless of postcondition state.handle_attested— ATTEST-heartbeat clock check onProcessPhase:: Attested; aNowverdict routes through Releasing when exports are declared, otherwise straight toExiting.handle_failed— Failed-phase clock check onProcessPhase:: Failed; aNowverdict routes through Releasing when post-mortem exports are declared, otherwise straight toZombie.
All three sites walked the SAME 3-arg call with the SAME
chrono::Utc::now() third argument — the wall-clock projection had
no per-callsite variation. Post-lift the three consumers share ONE
substrate owner for the wall-clock-at-tick projection; a future
clock swap (a monotonic clock cross-check, a per-reconciler
injected time source, a test-only override at the production
callsite via feature flag) lands at ONE substrate function and
every phase handler inherits the upgrade mechanically.
The 3-arg evaluate peer stays load-bearing for test callers —
the injected-now shape is what unit tests use to drive the clock
deterministically (every evaluate(&p, phase, Utc::now()) /
evaluate(&p, phase, seeded_now) in this module’s own test suite
reads that surface). This peer is production-only: pinning the
wall-clock at the substrate site means no test can accidentally
consume it without the deterministic-clock injection that makes
the test meaningful.
§Invariants
- Same decision shape: returns the SAME
AutoTerminatethe 3-argevaluatereturns when passedchrono::Utc::now()as the third argument. This is a delegation, not a re-implementation. - Wall-clock read once:
Utc::now()is called exactly ONCE per invocation, at the primitive’s body, so a future consumer that chains twoevaluate_nowcalls back-to-back still sees monotonicnowreads (each call reads a fresh instant, not a cached one) — matches the pre-lift shape where each of the three phase handlers computed its ownchrono::Utc::now()at its own line.
§#[must_use]
Every consumer either destructures the returned AutoTerminate at
an if let AutoTerminate::Now { reason } = … guard (the three
pre-lift phase-handler shapes) or feeds it into a downstream
dispatcher that gates on AutoTerminate::is_now. Dropping the
return means the clock check fired for no observable reason — the
attribute surfaces that as a warning at every call site.
Theory anchor: THEORY.md §VI.1 (generation over composition — the
3-arg call with chrono::Utc::now() as the third argument recurred
at 3 hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
duplication trigger, lifted onto the ONE workspace-wide substrate
owner here). THEORY.md §II.1 invariant 5 (composition preserves
proofs — the wall-clock projection lives at ONE site so a future
clock swap reaches all three consumers through one edit).