From 624a1307fc624354dfdf0ac0da863ace027c9fa9 Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 20 Jun 2026 11:23:25 +0000 Subject: [PATCH] =?UTF-8?q?spec:=20PJ2026-0104010803=20P0=20durable=20outb?= =?UTF-8?q?ox/reconciler=20+=20SSE=20cursor=20replay=20+=20DB=20constraint?= =?UTF-8?q?s=20+=200=E8=AF=BB=E4=BE=A7=E6=8E=A8=E7=90=86=E9=AA=8C=E6=94=B6?= =?UTF-8?q?=E7=9F=A9=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 SPEC 章节: - 5.6 durable projection outbox 与 reconciler 架构图 - 5.7 SSE cursor replay 架构与时序图 - 5.8 DB 唯一约束与幂等保障 - 5.9 0读侧推理验收矩阵 更新实现引用版本为 draft-2026-06-20-p1-zero-split-durable-realtime 同步 web-workbench 和 api-contract SPEC 引用版本 Closes #1746 Refs #1742 --- .../specs/PJ2026-010401-web-workbench.md | 2 +- ...-0104010803-workbench-unique-projection.md | 74 ++++++++++++++++++- .../specs/PJ2026-010403-api-contract.md | 4 +- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md b/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md index ab124e22..0506d761 100644 --- a/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md +++ b/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md @@ -19,7 +19,7 @@ | 短名 | Web工作台 | | 层级 | L2 课题 | | 状态 | 已生效 | -| 实现引用版本 | draft-2026-06-20-p0-long-running-workbench; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model | +| 实现引用版本 | draft-2026-06-20-p0-long-running-workbench; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime | | 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) | | 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) | | 规格治理索引 | [规格治理](spec-governance.md) | diff --git a/project-management/PJ2026-01/specs/PJ2026-0104010803-workbench-unique-projection.md b/project-management/PJ2026-01/specs/PJ2026-0104010803-workbench-unique-projection.md index 3fb82f54..a875e68a 100644 --- a/project-management/PJ2026-01/specs/PJ2026-0104010803-workbench-unique-projection.md +++ b/project-management/PJ2026-01/specs/PJ2026-0104010803-workbench-unique-projection.md @@ -19,7 +19,7 @@ | 短名 | Workbench唯一投影 | | 层级 | L4 专项规格切片 | | 状态 | 已生效 | -| 实现引用版本 | draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-view-local-timing-ticker | +| 实现引用版本 | draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-view-local-timing-ticker; draft-2026-06-20-p1-zero-split-durable-realtime | | 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) | | 上级规格 | [PJ2026-010401 Web工作台](PJ2026-010401-web-workbench.md) | | 关联规格 | [PJ2026-010403 API契约](PJ2026-010403-api-contract.md)、[PJ2026-010205 HWLAB接入](PJ2026-010205-hwlab-dispatch.md)、[PJ2026-0102 Agent编排](PJ2026-0102-agent-orchestration.md) | @@ -250,6 +250,76 @@ Workbench durable facts 是唯一投影的持久对象模型。后续实现可 对象模型必须支持下列 DTO 投影:session rail summary、session detail、message/part page、turn snapshot、trace event page、projection diagnostic 和 transport diagnostic。DTO 可以裁剪字段,但不得合并 authority;例如 trace detail 可展示 `sourceSeq/sourceEventId` 审计信息,主 timeline 的 finalResponse 只能来自 sealed message/part/turn facts。 + +### 5.6 durable projection outbox 与 reconciler + +Projection outbox 是 durable commit log,与 projection facts 在同一数据库事务提交。outbox 的作用是让 SSE、CLI 和其他消费者从 durable cursor 恢复实时通知,不依赖进程内内存 listener。 + +```mermaid +flowchart LR + AR[AgentRun events/result] --> AD[Adapter normalize] + AD --> WR[ProjectionWriter] + WR --> TX[(DB transaction: facts + outbox + checkpoint)] + TX --> FACTS[durable facts] + TX --> OUTBOX[durable outbox rows] + TX --> CP[checkpoint] + OUTBOX --> SSE[SSE cursor replay] + OUTBOX --> REC[reconciler worker] + FACTS --> RM[ReadModel] + RM --> REST[GET /v1/workbench/*] + SSE --> STREAM[SSE events] + CP --> BOOT[boot/resume scheduler] + BOOT --> FIN[Finalizer] + FIN --> WR +``` + +Outbox 每行至少包含 `outboxSeq`(全局单调)、`traceId`、`sessionId`、`turnId`、`projectedSeq`、`commitType`(event/terminal/checkpoint/diagnostic)、`createdAt` 和可序列化 payload 摘要。SSE 连接建立时先从 durable outbox 按 `afterSeq` 查询历史 commit notification 进行 replay,再切换到 live tail;cloud-api 重启后不需要内存 listener 即可恢复 SSE 输出。 + +Reconciler 是后台 worker,消费 outbox 和 checkpoint 驱动 finalizer 追平。它取代旧的请求/轮询式 `syncAgentRunChatResult` 推进模式:AgentRun result sync 只负责拉取/写入 projection source state,事件推进由 outbox/reconciler 管道统一处理。 + +### 5.7 SSE cursor replay 架构 + +```mermaid +sequenceDiagram + participant Client as Web/CLI + participant SSE as SSE handler + participant DB as durable outbox + participant WR as ProjectionWriter + Client->>SSE: GET /v1/workbench/events?afterSeq=N + SSE->>DB: SELECT outbox WHERE outboxSeq > N + DB-->>SSE: replay rows (terminal, events, diagnostics) + SSE-->>Client: replay events + Note over WR,DB: new projection commit + WR->>DB: INSERT outbox row + DB-->>SSE: live tail notification + SSE-->>Client: live event +``` + +SSE handler 不再直接订阅内存 `traceStore.subscribe`。它只从 durable outbox 读取:连接建立时执行 replay(按 `afterSeq` 查询历史 commit notification),replay 完成后切换到 live tail(poll 或 LISTEN/NOTIFY 等价机制)。cloud-api 滚动、多副本和多用户同看同 trace 时,SSE 从同一 durable outbox 恢复,不丢 terminal/sealed 状态。 + +### 5.8 DB 唯一约束与幂等保障 + +`workbench_trace_events` 表必须有 `(trace_id, source_event_id)` 唯一约束,防止并发或历史数据写入重复 source event。allocator 查询 sourceEventId 复用 projectedSeq 时,数据库层必须硬约束阻断重复写入。 + +`(trace_id, projected_seq)` 也应有唯一约束,确保同一 trace 内 projectedSeq 单调不重复。历史 collision 数据在 migration 时通过 collision blocker 策略处理:检测到重复时暴露 `projectionStatus=blocked`、`projectionHealth=degraded` 和稳定 blocker code,不把损坏序列交给 renderer 继续展示。 + +Projection outbox 的 `outboxSeq` 必须全局单调递增,可通过数据库 sequence 或等价机制生成。outbox 行与 projection facts 在同一事务提交,保证 commit notification 与 durable facts 一致。 + +### 5.9 0读侧推理验收矩阵 + +| 层 | 禁止模式 | 验收方式 | +| --- | --- | --- | +| 后端 turn projection | `result?.status ?? trace?.status ?? session?.status` | 源码扫描 + 单元测试构造多来源矛盾样本 | +| 后端 SSE handler | `traceStore.subscribe` / 内存 trace snapshot | 源码扫描 + cloud-api 重启后 SSE cursor 恢复验证 | +| 后端 trace snapshot | `events.at(-1)` 推导 status/lastEvent | 源码扫描 + 矛盾 events 样本测试 | +| 后端 compact result | result/traceSummary/agentRun/memoryTrace 混合 | 源码扫描 + GET 路径不访问旧 compact path 验证 | +| 前端 store | `events.at(-1)` 推导 activity/label/status | 源码扫描 + fake-server Playwright | +| 前端 subscription | turn poll + trace poll + event tail 合并 lifecycle | 源码扫描 + SSE gap/timeout Playwright | +| 前端 timing | `lastEventAgeMs` 作为相对时间权威 | 源码扫描 + fake clock Playwright | +| CLI renderer | `lastEvent.status` 推 trace lifecycle | 源码扫描 + CLI 同源语义验证 | + +每层验收必须先用负向 fixture 形成红灯,再用修复后代码证明通过。负向源码扫描是辅助证据,不能替代 fake-server Playwright 与 D601 v0.3 web-probe。 + ## 6. 原子需求 ### 6.1 WB-PROJ-REQ-001 durable facts store @@ -389,7 +459,7 @@ Sealed final response 回归必须构造 completed assistant 主正文已经展 本专项范围内新增或重构的核心源码文件,文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如: ```text -SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p0-durable-facts-model +SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-20-p1-zero-split-durable-realtime ``` 同一文件同时承载 API契约、HWLAB接入、Web工作台或 Agent编排职责时,应在同一头部追加对应 SPEC 编号与实现引用版本。实现文件不得只写 issue 编号、`latest` 或 `current`。自动生成文件、第三方 vendored 文件、纯配置、锁文件和无法承载注释头的二进制产物可例外,但对应生成器、渲染器或配置入口必须能追溯到本 SPEC。 diff --git a/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md b/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md index be4ad301..7be4a466 100644 --- a/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md +++ b/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md @@ -19,7 +19,7 @@ | 短名 | API契约 | | 层级 | L2 课题 | | 状态 | 已生效 | -| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; PJ2026-01050105 Web鉴权 draft-2026-06-18-p0-auth | +| 实现引用版本 | draft-2026-06-20-p0-workbench-pure-read-api; draft-2026-06-20-p0-error-diagnostics; draft-2026-06-20-p1-view-local-timing-ticker; PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-01050105 Web鉴权 draft-2026-06-18-p0-auth | | 需求规格模板 | [ISO/IEC/IEEE 29148 需求规格模板](../../templates/iso-iec-ieee-29148-requirements-spec-template.md) | | 上级规格 | [PJ2026-0104 客户端](PJ2026-0104-client.md) | | 规格治理索引 | [规格治理](spec-governance.md) | @@ -209,7 +209,7 @@ Trace resource 必须支持按事件位置继续读取,例如 `sinceSeq` / `cu 所有 GET path 必须无业务副作用。需要 repair、finalize、sync 或 migration 时,应由后台 finalizer、显式 mutation 或持久化投影入口执行,不能隐藏在 workspace、conversation、turn 或 trace GET 中。所有分页响应必须包含稳定 cursor 或 seq 边界;trace event page 的分页 cursor 使用 HWLAB `projectedSeq`,并保留 AgentRun `sourceSeq/sourceEventId` 作为来源审计字段,二者不得重叠或互相替代。所有错误响应必须包含 route、status、code/blocker、redacted actor、target resource 和下一步建议。 -新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; PJ2026-010403 API契约 draft-2026-06-20-p0-workbench-pure-read-api; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0`,并简述文件职责。实现文件不得只写 issue 编号、`latest` 或 `current` 作为规格引用。 +新增或重构的核心后端文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本,例如 `SPEC: PJ2026-0104010803 唯一投影 draft-2026-06-20-p0-durable-facts-model; draft-2026-06-20-p1-zero-split-durable-realtime; PJ2026-010403 API契约 draft-2026-06-20-p0-workbench-pure-read-api; PJ2026-010205 HWLAB接入 draft-2026-06-17-r0`,并简述文件职责。实现文件不得只写 issue 编号、`latest` 或 `current` 作为规格引用。 ### 6.4 CLIENT-API-REQ-004 资源与管理接口