feat(FN-3959): add heartbeat timer registration repair sweep

Heartbeat timer repair sweep — adds a registration repair mechanism that detects and flags stale timers via agent updates, with tests covering the new sweep behavior. Documentation updated in agents.md to reflect the repair flow.

Fusion-Task-Id: FN-3959

Fusion-Task-Lineage: 40708b6b-01e1-4673-93e1-299678de2879
This commit is contained in:
Fusion
2026-05-11 15:18:40 -07:00
committed by gsxdsm
parent 1f47e137f7
commit 3f6c4c688a
6 changed files with 193 additions and 111 deletions

View File

@@ -312,7 +312,7 @@ describe("Chat Room API Routes", () => {
expect(missingMessage.status).toBe(404);
});
it("resolves project-scoped room services for message replies", async () => {
it("resolves project-scoped room services for room reads and message replies", async () => {
const scopedRoot = mkdtempSync(join(tmpdir(), "fusion-chat-room-scoped-"));
const scopedFusionDir = join(scopedRoot, ".fusion");
const scopedDb = new Database(scopedFusionDir, { inMemory: true });
@@ -333,6 +333,12 @@ describe("Chat Room API Routes", () => {
projectId: "proj-scope",
memberAgentIds: [scopedAgent.id],
});
const seededMessage = scopedChatStore.addRoomMessage(room.id, {
role: "user",
content: "seeded scoped message",
senderAgentId: null,
mentions: [],
});
const defaultChatManager = {
sendRoomMessage: async () => {
@@ -362,6 +368,14 @@ describe("Chat Room API Routes", () => {
metadata: { roomId: room.id },
});
const listRes = await request(appWithScopedEngine, "GET", "/api/chat/rooms?projectId=proj-scope");
expect(listRes.status).toBe(200);
expect((listRes.body as any).rooms.map((entry: any) => entry.id)).toEqual([room.id]);
const messagesRes = await request(appWithScopedEngine, "GET", `/api/chat/rooms/${room.id}/messages?projectId=proj-scope`);
expect(messagesRes.status).toBe(200);
expect((messagesRes.body as any).messages.map((entry: any) => entry.id)).toContain(seededMessage.id);
const postRes = await request(
appWithScopedEngine,
"POST",