Patch folder realtime threads locally

This commit is contained in:
kris
2026-04-10 22:01:21 +08:00
parent 0781a56aad
commit a084688e35
7 changed files with 145 additions and 0 deletions

View File

@@ -23,4 +23,14 @@ test("android folder activity refreshes on matching device-scoped conversation u
/payloadDeviceId\.equals\(folderDeviceId\)/,
"expected folder activity to reload when the event targets its device",
);
assert.match(
source,
/tryApplyFolderRealtimePatch\(event\)/,
"expected folder activity to try a local thread-row patch before falling back to network reload",
);
assert.match(
source,
/threadConversationItem/,
"expected folder activity to read the direct thread item patch from realtime payloads",
);
});

View File

@@ -9,6 +9,7 @@ let readState: (typeof import("../src/lib/boss-data"))["readState"];
let updateConversationAction: (typeof import("../src/lib/boss-data"))["updateConversationAction"];
let getConversationHomeItems: (typeof import("../src/lib/boss-projections"))["getConversationHomeItems"];
let getConversationHomeItemForProject: (typeof import("../src/lib/boss-projections"))["getConversationHomeItemForProject"];
let getConversationThreadItemForProject: (typeof import("../src/lib/boss-projections"))["getConversationThreadItemForProject"];
let getConversationFolderView: (typeof import("../src/lib/boss-projections"))["getConversationFolderView"];
let formatTimestampLabel: (typeof import("../src/lib/boss-projections"))["formatTimestampLabel"];
let getConversationListItemPresentation: (typeof import("../src/components/app-ui"))["getConversationListItemPresentation"];
@@ -30,6 +31,7 @@ async function setup() {
updateConversationAction = data.updateConversationAction;
getConversationHomeItems = projections.getConversationHomeItems;
getConversationHomeItemForProject = projections.getConversationHomeItemForProject;
getConversationThreadItemForProject = projections.getConversationThreadItemForProject;
getConversationFolderView = projections.getConversationFolderView;
formatTimestampLabel = projections.formatTimestampLabel;
getConversationListItemPresentation = ui.getConversationListItemPresentation;
@@ -233,6 +235,40 @@ test("conversation home patch lookup returns the direct thread item when no fold
assert.equal(item?.projectId, "solo-thread");
});
test("conversation thread patch lookup keeps the direct single-thread item for grouped folders", async () => {
await setup();
const state = await readState();
state.projects = state.projects.filter((project) => project.id === "master-agent");
state.projects.push(
buildImportedThreadProject(
"mac-studio",
"boss-thread-a",
"Boss",
"boss",
"线程 A",
"thread-a",
"2026-04-04T12:00:00+08:00",
),
buildImportedThreadProject(
"mac-studio",
"boss-thread-b",
"Boss",
"boss",
"线程 B",
"thread-b",
"2026-04-04T11:00:00+08:00",
),
);
const item = getConversationThreadItemForProject(state, "boss-thread-b");
assert.ok(item, "expected grouped thread lookup to resolve to its direct thread row");
assert.equal(item?.conversationType, "single_device");
assert.equal(item?.projectId, "boss-thread-b");
assert.equal(item?.folderKey, "mac-studio:boss");
});
test("folder archive context ring prefers more urgent contextBudgetLevel when mustFinishBeforeCompaction is equal", async () => {
await setup();
const state = await readState();

View File

@@ -19,6 +19,11 @@ test("events route enriches project conversation events with a visible home item
/conversationItem:\s*getConversationHomeItemForProject\(state,\s*String\(payload\.projectId \?\? ""\)\)/,
"expected enriched event payload to carry a conversation item slot",
);
assert.match(
source,
/threadConversationItem:\s*getConversationThreadItemForProject\(state,\s*String\(payload\.projectId \?\? ""\)\)/,
"expected enriched event payload to carry a direct thread item slot for folder pages",
);
});
test("MainActivity applies realtime conversation patches without forcing a network refresh", async () => {