fix: make last phase detection deterministic#331
Conversation
Nightly -> Main 11/02/2026
|
Claude finished @karishnu's task in 54s —— View job Code Quality & Security ReviewRecommendation: ✅ APPROVE PR SummaryMakes last phase detection deterministic by calculating roadmap completion based on completed phase count rather than relying on LLM's PR Description
Addressed Issues
Code Quality
Analysis: The changes are clean and well-implemented:
Security
No security concerns - this is purely internal logic for phase management. Testing
Final Recommendation✅ Approve - This is a well-thought-out improvement that replaces non-deterministic LLM output with deterministic state-based calculation. The code is clean, handles edge cases appropriately, and maintains backward compatibility. |
There was a problem hiding this comment.
Pull request overview
This PR aims to make “last phase” detection deterministic by removing reliance on LLM-provided lastPhase and instead finalizing when the blueprint implementation roadmap is deemed complete.
Changes:
- Updated the phase-generation system prompt to stop instructing the LLM to decide
lastPhase. - Changed the phasic state machine to transition to
FINALIZINGbased on completed phases vs. roadmap length (plus the existing phases counter fallback).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| worker/agents/operations/PhaseGeneration.ts | Removes LLM instruction for setting lastPhase, stating completion is determined by the system. |
| worker/agents/core/behaviors/phasic.ts | Implements deterministic completion check using completed phase count vs. roadmap length. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Plan the next phase to advance toward completion. The system will automatically determine when the roadmap is complete based on implemented phases. | ||
|
|
||
| Do not add phases for polish, optimization, or hypothetical improvements - users can request those via feedback. |
There was a problem hiding this comment.
SYSTEM_PROMPT now says the system will automatically determine completion, but the phase generation contract still includes lastPhase (PhaseConcept schema) and the user prompt section later in this file still instructs the LLM to set lastPhase. This mixed signaling can confuse the model and produce inconsistent outputs; either remove/soften lastPhase guidance everywhere (and/or drop it from the schema), or keep the guidance consistent and explicitly state that lastPhase is ignored by the orchestrator.
| const completedPhasesCount = this.state.generatedPhases.filter(p => p.completed).length; | ||
| const roadmapLength = this.state.blueprint.implementationRoadmap?.length ?? 0; | ||
| const isRoadmapComplete = roadmapLength > 0 && completedPhasesCount >= roadmapLength; |
There was a problem hiding this comment.
isRoadmapComplete is computed from completedPhasesCount >= roadmapLength, which assumes a 1:1 correspondence between completed generated phases and roadmap items. Since phase generation explicitly allows phases to deviate from the roadmap (e.g., extra bugfix/user-suggested phases), this can deterministically transition to FINALIZING before the last roadmap item is actually implemented. Consider basing completion on matching the final roadmap entry (e.g., last completed phase name vs implementationRoadmap[roadmapLength-1].phase), or tracking a separate roadmap progress index in state so non-roadmap phases don’t advance completion.
| const completedPhasesCount = this.state.generatedPhases.filter(p => p.completed).length; | |
| const roadmapLength = this.state.blueprint.implementationRoadmap?.length ?? 0; | |
| const isRoadmapComplete = roadmapLength > 0 && completedPhasesCount >= roadmapLength; | |
| const implementationRoadmap = this.state.blueprint.implementationRoadmap ?? []; | |
| const roadmapLength = implementationRoadmap.length; | |
| const isRoadmapComplete = | |
| roadmapLength > 0 && | |
| this.state.generatedPhases | |
| .filter(p => p.completed) | |
| .some(p => p.name === implementationRoadmap[roadmapLength - 1].phase); |
Summary
Make the last phase detection deterministic by basing it on roadmap completion progress rather than relying on the LLM's
lastPhaseoutput flag.Changes
worker/agents/core/behaviors/phasic.tsto calculateisRoadmapCompletebased on the count of completed phases versus the implementation roadmap lengthworker/agents/operations/PhaseGeneration.tsby removing instructions for the LLM to setlastPhase: true, since the system now handles this automaticallyMotivation
Previously, the system relied on the LLM to output
lastPhase: truewhen it determined the roadmap was complete. This approach was non-deterministic because LLM outputs can vary. By calculating roadmap completion based on the actual number of completed phases compared to the roadmap length, the behavior becomes predictable and consistent.Testing
completedPhasesCount >= roadmapLengthroadmapLengthis 0, the fallback tophasesCounter <= 0still worksBreaking Changes
None - this is an internal implementation change that should not affect external behavior.