End the implementer's trajectory when Orchestra reopens the phase
Run 20 showed the leak precisely: the reopen rotated the session, and 31 seconds later the planning session that replaced it recorded phase-2 of the plan being replaced. The implementer's .orchestra/plan-progress.json had outlived it in the worktree, and the successor executed it. Two changes. Phase verification now belongs to the implement phase and is refused anywhere else, which covers every worker and every path rather than the one that produced it. The rotation also drops the ended session's request files, so a successor never inherits work from a trajectory Orchestra has already invalidated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
This commit is contained in:
@@ -330,3 +330,30 @@ func TestASignOffDoesNotSurviveTheTreeItWasGivenAgainst(t *testing.T) {
|
||||
t.Fatalf("a fresh sign-off did not verify the current tree: %+v", rec)
|
||||
}
|
||||
}
|
||||
|
||||
// Run 20: a replan reopened the plan phase, the implementer's leftover
|
||||
// verification request outlived its session, and the planning session that
|
||||
// replaced it executed the request. Orchestra recorded a verified phase of the
|
||||
// plan it was in the middle of replacing.
|
||||
func TestVerificationIsRefusedOutsideImplement(t *testing.T) {
|
||||
s, project, id := planWith(t, twoPhasePlan)
|
||||
task, _ := s.Task(id)
|
||||
m := mismatch(task.PlanRef)
|
||||
m.RequestedAction = domain.PlanMismatchReplan
|
||||
if _, err := RecordPlanMismatch(s, project, id, m, shaOne); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertPhase(t, s, id, domain.WorkPhasePlan)
|
||||
|
||||
_, err := RecordPlanPhaseVerification(s, project, id, "phase-1", shaOne,
|
||||
[]VerificationRun{{Command: []string{"go", "build", "./..."}, ExitCode: 0}})
|
||||
if !errors.Is(err, ErrPlanPhase) {
|
||||
t.Fatalf("a reopened task verified a phase of the plan being replaced: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "implement") {
|
||||
t.Fatalf("the refusal does not say which phase owns verification: %v", err)
|
||||
}
|
||||
if after, _ := s.Task(id); len(after.PlanPhases()) != 0 {
|
||||
t.Fatalf("progress was recorded anyway: %+v", after.PlanPhases())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user