pub fn evaluate_layer2(
project_root: &Path,
phase: PhaseId,
git_flow: &GitFlowConfig,
stage: Stage,
) -> Result<Option<AgentResult>, ResultError>Expand description
Layer 2: Use exit code + commit count to determine result.
Reads exit code from .devflow/phase-NN-exit file.
Counts commits in feature/phase-NN branch (if it exists), via
phase_commit_count.
The commit-count gate (“no commits → failed”) is scoped to stage — it
only applies to Stage::Plan/Stage::Code (checked via an explicit
matches!, NOT Stage::is_agent_stage(), since that also includes
Define, which legitimately produces zero commits). exit≠0 is ALWAYS
Failed, for every stage — only the exit=0/zero-commits branch is
stage-scoped.
Decision matrix: exit=137 → ResourceKilled (ALL stages, D-07) exit=127 → AgentUnavailable (ALL stages, D-07) exit≠0 (excluding 137/127) → Failed (ALL stages) exit=0, stage in {Plan, Code}, commits=0 → Failed (“no work done”) exit=0, stage in {Plan, Code}, commits>0 → Success exit=0, stage NOT in {Plan, Code} (Define/Validate/Ship), commits=0 → Success (not commit-gated; Validate’s real pass signal is its verdict, not a bare zero-commit — see Task 2’s turn.completed deferral) exit unknown → fall to Layer 3 (return None) exit=0, stage in {Plan, Code}, commits UNMEASURABLE → fall to Layer 3 (return None) (CR-01: the ONLY row an unmeasurable count changes. Every other row above is decided by the exit code alone and keeps its verdict with the count rendered as “unknown” in the reason string.)
WR-06 (13-REVIEW.md): takes only the explicit project_root parameter
for both the .devflow/ file paths and the git subprocess current_dir
— previously it also accepted state: &State and used state.project_root
for the git calls, which every caller happened to pass consistently with
project_root but which the function itself had no way to enforce.