FN-8760: publish workflow lanes for new tasks
Publish durable workflow lane metadata when new tasks wake triage. - Defer task-created events until selected workflow lanes are durable. - Cache and emit resolved lifecycle lanes while preserving listener compatibility. - Prevent proposal-claim replays from issuing duplicate triage wakes and cover custom lanes. Files changed: .changeset/fn-8760-planning-wake.md | 7 ++++ .../postgres/task-proposal-claim.pg.test.ts | 48 +++++++++++++++++++++- .../__tests__/task-updated-lanes-payload.test.ts | 20 ++++++++- packages/core/src/store.ts | 12 ++++-- packages/core/src/task-store/task-creation.ts | 44 ++++++++++++++++---- packages/engine/src/__tests__/triage.test.ts | 34 ++++++++++++++- 6 files changed, 152 insertions(+), 13 deletions(-) Fusion-Task-Id: FN-8760 Fusion-Task-Lineage: 06275d4a-3fc0-405e-baa5-3cdc8d195695 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -882,7 +882,7 @@ describe("canonical triage policy prompt", () => {
|
||||
|
||||
describe("FN-5893 invariant regression wording", () => {
|
||||
const corePromptSource = readFileSync(
|
||||
fileURLToPath(new URL("../../../core/src/agent-prompts.ts", import.meta.url)),
|
||||
fileURLToPath(new URL("../../../core/src/agents/agent-prompts.ts", import.meta.url)),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
@@ -1759,6 +1759,38 @@ Planner rewrote mission without the raw request.
|
||||
// Should not throw
|
||||
});
|
||||
|
||||
/*
|
||||
FNXC:PlanningModeScheduling 2026-08-03-09:44:
|
||||
Planning Mode may create into a selected workflow whose intake and hold lanes are renamed.
|
||||
The creation event must carry that durable lane answer so the normal wake reaches triage without
|
||||
a route-specific scheduler call; paused work remains gated before the poll is requested.
|
||||
*/
|
||||
it("wakes normal planning admission for a created task in a custom workflow lane", () => {
|
||||
const listeners = new Map<string, (...args: unknown[]) => void>();
|
||||
const triageStore = createMockStore({
|
||||
on: vi.fn((event: string, listener: (...args: unknown[]) => void) => {
|
||||
listeners.set(event, listener);
|
||||
return triageStore;
|
||||
}),
|
||||
off: vi.fn(),
|
||||
});
|
||||
const triageProcessor = trackProcessor(new TriageProcessor(triageStore, rootDir));
|
||||
const requestImmediatePoll = vi.spyOn(triageProcessor, "requestImmediatePoll").mockReturnValue(true);
|
||||
|
||||
triageProcessor.start();
|
||||
listeners.get("task:created")?.(
|
||||
createTriageTask({ id: "FN-PLANNING-CREATED", column: "planning-inbox" }),
|
||||
{ lanes: { intake: "planning-inbox", hold: "ready-to-plan" } },
|
||||
);
|
||||
listeners.get("task:created")?.(
|
||||
createTriageTask({ id: "FN-PLANNING-PAUSED", column: "planning-inbox", paused: true }),
|
||||
{ lanes: { intake: "planning-inbox", hold: "ready-to-plan" } },
|
||||
);
|
||||
|
||||
expect(requestImmediatePoll).toHaveBeenCalledTimes(1);
|
||||
triageProcessor.stop();
|
||||
});
|
||||
|
||||
it("handles settings:updated event for globalPause", () => {
|
||||
const handler = vi.fn();
|
||||
(store.on as ReturnType<typeof vi.fn>).mockImplementation(
|
||||
|
||||
Reference in New Issue
Block a user