Skip to main content

phase_commit_count

Function phase_commit_count 

Source
pub fn phase_commit_count(
    project_root: &Path,
    git_flow: &GitFlowConfig,
    phase: PhaseId,
) -> Option<u32>
Expand description

Commits on the phase’s feature branch that are not on develop.

Derives the branch name from git_flow.feature_prefix and the zero-padded phase, verifies the branch exists with rev-parse --verify, and on success counts {git_flow.develop}..{branch} with rev-list --count. This is the single implementation of that count — evaluate_layer2, evaluate_layer3 and pipeline_outcomes::handle_validate_outcome’s forward-progress check all call it rather than each re-deriving the branch name and re-running the same two git commands, which is what made the counts able to silently diverge before this extraction. That claim was aspirational until 35-01: evaluate_layer3 carried its own inline rev-list --count with an independent copy of the lossy zero collapse, and deleting it is what makes “single implementation” true.

Must be called with the main project_root, never a worktree path — git worktrees share refs and the object database, so a commit made inside a linked worktree is immediately visible to a count run from the main checkout, which is the property every caller already relies on.

The return distinguishes a MEASUREMENT from a measurement FAILURE, which is the whole point of the Option (999.77 / D-08, A-06):

  • Some(n) — git ran and reported a real number. This includes Some(0) for a branch that genuinely does not exist yet, which is normal on a phase’s first Validate and is a real observation, not a failure to observe.
  • None — the count could not be established: either the git child could not be executed at all (.output() returned Err), or it ran but produced stdout that does not parse as a u32. A-06 splits only the ran/did-not-run axis; the unparseable case is mapped to None here because the child produced no usable count, and reporting a forged zero for it would recreate exactly the hazard this signature removes.

The two consumers now handle None distinctly, and neither collapses it to zero. pipeline_outcomes::handle_validate_outcome treats an unmeasurable cycle as not-progress and leaves its persisted baseline untouched, so the next real measurement still compares against the last real observation. evaluate_layer2 returns Ok(None) and falls through to evaluate_layer3, which classifies an unmeasurable count as AgentStatus::Unknown rather than asserting the negative that no work was done.

§Changed in v2.5.0 — breaking

The return type was u32 before this release; it is now Option<u32> (999.77 / 999.87). A call site updating from the old form must decide which of the two states it means, because the old type conflated them:

  • Some(0) — git RAN and the branch genuinely has no commits. This is the old 0 in its legitimate sense, and is normal on a phase’s first Validate.
  • None — no count was established at all. This is the case the old signature could not express, and .unwrap_or(0) is precisely the wrong way to restore it: collapsing it back to zero is the defect this change exists to remove. A transient git failure then reads as “no work done”, which forged a consecutive_failures baseline reset (999.77) and made the result cascade classify a successful agent as Failed (999.87).

The enumeration of this and every other public-surface change in the release is in CHANGELOG.md under 2.5.0.