Skip to main content

evaluate_now

Function evaluate_now 

Source
pub fn evaluate_now(
    process: &Process,
    current_phase: ProcessPhase,
) -> AutoTerminate
Expand 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 on ProcessPhase:: Running; a Now verdict force-transitions to Exiting regardless of postcondition state.
  • handle_attested — ATTEST-heartbeat clock check on ProcessPhase:: Attested; a Now verdict routes through Releasing when exports are declared, otherwise straight to Exiting.
  • handle_failed — Failed-phase clock check on ProcessPhase:: Failed; a Now verdict routes through Releasing when post-mortem exports are declared, otherwise straight to Zombie.

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 AutoTerminate the 3-arg evaluate returns when passed chrono::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 two evaluate_now calls back-to-back still sees monotonic now reads (each call reads a fresh instant, not a cached one) — matches the pre-lift shape where each of the three phase handlers computed its own chrono::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).