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:
@@ -734,3 +734,61 @@ func TestPendingManualGateRendersStale(t *testing.T) {
|
||||
t.Errorf("a pending manual gate at HEAD rendered stale:\n%s", fresh)
|
||||
}
|
||||
}
|
||||
|
||||
// F66, found live on run 20. A replan convenes a planning session to settle a
|
||||
// contradiction, and that session was told nothing about it: the ordinary plan
|
||||
// brief, an empty template, and no mention that a plan already exists.
|
||||
func TestAReopenedPlanPhaseIsToldWhatContradictedThePlan(t *testing.T) {
|
||||
in := input()
|
||||
in.Phase = domain.WorkPhasePlan
|
||||
in.Task.PlanRef = "plan-a"
|
||||
in.Task.PlanMismatch = &domain.PlanMismatch{
|
||||
PlanRef: "plan-a", PhaseID: "phase-3", AtSHA: "18ccaf00000000000000000000000000000000aa",
|
||||
Observed: "the aggregation runs per figure, not per person",
|
||||
Contradicts: "the plan states the pipeline already aggregates per person",
|
||||
Evidence: []string{"internal/figures/aggregate.go:88"},
|
||||
RequestedAction: domain.PlanMismatchReplan,
|
||||
}
|
||||
out, err := Build(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{
|
||||
"## Why this phase reopened",
|
||||
"phase: phase-3",
|
||||
"the aggregation runs per figure",
|
||||
"the plan states the pipeline already aggregates per person",
|
||||
"internal/figures/aggregate.go:88",
|
||||
"stays accepted until you seal a replacement",
|
||||
} {
|
||||
if !strings.Contains(out.Task, want) {
|
||||
t.Fatalf("the planner was not told %q:\n%s", want, out.Task)
|
||||
}
|
||||
}
|
||||
// It must come before the artifacts it changes the reading of.
|
||||
in.Research = &workphase.Research{Findings: []workphase.Finding{{
|
||||
ID: "r1", Confidence: "fact", Claim: "aggregation is per figure",
|
||||
Evidence: "internal/figures/aggregate.go:88",
|
||||
}}}
|
||||
out, err = Build(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(out.Task, "## Accepted research") {
|
||||
t.Fatal("the research this planner works from is missing")
|
||||
}
|
||||
if strings.Index(out.Task, "## Why this phase reopened") > strings.Index(out.Task, "## Accepted research") {
|
||||
t.Fatal("the reason this session exists is rendered below the material it qualifies")
|
||||
}
|
||||
|
||||
// An implementer is looking at the code, not at an account of the last
|
||||
// contradiction, so it renders nowhere else.
|
||||
in.Phase = domain.WorkPhaseImplement
|
||||
out, err = Build(in)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(out.Task, "## Why this phase reopened") {
|
||||
t.Fatal("a settled contradiction reached the implementation phase")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user