fix(server,test): W6-A stabilize CI — sync lost update, atomic recovery summary, serial PG tests

- downloads.ts observe: re-read download_task FOR UPDATE inside the tx and merge
  from the locked row; qB sync could overwrite imported back to importing when
  verifyAndImport committed between the sync read and write (E8 flake).
- agent finalize: accept summaryPrefix so the recovery verdict is written with
  the terminal status in one update (E6 read a budget_exceeded run before the
  "未恢复:…" annotation landed); recover-summary step kept, now idempotent no-op.
- organize.ts: drop local slotComplete and the once-subscription completion
  write; completion/history are decided only by applySlotEvent(verify_passed)
  (W5-C follow-up, removes double write). Manual slot organize uses the shared
  subscriptions.slotComplete.
- vitest: server split into unit (parallel) and pg (file-serial, groupOrder 1)
  projects; packages/tasks file-serial; explicit worker concurrency in e2e.
- docs: W6 stabilization record in 04-v0.1-acceptance.md.

Test expectations unchanged. Full `deno task ci` x3 green: 369s / 341s / 337s.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 00:32:57 +08:00
1 parent 36aa99b8aa
commit 887843f777
10 files changed
+198 -143

No files matched your search

+3
View File
@@ -189,6 +189,7 @@ export async function finalize(
runId: string,
res: DriveResult,
settled: AgentGoalReport | null,
opts: { summaryPrefix?: string } = {},
): Promise<{ status: AgentRunStatus; summary: string }> {
const { ctx } = env;
const run = await ctx.db.selectFrom("agent_run").selectAll().where("id", "=", runId).executeTakeFirstOrThrow();
@@ -213,6 +214,8 @@ export async function finalize(
}
// 模型文本只作参考:附在业务核查结论之后,明确标注未经核查
if (res.finalText && res.status !== "failed") summary += `\n模型汇报(未经核查):${res.finalText}`;
// 系统核实结论(授权内恢复)与终态同一次写入:观察者看到终态时汇总已是最终文本
if (opts.summaryPrefix) summary = `${opts.summaryPrefix}\n${summary}`;
await ctx.db
.insertInto("artifact")
.values({
+4 -1
View File
@@ -90,8 +90,11 @@ export function registerAgentTasks(registry: TaskRegistry, env: () => AgentEnv)
maxRounds: rounds,
});
}
const out = await t.step.run("finalize", () => finalize(e, runId, res, settled));
const out = await t.step.run("finalize", () =>
finalize(e, runId, res, settled, recovery ? { summaryPrefix: recovery.summary } : {}),
);
if (recovery) {
// 已在 finalize 内带上核实结论;保留该步骤兼容旧 run 的步骤历史(已带前缀时幂等跳过)
const rec = recovery;
return t.step.run("recover-summary", () => annotateRunSummary(e.ctx, runId, rec));
}