Tell the planner what it was convened to fix
F66, found live on run 20. A replan reopens the plan phase and the session it convenes was given the ordinary plan brief and an empty template: no mention that a plan already exists, what contradicted it, which phase, what evidence, or that its output supersedes an accepted plan. All of it was already durable on PlanMismatchRecorded and none of it reached the agent, so nothing stopped the replacement from sealing with the same contradiction in it. The contradiction is now projected onto the task and rendered above the sealed artifacts, because it changes how they should be read. Its lifetime is bounded at both ends: a sealed replacement answers it, and so does a human reply to the stop it caused. Only the phases a mismatch can reopen render it, since an implementer looks at the code rather than at an account of the last contradiction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
This commit is contained in:
@@ -108,6 +108,11 @@ func TestReplanKeepsTheOldPlanUntilAReplacementIsSealed(t *testing.T) {
|
||||
if len(during.PlanHistory) != 0 {
|
||||
t.Fatalf("the plan was moved to history early: %v", during.PlanHistory)
|
||||
}
|
||||
// F66: the planning session this reopen convenes has to be told what it is
|
||||
// there to fix, and the implementer that found it is gone by then.
|
||||
if during.PlanMismatch == nil || during.PlanMismatch.PhaseID != "phase-1" {
|
||||
t.Fatalf("the contradiction did not survive to the phase it reopened: %+v", during.PlanMismatch)
|
||||
}
|
||||
}
|
||||
|
||||
// Sealing the replacement is the moment the old plan is superseded. Progress
|
||||
@@ -151,6 +156,11 @@ func TestSealingTheReplacementSupersedesThePlanAndItsProgress(t *testing.T) {
|
||||
if _, err := s.Artifact(oldRef); err != nil {
|
||||
t.Fatalf("the superseded plan is unreadable: %v", err)
|
||||
}
|
||||
// The replacement answers the contradiction, so it stops being a live
|
||||
// instruction and stays in the log as history.
|
||||
if after, _ := s.Task(id); after.PlanMismatch != nil {
|
||||
t.Fatalf("a settled contradiction is still live: %+v", after.PlanMismatch)
|
||||
}
|
||||
assertPhase(t, s, id, domain.WorkPhaseImplement)
|
||||
}
|
||||
|
||||
@@ -229,6 +239,11 @@ func TestHumanAnswerResumesTheSamePlanWithoutResealing(t *testing.T) {
|
||||
if after.BlockReason != "" || after.Blocker != "" {
|
||||
t.Fatalf("a resumed task still reports its blocker: %q %q", after.BlockReason, after.Blocker)
|
||||
}
|
||||
// The answer outranks the plan and stands as an ordinary decision, so the
|
||||
// contradiction it settled is not carried into later sessions either.
|
||||
if after.PlanMismatch != nil {
|
||||
t.Fatalf("an answered contradiction is still live: %+v", after.PlanMismatch)
|
||||
}
|
||||
if after.PlanRef != planRef {
|
||||
t.Fatal("answering the question replaced the plan")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user