feat: PJ2026-0104010803 P3 后端读侧推理清零 - session list + metric status 只读 projection (#1757)

server-workbench-http.ts:
- sessionListProjectionOptions: 当 session snapshot 已有 durable projection 字段
  (projectionStatus/terminal/sealedAt) 时,直接使用 projection 字段构建 turn projection,
  不再从 compactSessionTraceResult/compactSessionTraceSnapshot 多来源混合
- recordWorkbenchProjectionMetric: status 只读 projection.status,不再 fallback 到
  result?.status ?? trace?.status;source 固定为 workbench_read_model
- SPEC header 更新到 draft-2026-06-20-p3-read-side-zero

workbench-turn-projection.ts:
- SPEC header 更新到 draft-2026-06-20-p1-zero-split-durable-realtime

Closes #1749
Refs #1742
This commit is contained in:
Lyon
2026-06-20 19:34:52 +08:00
committed by GitHub
parent 7c5a1f8c5b
commit 9574e2b514
2 changed files with 19 additions and 7 deletions
+18 -6
View File
@@ -1,5 +1,5 @@
/*
* SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-010403 API契约 draft-2026-06-18-r1; PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0
* SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p0-projector-resume; draft-2026-06-20-p1-zero-split-durable-realtime; draft-2026-06-20-p3-read-side-zero; PJ2026-010403 API契约 draft-2026-06-18-r1; PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-01060505 Workbench Performance draft-2026-06-17-p0
* 职责: Workbench REST read model。只读投影 session/message/turn/trace facts,不执行 AgentRun sync、billing finalize 或 workspace repair。
*/
import { createHash } from "node:crypto";
@@ -267,10 +267,10 @@ function recordWorkbenchProjectionMetric(options = {}, { result = null, trace =
projectedLatestEventAt: diagnostic?.updatedAt ?? projection?.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null,
terminalSourceAt: workbenchTerminalSourceAt(result, projection),
terminalProjectedAt: diagnostic?.projectionStatus === "caught-up" ? diagnostic?.updatedAt ?? projection?.updatedAt ?? trace?.updatedAt ?? result?.updatedAt ?? null : null,
status: projection?.status ?? result?.status ?? trace?.status ?? "unknown",
status: projection?.status ?? "unknown",
reason: workbenchProjectionReason(diagnostic),
projectionStatus: diagnostic?.projectionStatus ?? "unknown",
source: result?.agentRun ? "agentrun_v01" : "workbench_read_model"
source: "workbench_read_model"
});
}
@@ -1202,9 +1202,21 @@ function sessionListProjectionOptions(readModel, session, options) {
const traceId = safeTraceId(session?.lastTraceId ?? snapshot.lastTraceId ?? snapshot.currentTraceId ?? snapshot.traceId) ?? null;
if (!traceId) return options;
const memoryResult = readModel.resultForTrace(traceId);
const result = memoryResult ?? compactSessionTraceResult(snapshot, session, traceId);
const memoryTrace = traceSnapshotSync(options, traceId);
const trace = compactSessionTraceSnapshot(snapshot, session, traceId, result, memoryTrace);
const hasDurableProjection = Boolean(snapshot.projectionStatus || snapshot.terminal !== undefined || snapshot.sealedAt);
const result = hasDurableProjection ? null : (memoryResult ?? compactSessionTraceResult(snapshot, session, traceId));
const memoryTrace = hasDurableProjection ? null : traceSnapshotSync(options, traceId);
const trace = hasDurableProjection ? null : compactSessionTraceSnapshot(snapshot, session, traceId, result, memoryTrace);
if (hasDurableProjection) {
const projection = createWorkbenchTurnProjection({
traceId,
turnId: traceId,
result: { status: snapshot.projectionStatus ?? snapshot.status, terminal: snapshot.terminal, timing: snapshot.timing, finalResponse: snapshot.finalResponse, valuesRedacted: true },
session: null,
trace: null
});
const projectionDiagnostic = readModel.projectionDiagnostics({ traceId, result: null, trace: null, projection });
return { ...options, trace: null, result: null, projection, projectionDiagnostic };
}
const projection = createWorkbenchTurnProjection({ traceId, result, session, trace });
const projectionDiagnostic = readModel.projectionDiagnostics({ traceId, result, trace, projection });
return { ...options, trace, result, projection, projectionDiagnostic };