fix(engine,core): dedup heartbeat-spawned follow-ups by parent task

Same-agent intake guard now also matches siblings sharing a
sourceParentTaskId, so repeated heartbeats from one parent task
can't bypass dedup just because triage rewrites the title.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-23 03:05:46 -07:00
parent 02971efcfe
commit 51fc826199
8 changed files with 250 additions and 20 deletions

View File

@@ -170,10 +170,40 @@ describe("createTaskCreateTool", () => {
await tool.execute("call-1", { description: "Test" } as any, undefined, undefined, {} as any);
expect(store.createTask).toHaveBeenCalledWith(expect.objectContaining({
source: { sourceType: "agent_heartbeat", sourceAgentId: "agent-123", sourceRunId: undefined },
source: {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-123",
sourceRunId: undefined,
sourceParentTaskId: undefined,
},
}), expect.objectContaining({ settings: { autoSummarizeTitles: false } }));
});
it("threads sourceParentTaskId from provenance into store.createTask", async () => {
const store = {
getSettings: vi.fn().mockResolvedValue({ autoSummarizeTitles: false }),
createTask: vi.fn().mockResolvedValue({ id: "PROJ-101", description: "Test", dependencies: [], column: "triage" }),
};
const tool = createTaskCreateTool(store as any, {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-123",
sourceRunId: "run-abc",
sourceParentTaskId: "FN-5206",
});
await tool.execute("call-1", { description: "spawn follow-up" } as any, undefined, undefined, {} as any);
expect(store.createTask).toHaveBeenCalledWith(expect.objectContaining({
source: {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-123",
sourceRunId: "run-abc",
sourceParentTaskId: "FN-5206",
},
}), expect.anything());
});
it("surfaces linked-existing text when deterministic duplicate is found", async () => {
const existing = { id: "PROJ-500", description: "duplicate", dependencies: [], column: "triage" };
vi.spyOn(core, "runDeterministicDuplicateGuard").mockResolvedValueOnce({