FN-5733: enforce mission completion-gate assertions for live Goals mission

Realize the mission completion-gate contract by surfacing and enforcing structured assertion coverage for milestone completion.

- add milestone rollup signaling for prose-only acceptance criteria and wire it into mission-store completion gating
- update mission execution loop reliability paths so validator-trigger continuity is preserved across completion and startup recovery
- expose the new rollup flag in dashboard mission types/API and show an autopilot warning badge in MissionManager when prose exists without structured assertions
- extend core, engine, and dashboard tests plus mission docs, and add a patch changeset for @runfusion/fusion

Files changed:
 .changeset/fn-5733-mission-completion-gate.md      | 10 +++
 docs/missions-completion-contract.md               | 11 +++
 docs/missions.md                                   |  4 +
 packages/core/src/__tests__/mission-store.test.ts  | 81 ++++++++++++++++++++
 packages/core/src/mission-store.ts                 | 89 ++++++++++++++++++++++
 packages/core/src/mission-types.ts                 |  2 +
 packages/dashboard/app/api/legacy.ts               |  1 +
 .../dashboard/app/components/MissionManager.css    | 42 +++++++++-
 .../dashboard/app/components/MissionManager.tsx    | 22 +++++-
 .../components/__tests__/MissionManager.test.tsx   | 20 ++++-
 packages/dashboard/app/components/mission-types.ts |  1 +
 .../src/__tests__/mission-execution-loop.test.ts   | 23 ++++++
 .../mission-validation-trigger-gap.test.ts         | 41 ++++++++++
 packages/engine/src/mission-execution-loop.ts      | 21 ++++-
 14 files changed, 357 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-5733

Fusion-Task-Lineage: 259418c6-5404-4773-8fd2-db8d7e9cadd3
This commit is contained in:
gsxdsm
2026-05-30 14:07:20 -07:00
parent 90a23e9fc1
commit 9c4e8edf39
14 changed files with 357 additions and 11 deletions

View File

@@ -148,4 +148,45 @@ describe("FN-5715 reliability: mission validation trigger gap", () => {
expect(processSpy).not.toHaveBeenCalled();
loop.stop();
});
it("recovery replays implementing done tasks with zero assertions and advances loop state", async () => {
const feature = makeFeature({ status: "done", lastValidatorStatus: undefined, loopState: "implementing" });
const missionStore = {
listMissions: vi.fn(() => [{ id: "M-001", status: "active" }]),
getMissionWithHierarchy: vi.fn(() => ({
id: "M-001",
status: "active",
milestones: [{ status: "active", slices: [{ status: "active", features: [feature] }] }],
})),
getFeatureByTaskId: vi.fn(() => feature),
getFeature: vi.fn(() => feature),
updateFeatureStatus: vi.fn(),
updateFeature: vi.fn(),
listAssertionsForFeature: vi.fn(() => []),
getSlice: vi.fn(() => ({ id: "SL-001", milestoneId: "MS-001", status: "active" })),
getMilestone: vi.fn(() => ({ id: "MS-001", missionId: "M-001" })),
logMissionEvent: vi.fn(),
transitionLoopState: vi.fn(),
};
const taskStore = {
getTask: vi.fn(async () => ({ id: "FN-001", column: "done", status: "done" })),
on: vi.fn(),
off: vi.fn(),
};
const loop = new MissionExecutionLoop({
missionStore: missionStore as any,
taskStore: taskStore as any,
rootDir: process.cwd(),
});
loop.start();
await loop.recoverActiveMissions();
expect(missionStore.updateFeature).toHaveBeenCalledWith(
"F-001",
expect.objectContaining({ loopState: "passed", lastValidatorStatus: "passed" }),
);
loop.stop();
});
});