fix: keep workbench projection facts trace-scoped

This commit is contained in:
lyon
2026-06-25 08:36:55 +08:00
parent 41555af9ae
commit 8bae0ef604
2 changed files with 69 additions and 1 deletions
@@ -90,6 +90,74 @@ test("workbench projection writer commits terminal owner evidence as sealed dura
assert.equal(facts.checkpoints[0].timing.finishedAt, "2026-06-20T11:00:00.000Z");
});
test("workbench projection writer does not rewrite prior-turn messages from merged owner session", async () => {
const factWrites = [];
const runtimeStore = {
async writeWorkbenchFacts(params, requestMeta) {
factWrites.push({ params, requestMeta });
return { written: true, facts: params.facts };
}
};
const accessController = {
async recordAgentSessionOwner(input) {
return {
id: input.sessionId,
projectId: input.projectId,
ownerUserId: input.ownerUserId,
conversationId: input.conversationId,
threadId: input.threadId,
lastTraceId: input.traceId,
status: input.status,
updatedAt: "2026-06-20T11:10:00.000Z",
session: {
sessionStatus: "completed",
lastTraceId: input.traceId,
messages: [
{ messageId: "msg_writer_r1_user", role: "user", text: "round1 prompt", status: "sent", turnId: "trc_writer_r1", traceId: "trc_writer_r1" },
{ messageId: "msg_writer_r1_agent", role: "agent", text: "WRONG_ROUND2_TEXT", status: "completed", turnId: "trc_writer_r1", traceId: "trc_writer_r1" },
...input.session.messages
]
}
};
}
};
await writeWorkbenchProjectionSession({
accessController,
runtimeStore,
traceId: "trc_writer_r2",
ownerUserId: "usr_writer",
ownerRole: "user",
sessionId: "ses_writer_multi_turn",
projectId: "prj_writer",
conversationId: "cnv_writer_multi_turn",
threadId: "thread-writer-multi-turn",
status: "completed",
payload: {
traceId: "trc_writer_r2",
status: "completed",
finalResponse: { text: "ROUND2_DONE", status: "completed", traceId: "trc_writer_r2" },
agentRun: { runId: "run_writer_r2", commandId: "cmd_writer_r2", status: "completed", terminalStatus: "completed", lastSeq: 9 },
updatedAt: "2026-06-20T11:10:00.000Z"
},
session: {
sessionStatus: "completed",
messages: [
{ messageId: "msg_writer_r2_user", role: "user", text: "round2 prompt", status: "sent", turnId: "trc_writer_r2", traceId: "trc_writer_r2" },
{ messageId: "msg_writer_r2_agent", role: "agent", text: "ROUND2_DONE", status: "completed", turnId: "trc_writer_r2", traceId: "trc_writer_r2" }
]
}
});
assert.equal(factWrites.length, 1);
const facts = factWrites[0].params.facts;
assert.deepEqual(facts.messages.map((message) => message.messageId), ["msg_writer_r2_user", "msg_writer_r2_agent"]);
assert.equal(facts.messages.some((message) => message.traceId === "trc_writer_r1"), false);
assert.equal(facts.messages.find((message) => message.messageId === "msg_writer_r2_agent").text, "ROUND2_DONE");
assert.equal(facts.turns[0].traceId, "trc_writer_r2");
assert.equal(facts.turns[0].finalResponse.text, "ROUND2_DONE");
});
test("workbench projection writer seals canceled AgentRun turns with canonical cancel final response", async () => {
const factWrites = [];
const runtimeStore = {
@@ -35,7 +35,7 @@ export async function writeWorkbenchProjectionSession({ accessController, runtim
conversationId: ownerRecord?.conversationId ?? conversationId,
threadId: ownerRecord?.threadId ?? threadId,
status: ownerRecord?.status ?? status,
session: ownerRecord?.session ?? session,
session,
payload,
params
});