baa-conductor

git clone 

commit
625f808
parent
bb4d393
author
codex@macbookpro
date
2026-03-30 17:12:03 +0800 CST
fix: ignore inactive remote conversation links
3 files changed,  +138, -0
M apps/conductor-daemon/src/index.test.js
+79, -0
 1@@ -41,6 +41,7 @@ import {
 2   routeBaaInstruction,
 3   writeHttpResponse
 4 } from "../dist/index.js";
 5+import { observeRenewalConversation } from "../dist/renewal/conversations.js";
 6 
 7 const BROWSER_REQUEST_WAITER_TIMEOUT_MS = 120_000;
 8 
 9@@ -6615,6 +6616,84 @@ test("ConductorRuntime routes browser.final_message into live instruction ingest
10   }
11 });
12 
13+test("observeRenewalConversation ignores inactive remote links and creates a new local conversation", async () => {
14+  const rootDir = mkdtempSync(join(tmpdir(), "baa-conductor-renewal-observe-active-link-"));
15+  const stateDir = join(rootDir, "state");
16+  const store = new ArtifactStore({
17+    artifactDir: join(stateDir, ARTIFACTS_DIRNAME),
18+    databasePath: join(stateDir, ARTIFACT_DB_FILENAME)
19+  });
20+
21+  try {
22+    const firstObservation = await observeRenewalConversation({
23+      assistantMessageId: "msg-renewal-observe-1",
24+      clientId: "firefox-chatgpt",
25+      observedAt: Date.UTC(2026, 2, 30, 12, 0, 0),
26+      pageTitle: "Renewal Thread",
27+      pageUrl: "https://chatgpt.com/c/conv-renewal-observe",
28+      platform: "chatgpt",
29+      remoteConversationId: "conv-renewal-observe",
30+      store
31+    });
32+
33+    assert.equal(firstObservation.created, true);
34+    assert.equal(firstObservation.resolvedBy, "new");
35+
36+    await store.upsertConversationLink({
37+      isActive: false,
38+      linkId: firstObservation.link.linkId,
39+      localConversationId: firstObservation.conversation.localConversationId,
40+      observedAt: firstObservation.link.observedAt,
41+      platform: "chatgpt",
42+      updatedAt: Date.UTC(2026, 2, 30, 12, 1, 0)
43+    });
44+
45+    assert.equal(
46+      await store.findConversationLinkByRemoteConversation("chatgpt", "conv-renewal-observe"),
47+      null
48+    );
49+
50+    const secondObservation = await observeRenewalConversation({
51+      assistantMessageId: "msg-renewal-observe-2",
52+      clientId: "firefox-chatgpt",
53+      observedAt: Date.UTC(2026, 2, 30, 12, 2, 0),
54+      pageTitle: "Renewal Thread Reopened",
55+      pageUrl: "https://chatgpt.com/c/conv-renewal-observe",
56+      platform: "chatgpt",
57+      remoteConversationId: "conv-renewal-observe",
58+      store
59+    });
60+
61+    assert.equal(secondObservation.created, true);
62+    assert.equal(secondObservation.resolvedBy, "new");
63+    assert.notEqual(
64+      secondObservation.conversation.localConversationId,
65+      firstObservation.conversation.localConversationId
66+    );
67+    assert.equal(secondObservation.link.linkId, firstObservation.link.linkId);
68+    assert.equal(secondObservation.link.localConversationId, secondObservation.conversation.localConversationId);
69+    assert.equal(secondObservation.link.isActive, true);
70+    assert.deepEqual(
71+      await store.findConversationLinkByRemoteConversation("chatgpt", "conv-renewal-observe"),
72+      secondObservation.link
73+    );
74+
75+    const originalConversation = await store.getLocalConversation(firstObservation.conversation.localConversationId);
76+    assert.ok(originalConversation);
77+    assert.equal(originalConversation.lastMessageId, "msg-renewal-observe-1");
78+
79+    const replacementConversation = await store.getLocalConversation(secondObservation.conversation.localConversationId);
80+    assert.ok(replacementConversation);
81+    assert.equal(replacementConversation.lastMessageId, "msg-renewal-observe-2");
82+  } finally {
83+    store.close();
84+    rmSync(rootDir, {
85+      force: true,
86+      recursive: true
87+    });
88+  }
89+});
90+
91 test("ConductorRuntime persists renewal conversation links from browser.final_message and exposes renewal controls", async () => {
92   const stateDir = mkdtempSync(join(tmpdir(), "baa-conductor-renewal-control-"));
93   const runtime = new ConductorRuntime(
M packages/artifact-db/src/index.test.js
+58, -0
 1@@ -319,3 +319,61 @@ test("ArtifactStore persists renewal storage records and enqueues sync payloads"
 2     });
 3   }
 4 });
 5+
 6+test("ArtifactStore findConversationLinkByRemoteConversation only returns active links", async () => {
 7+  const rootDir = mkdtempSync(join(tmpdir(), "artifact-db-renewal-active-link-test-"));
 8+  const stateDir = join(rootDir, "state");
 9+  const databasePath = join(stateDir, ARTIFACT_DB_FILENAME);
10+  const artifactDir = join(stateDir, ARTIFACTS_DIRNAME);
11+  const store = new ArtifactStore({
12+    artifactDir,
13+    databasePath
14+  });
15+
16+  try {
17+    await store.upsertLocalConversation({
18+      localConversationId: "lc_active_link_123",
19+      platform: "chatgpt"
20+    });
21+    const activeLink = await store.upsertConversationLink({
22+      linkId: "link_active_link_123",
23+      localConversationId: "lc_active_link_123",
24+      observedAt: Date.UTC(2026, 2, 30, 8, 0, 0),
25+      platform: "chatgpt",
26+      remoteConversationId: "conv_active_link_123"
27+    });
28+
29+    assert.deepEqual(
30+      await store.findConversationLinkByRemoteConversation("chatgpt", "conv_active_link_123"),
31+      activeLink
32+    );
33+
34+    const inactiveLink = await store.upsertConversationLink({
35+      isActive: false,
36+      linkId: activeLink.linkId,
37+      localConversationId: activeLink.localConversationId,
38+      observedAt: activeLink.observedAt,
39+      platform: activeLink.platform,
40+      updatedAt: Date.UTC(2026, 2, 30, 8, 1, 0)
41+    });
42+
43+    assert.deepEqual(
44+      await store.listConversationLinks({
45+        isActive: false,
46+        platform: "chatgpt",
47+        remoteConversationId: "conv_active_link_123"
48+      }),
49+      [inactiveLink]
50+    );
51+    assert.equal(
52+      await store.findConversationLinkByRemoteConversation("chatgpt", "conv_active_link_123"),
53+      null
54+    );
55+  } finally {
56+    store.close();
57+    rmSync(rootDir, {
58+      force: true,
59+      recursive: true
60+    });
61+  }
62+});
M packages/artifact-db/src/store.ts
+1, -0
1@@ -478,6 +478,7 @@ export class ArtifactStore {
2       FROM conversation_links
3       WHERE platform = ?
4         AND remote_conversation_id = ?
5+        AND is_active = 1
6       LIMIT 1;
7       `,
8       normalizeRequiredString(platform, "platform"),