FN-8936: stabilize Planning Mode handoff tests

Stabilize live Proceed-action handoffs and re-admit the Planning Mode flow suite.

- Settle hydration and re-query the Proceed action before direct-create test clicks.
- Remove the Planning Mode test quarantine and record its rescue in the testing ledger.

Files changed:
 .../suite-only-flakes-observed-register.md           |  4 ++++
 docs/testing.md                                      |  3 +++
 .../PlanningModeModal.planning-flow.test.tsx         | 20 ++++++++++++++++----
 packages/dashboard/vitest.config.ts                  |  5 -----
 scripts/lib/test-quarantine.json                     |  5 -----
 5 files changed, 23 insertions(+), 14 deletions(-)

Fusion-Task-Id: FN-8936

Fusion-Task-Lineage: ed869b67-9394-458b-879c-54da0d7d327e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-09 23:06:18 -07:00
parent b30508c685
commit e7a873c505
5 changed files with 23 additions and 14 deletions

View File

@@ -75,6 +75,8 @@ Seven tests failed in `plugin-runner.test.ts`, but only this one identity surviv
The failure is unrelated to the mobile question footer: it exercises the completed-plan Proceed handoff, while FN-8757 changes only the active-question footer. The file retains substantial coverage, so this first sighting is recorded rather than quarantined; a second sighting requires the normal file-level quarantine.
**Superseded 2026-08-10 (FN-8936):** The second sighting moved the file to the deletion-ratchet ledger. Investigation classified the direct handoff as a detached test-node hydration race, not a product create-state race; the suite was rescued by settling hydration and re-querying the live Proceed action before every previously unsafe direct click. The ledger and Vitest exclusion were removed together after exact and loaded-file proof, without timeout/retry/assertion appeasement.
## 5. Planning Mode mobile plan-tab selection
- **File:** `packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx`
@@ -88,6 +90,8 @@ The failure is unrelated to the mobile question footer: it exercises the complet
The failure exercises the pre-existing mobile tab transition, while the task-creation fix changes the completed-plan Proceed handoff. The file retains substantial coverage, so this first sighting is recorded rather than quarantined; a second sighting requires the normal file-level quarantine.
**Suite re-admitted 2026-08-10 (FN-8936):** This first-sighting mobile observation did not receive a second failure. The shared file-level quarantine was removed only after the direct-handoff root cause was structurally fixed and the unexcluded loaded suite, including this mobile coverage, passed.
## Common shape and unverified suspicion
The first three entries are PostgreSQL-backed or PostgreSQL-suite-adjacent, pass in isolation, and appear only under full-suite parallelism. This points at shared database state between those test files rather than any one test. It is **unverified and uninvestigated**, not a diagnosis; do not infer a root-cause fix from this record. The Planning Mode entries are separate frontend timing observations.

View File

@@ -388,6 +388,9 @@ Flags:
<!-- FNXC:DashboardTestQuarantine 2026-08-09-10:27: FN-8900 supersedes the FN-8788 retention decision before the 2026-08-15 deletion-ratchet deadline. The retained route test reads pi-ai's real bundled Kimi catalog through a no-refresh registry seam because five samples reproduced live refresh at 74–300047 ms, including a 300.50 s process. The paired ledger and Vitest exclusion are removed together; no timeout budget was changed and no retry was added. -->
**2026-08-09 Kimi K3 disposition (FN-8900):** Rescued `register-model-routes-kimi-k3-supplemental.test.ts` before the 2026-08-15 deadline. The route test now consumes pi-ai 0.82.1's real bundled K3 catalog via a deterministic registry seam, retaining SDK-catalog regression signal and route merge/deduplication coverage without `ModelRuntime.create()` or live `ModelRegistry.refresh()`. The re-measurement recorded refresh samples of 224, 74, 75, 279, and 300047 ms (the last process took 300.50 s), so the ledger entry and dashboard Vitest exclusion were removed together rather than widening the unchanged 15 s budget or adding a retry.
<!-- FNXC:DashboardTestQuarantine 2026-08-10-05:53: FN-8936 rescued PlanningModeModal's high-value planning-flow suite before its 2026-08-20 deadline. A resumed plan can replace the newly discovered Proceed action during hydration, so each direct-create test now settles that commit and re-queries the live action before dispatch; do not replace this structural fix with waits, retries, or weaker assertions. -->
**2026-08-10 Planning Mode disposition (FN-8936):** Rescued `PlanningModeModal.planning-flow.test.tsx` before its 2026-08-20 deadline. Investigation found no product state-machine race: Proceed snapshots stable session/summary refs and takes its single-flight guard before create. The loaded failure was a test harness detached-node race when session hydration replaced an action-bar button returned by `findByRole`. All unsafe direct Proceed handoffs now settle hydration and query a live button before clicking, while retaining strict create arguments, task-created/onTaskCreated, desktop/mobile handoff, claim-retry, retry, and multi-task assertions. Exact and loaded-file runs passed, and the matching ledger entry and dashboard Vitest exclude were removed together without changing timeouts or adding retries.
### Validate before excluding and preserve timeout budgets
Capture **full runner output** before recording or filing a ledger entry—for example, tee it to a file. Never pipe a dot reporter through `tail`: the summary remains but the `FAIL` identity lines needed for evidence are truncated.

View File

@@ -45,6 +45,18 @@ function answeredHistory(count: number) {
}));
}
/*
FNXC:PlanningMode 2026-08-10-05:45:
A resumed plan can finish hydration after its Proceed action first becomes discoverable, replacing
that action-bar node before an event dispatches. Settle the pending commit and query the live button
at click time so every direct-create handoff tests a real user action rather than a detached node.
*/
async function clickProceedAfterHydration() {
await screen.findByRole("button", { name: "Proceed with plan" });
await act(async () => {});
fireEvent.click(screen.getByRole("button", { name: "Proceed with plan" }));
}
describe("PlanningModeModal sequential flow", () => {
beforeEach(() => {
vi.useRealTimers();
@@ -604,7 +616,7 @@ describe("PlanningModeModal sequential flow", () => {
const onViewTask = vi.fn();
render(<PlanningModeModal isOpen onClose={onClose} onTaskCreated={onTaskCreated} onTasksCreated={vi.fn()} onViewTask={onViewTask} tasks={mockTasks} projectId="project-1" resumeSessionId="session-1" />);
fireEvent.click(await screen.findByRole("button", { name: "Proceed with plan" }));
await clickProceedAfterHydration();
await waitFor(() => expect(mockCreateTaskFromPlanning).toHaveBeenCalledWith(
"session-1",
@@ -716,7 +728,7 @@ describe("PlanningModeModal sequential flow", () => {
const onViewTask = vi.fn();
render(<PlanningModeModal isOpen onClose={vi.fn()} onTaskCreated={vi.fn()} onTasksCreated={vi.fn()} onViewTask={onViewTask} tasks={mockTasks} projectId="project-1" resumeSessionId="session-1" />);
fireEvent.click(await screen.findByRole("button", { name: "Proceed with plan" }));
await clickProceedAfterHydration();
expect(await screen.findByRole("button", { name: "View task" })).toBeEnabled();
expect(screen.getByRole("button", { name: "Return to sessions" })).toBeEnabled();
@@ -784,7 +796,7 @@ describe("PlanningModeModal sequential flow", () => {
// tasks={[]} proves the banner resolves the just-created Task object, not the tasks prop.
render(<PlanningModeModal isOpen onClose={vi.fn()} onTaskCreated={vi.fn()} onTasksCreated={vi.fn()} onViewTask={vi.fn()} tasks={[]} projectId="project-1" resumeSessionId="session-1" />);
fireEvent.click(await screen.findByRole("button", { name: "Proceed with plan" }));
await clickProceedAfterHydration();
expect(await screen.findByTestId("planning-task-created")).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Continue planning" }));
@@ -821,7 +833,7 @@ describe("PlanningModeModal sequential flow", () => {
render(<PlanningModeModal isOpen onClose={vi.fn()} onTaskCreated={vi.fn()} onTasksCreated={vi.fn()} onViewTask={vi.fn()} tasks={mockTasks} projectId="project-1" resumeSessionId="session-1" />);
fireEvent.click(await screen.findByRole("button", { name: "Proceed with plan" }));
await clickProceedAfterHydration();
expect(await screen.findByTestId("planning-create-retry")).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Retry create" }));

View File

@@ -350,11 +350,6 @@ uses pi-ai's real bundled catalog behind a no-refresh registry seam, after live
roughly 300-second stall. Its paired ledger entry is removed in the same commit; no timeout or retry changed.
*/
const quarantinedDashboardTests: string[] = [
/*
FNXC:DashboardTestQuarantine 2026-08-06-15:08:
FN-8816 observed PlanningModeModal's direct task-handoff test fail a second time only under a loaded planning-flow file, after its first-sighting register entry. Quarantine the entire file with its ledger row rather than weaken user-flow assertions or add timing retries; delete it at the ratchet deadline unless a root-cause rescue restores stable coverage.
*/
"app/components/__tests__/PlanningModeModal.planning-flow.test.tsx",
/*
FNXC:DashboardTestQuarantine 2026-07-17-16:50:
FN-8245 re-admits all three UI files with their ledger rows removed in lockstep.

View File

@@ -5,11 +5,6 @@
"file": "packages/engine/src/__tests__/project-engine.test.ts",
"reason": "FN-8811 observed B4/B5 workspace busy contention asserting a stale 60s cap while runtime schedules 120s, then the subprocess guard timed out on git remote; reproduced in isolation on 2026-08-06. Do not widen timing or weaken the assertion; restore only with a root-cause fix before the deletion deadline.",
"quarantinedAt": "2026-08-06"
},
{
"file": "packages/dashboard/app/components/__tests__/PlanningModeModal.planning-flow.test.tsx",
"reason": "FN-8816 observed the previously registered direct task-handoff failure a second time in a loaded planning-flow run while the exact test passed in isolation. Quarantined under the deletion ratchet rather than weakening assertions or adding retries; delete by 2026-08-20 unless a root-cause rescue restores stable coverage.",
"quarantinedAt": "2026-08-06"
}
]
}