FN-7986: raise plan review replan cap to 8
Allow more automatic Plan Review revisions before escalating tasks for human approval. - Raise the consecutive REVISE replan cap from 3 to 8. - Cover the seven- and eight-revision boundaries in triage tests. - Add a patch changeset describing the revised default. Files changed: .changeset/fn-7986-plan-review-cap.md | 7 +++++++ .../triage-plan-review-replan-cap.test.ts | 23 +++++++++++++--------- packages/engine/src/triage.ts | 8 ++++---- 3 files changed, 25 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-7986 Fusion-Task-Lineage: 3b61f333-be9a-414a-bd27-aabdbb45caa0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7986-plan-review-cap.md
Normal file
7
.changeset/fn-7986-plan-review-cap.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Plan Review now allows more automatic replan attempts (default 8) before asking a human.
|
||||
category: internal
|
||||
dev: Raised triage PLAN_REVIEW_GATE_REPLAN_CAP from 3 to 8 in packages/engine/src/triage.ts; escalation to awaiting-approval (awaitingApprovalReason "plan-review-replan-cap") now fires at 8 consecutive REVISE replans.
|
||||
@@ -3,7 +3,7 @@ import type { Settings, Task, TaskStore } from "@fusion/core";
|
||||
import { join } from "node:path";
|
||||
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { PLAN_REVIEW_GATE_REPLAN_CAP, TriageProcessor } from "../triage.js";
|
||||
import { TriageProcessor } from "../triage.js";
|
||||
|
||||
/*
|
||||
* Bug A (part 2): the triage pre-execution Plan Review gate must bound consecutive
|
||||
@@ -142,11 +142,11 @@ describe("Plan Review replan cap", () => {
|
||||
it("escalates to awaiting-approval instead of replanning once the cap is reached", async () => {
|
||||
const rootDir = await createFixtureRoot();
|
||||
roots.push(rootDir);
|
||||
// Cap is PLAN_REVIEW_GATE_REPLAN_CAP (8): a task that has already consumed that many
|
||||
// consecutive REVISE replans must escalate on the next REVISE rather than replanning again.
|
||||
// Cap is 8: a task that has already consumed that many consecutive REVISE replans must
|
||||
// escalate on the next REVISE rather than replanning again.
|
||||
const task = createRetryTask({
|
||||
id: "FN-REPLAN-CAP-HIT",
|
||||
planReviewReplanCount: PLAN_REVIEW_GATE_REPLAN_CAP,
|
||||
planReviewReplanCount: 8,
|
||||
});
|
||||
const prompt = `# Task: ${task.id} - Existing draft\n\n## Mission\n\nOnly rewrite after reviewer feedback.\n`;
|
||||
await writePrompt(rootDir, task.id, prompt);
|
||||
@@ -171,17 +171,22 @@ describe("Plan Review replan cap", () => {
|
||||
expect(store.logEntry).toHaveBeenCalledWith(
|
||||
task.id,
|
||||
"Plan Review replan cap reached — escalating to manual approval",
|
||||
expect.stringContaining(`cap ${PLAN_REVIEW_GATE_REPLAN_CAP}`),
|
||||
expect.stringContaining("cap 8"),
|
||||
);
|
||||
});
|
||||
|
||||
it("still replans when one attempt remains under the cap", async () => {
|
||||
it("still replans from seven consecutive REVISE verdicts", async () => {
|
||||
const rootDir = await createFixtureRoot();
|
||||
roots.push(rootDir);
|
||||
const priorCount = PLAN_REVIEW_GATE_REPLAN_CAP - 1;
|
||||
/*
|
||||
FNXC:PlanReviewReplan 2026-07-15-11:30:
|
||||
Keep this boundary literal rather than deriving it from the production constant. FN-7986
|
||||
requires proof that the default is truly 8: with the former cap of 3, seven prior REVISE
|
||||
verdicts would escalate instead of returning the task to `needs-replan` at count 8.
|
||||
*/
|
||||
const task = createRetryTask({
|
||||
id: "FN-REPLAN-CAP-LAST",
|
||||
planReviewReplanCount: priorCount,
|
||||
planReviewReplanCount: 7,
|
||||
});
|
||||
const prompt = `# Task: ${task.id} - Existing draft\n\n## Mission\n\nOnly rewrite after reviewer feedback.\n`;
|
||||
await writePrompt(rootDir, task.id, prompt);
|
||||
@@ -192,7 +197,7 @@ describe("Plan Review replan cap", () => {
|
||||
|
||||
expect(store.updateTask).toHaveBeenCalledWith(task.id, expect.objectContaining({
|
||||
status: "needs-replan",
|
||||
planReviewReplanCount: PLAN_REVIEW_GATE_REPLAN_CAP,
|
||||
planReviewReplanCount: 8,
|
||||
}));
|
||||
expect(store.updateTask).not.toHaveBeenCalledWith(task.id, expect.objectContaining({
|
||||
status: "awaiting-approval",
|
||||
|
||||
@@ -61,10 +61,10 @@ The triage pre-execution Plan Review gate (runPlanReviewBeforeExecution) routes
|
||||
verdict back to `needs-replan`, which re-plans and re-reviews. Without a ceiling, a planner
|
||||
and reviewer that persistently disagree loop plan → Plan Review REVISE → replan forever
|
||||
(observed on TC-002), and in `planApprovalMode: require-all` there is no human escape because
|
||||
the task never reaches `awaiting-approval`. Bound the consecutive REVISE replans with a small
|
||||
cap (mirroring the executor graph's PLAN_REVIEW_REPLAN_HARD_CAP backstop): after this many
|
||||
replans the gate escalates the task to `awaiting-approval` for a human decision instead of
|
||||
replanning again. The counter (Task.planReviewReplanCount) resets when the gate passes.
|
||||
the task never reaches `awaiting-approval`. Bound the consecutive REVISE replans with a
|
||||
cap (default 8, mirroring the executor graph's PLAN_REVIEW_REPLAN_HARD_CAP backstop): after
|
||||
this many replans the gate escalates the task to `awaiting-approval` for a human decision
|
||||
instead of replanning again. The counter (Task.planReviewReplanCount) resets when the gate passes.
|
||||
|
||||
FNXC:PlanReviewReplan 2026-07-15-11:09:
|
||||
Raise the automatic REVISE replan ceiling from 3 to 8 so planner/reviewer pairs get more
|
||||
|
||||
Reference in New Issue
Block a user