Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .opencode/handoff-batch-b.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,32 @@
> 本会话(批 A 全链路)已极长,批次 B 在新对话执行。引用本文件 + 下述证据路径即可开工。

## 起点状态(交接时)
- 基线:**dev**(`bee78d7ed` 起算,开工前 `git fetch && git switch dev && git pull`)
- 基线:**dev**(批 B 规划基线 `3e8368f37`;每票开工前重新同步最新 `dev`)
- 批次 A 全闭环:Q1-Q6 引擎语义 + 接受期绑定校验 + flaky 根治(豁免清单已清零)+ 技术债清零(PR #185-#189 全合入)
- lint 棘轮:4852(CI 口径;本地 = CI − 10 生成物差,本地基线 ≤4842)——**只紧不松**
- 台账:.scratch/batch-a/issues/01-11(01-09 完成,10/11 closed)

## 批次 B 四组票(Ask Matt 路由:agent-ready,证据已在案)
## 批次 B 四组票(审计后路由,证据已在案)

### 组 1:U-1 / U-2 + Transport mid-stream-stall(一个 spec 三张票)
三个 abort-path 集成测试,同源同批。先 /to-spec 收敛三票边界,再逐票 /implement。
三个 abort-path 集成测试,同源同批。规格已收敛到 `.scratch/batch-b/abort-path-contracts.md`,按 01→02→03 逐票 /implement。

### 组 2:F3 / F4 测试卫生债
小票直接做(无需 grill),每票新上下文 /implement。

### 组 3:O1 remote config last-known-good 缓存
小 feature;离线降级的 last-known-good 语义在批 A 前置调研中有上下文(config-offline-degrade 已合入 dev,先读现状再定增量)
批 A 已完成“网络/响应体失败时 warn + skip”;剩余增量只有持久化 last-known-good。先完成 `.scratch/batch-b/issues/06-o1-lkg-spec.md` 的小规格,再按 07 实现;不得重新实现离线降级

### 组 4:S7 recovery INVENTED 推断 ⚠️
唯一带 bug 气味的——**必须走 /diagnosing-bugs**:先 tight feedback loop(一条命令红灯复现)再修,禁止先理论后复现。修复以回归测试收口
当前已有 ownership-lost 后暂停工作流的缓解,尚无用户态缺陷实证。**必须走 /diagnosing-bugs**:先建立一条确定性、快速、可红灯的复现命令;不能建立反馈回路则记录尝试并停止,不得先改生产代码。若红灯成立,另开修复票与新上下文

## 证据路径(不用重新调查,票据直接引用)
- .opencode/promotion-review-round1/*.md(U-1/U-2/F3/F4/O1/S7/P8 全部 finding + 根因记录)
- .opencode/promotion-review-round2.yaml 相关证据(若引用深审轮次)
- `.scratch/batch-b/evidence.md`:已追踪的稳定证据快照,含当前代码路径纠偏与验收边界;新 worktree 只依赖此文件
- `.opencode/promotion-review-round1/*.md`、`.opencode/.dag-specs/evidence/*.md`:原始本地评审产物,当前未追踪,仅用于复核来源,不作为跨 worktree 前置
- `.scratch/batch-b/abort-path-contracts.md`:U-1/U-2/mid-stream-stall 的已追踪规格;本地 OpenSpec 原件受 `.gitignore` 约束,不作为跨 worktree 前置

## 工程纪律(仓库铁律 + 本项目惯例)
- 分支: **dev** `feat/**` 或 `fix/**`(AGENTS.md 原文写 main,本项目当前惯例:批 B 基于 dev——dev 领先 main 且为集成层)
- 分支:从最新 **dev** 切票据指定分支;生产 feature 用 `feat/**`,测试/规格债用 `test/**` 或 `docs/**`,均符合 branch-naming ruleset
- PR → dev:Typecheck 门禁;push dev 自动触发全量测试(Typecheck + Unit + E2E×2)
- 测试从包目录跑(packages/opencode 等),禁根目录;typecheck 用 `bun typecheck` 不用裸 tsc
- 每票一个新上下文会话执行(/implement 内含 /tdd),票间清上下文
Expand Down
14 changes: 8 additions & 6 deletions .scratch/batch-a/issues/01-q1-escalation-pending-lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

**Blocked by:** None — can start immediately

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] 节点终态转移(completed/failed/aborted)与取消路径清 escalation_pending
- [ ] wake_reported 在清旗路径上不被触碰(两旗正交测试)
- [ ] 已有 NodeStarted/NodeRestarted 清旗点保持不回退
- [ ] replay/恢复场景下清旗经事件折叠重放一致
- [ ] dag 测试套件 + typecheck 绿
**Completion evidence:** 批次 A 实现与测试随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] 节点终态转移(completed/failed/aborted)与取消路径清 escalation_pending
- [x] wake_reported 在清旗路径上不被触碰(两旗正交测试)
- [x] 已有 NodeStarted/NodeRestarted 清旗点保持不回退
- [x] replay/恢复场景下清旗经事件折叠重放一致
- [x] dag 测试套件 + typecheck 绿
14 changes: 8 additions & 6 deletions .scratch/batch-a/issues/02-q2-delivery-gated-retime.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

**Blocked by:** None — can start immediately

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] skip 合取项落在 re-time 唯一发起点,全 re-time 触发路径逐条覆盖(测试枚举,不只抄规格)
- [ ] 初始升级(deadline ⟹ 首次 wake)不受门控影响
- [ ] 裁决写入后 re-time 能力恢复的测试
- [ ] watchdog 无状态写(仅提案)的断言保持
- [ ] dag 测试套件 + typecheck 绿
**Completion evidence:** 批次 A 实现与测试随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] skip 合取项落在 re-time 唯一发起点,全 re-time 触发路径逐条覆盖(测试枚举,不只抄规格)
- [x] 初始升级(deadline ⟹ 首次 wake)不受门控影响
- [x] 裁决写入后 re-time 能力恢复的测试
- [x] watchdog 无状态写(仅提案)的断言保持
- [x] dag 测试套件 + typecheck 绿
16 changes: 9 additions & 7 deletions .scratch/batch-a/issues/03-q3-node-deadline-extended-event.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

**Blocked by:** 01 — Q1:escalation_pending 裁决旗生命周期闭环(projector 折叠侧写集串行)

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] Schema 定义 NodeDeadlineExtended + 入 EventManifest.Definitions
- [ ] 命令层执行 guard:拒绝时命令失败并携带 typed 错误,编排器可区分拒绝与成功
- [ ] 直写 deadline 旧路径废除(无遗留调用方)
- [ ] projector 纯折叠:无事件发布、无返回值契约依赖
- [ ] 恢复/replay 一致性测试(事件日志重放 ⟺ 活跃态)
- [ ] dag 测试套件 + typecheck 绿
**Completion evidence:** 批次 A 实现与测试随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] Schema 定义 NodeDeadlineExtended + 入 EventManifest.Definitions
- [x] 命令层执行 guard:拒绝时命令失败并携带 typed 错误,编排器可区分拒绝与成功
- [x] 直写 deadline 旧路径废除(无遗留调用方)
- [x] projector 纯折叠:无事件发布、无返回值契约依赖
- [x] 恢复/replay 一致性测试(事件日志重放 ⟺ 活跃态)
- [x] dag 测试套件 + typecheck 绿
14 changes: 8 additions & 6 deletions .scratch/batch-a/issues/04-q3-sdk-regen-consumers.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

**Blocked by:** 03 — Q3:NodeDeadlineExtended durable 事件 + guard 前移命令层

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] SDK 再生脚本执行,生成物提交
- [ ] 事件联合类型包含 NodeDeadlineExtended,消费方编译绿
- [ ] `check:generated`(SDK + client)零 diff
- [ ] 涉及响应/事件形状的 httpapi-exercise 场景已更新(如有)
- [ ] 全量单元测试(含 httpapi 契约)绿
**Completion evidence:** 批次 A 生成物与消费者更新随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] SDK 再生脚本执行,生成物提交
- [x] 事件联合类型包含 NodeDeadlineExtended,消费方编译绿
- [x] `check:generated`(SDK + client)零 diff
- [x] 涉及响应/事件形状的 httpapi-exercise 场景已更新(如有)
- [x] 全量单元测试(含 httpapi 契约)绿
14 changes: 8 additions & 6 deletions .scratch/batch-a/issues/05-s5-workflow-lock-timeout.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

**Blocked by:** None — can start immediately

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] 唯一改动点在 withWorkflowLock 包装层(一行 + 常量)
- [ ] 30s 超限产生 TimeoutException,编排器按既有 error_class 分诊规则处置
- [ ] 无新错误类、无 per-caller 分支的断言
- [ ] watchdog 自续行为在锁超时后仍正确的测试
- [ ] dag 测试套件 + typecheck 绿
**Completion evidence:** 批次 A 实现与测试随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] 唯一改动点在 withWorkflowLock 包装层(一行 + 常量)
- [x] 30s 超限产生 TimeoutException,编排器按既有 error_class 分诊规则处置
- [x] 无新错误类、无 per-caller 分支的断言
- [x] watchdog 自续行为在锁超时后仍正确的测试
- [x] dag 测试套件 + typecheck 绿
12 changes: 7 additions & 5 deletions .scratch/batch-a/issues/06-flaky-stdout-pollution.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

**Blocked by:** None — can start immediately

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] 污染源定位经可复现测试验证(修复前红、修复后绿)
- [ ] run-process 9 项断言不削弱、不删除,本地重复跑(≥5 次)稳定绿
- [ ] ShareNext 的 stdout 污染分量同步修复(计时问题归 07 票)
- [ ] opencode 包测试套全绿(除豁免清单剩余项)
**Completion evidence:** flaky 根因修复与验证随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] 污染源定位经可复现测试验证(修复前红、修复后绿)
- [x] run-process 9 项断言不削弱、不删除,本地重复跑(≥5 次)稳定绿
- [x] ShareNext 的 stdout 污染分量同步修复(计时问题归 07 票)
- [x] opencode 包测试套全绿(除豁免清单剩余项)
10 changes: 6 additions & 4 deletions .scratch/batch-a/issues/07-flaky-sharenext-timing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

**Blocked by:** 06 — Flaky:stdout 污染族根治(同一测试文件,写集串行)

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] 修复走信号等待惯用法;若改预算须附 CI 计时证据
- [ ] 本地重复跑(≥5 次)+ 模拟负载下稳定绿
- [ ] 无新增 Effect.sleep 等待 forked fiber 的反模式
**Completion evidence:** flaky 稳定化与验证随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] 修复走信号等待惯用法;若改预算须附 CI 计时证据
- [x] 本地重复跑(≥5 次)+ 模拟负载下稳定绿
- [x] 无新增 Effect.sleep 等待 forked fiber 的反模式
10 changes: 6 additions & 4 deletions .scratch/batch-a/issues/08-flaky-workspace-timing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@

**Blocked by:** None — can start immediately

**Status:** ready-for-agent
**Status:** closed(PR #186,merge commit `4ddeaf2fc`)

- [ ] 先复现并确认根因(计时 vs 其他),根因记录入票
- [ ] 修复后本地重复跑(≥5 次)+ 模拟负载下稳定绿
- [ ] 无新增固定 sleep 反模式
**Completion evidence:** flaky 稳定化与验证随 PR #186 合入 `dev`,并随 PR #188 通过 main 全量门禁。

- [x] 先复现并确认根因(计时 vs 其他),根因记录入票
- [x] 修复后本地重复跑(≥5 次)+ 模拟负载下稳定绿
- [x] 无新增固定 sleep 反模式
12 changes: 7 additions & 5 deletions .scratch/batch-a/issues/09-promote-dev-to-main.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

**Blocked by:** 01、02、03、04、05、06、07、08 全部合入 dev

**Status:** ready-for-agent
**Status:** closed(PR #188,merge commit `e837dcbfa`)

- [ ] dev 最新 push 的 CI 四项检查全绿(Typecheck、Unit、E2E linux、E2E windows)
- [ ] 豁免清单清零或逐项重新裁决留档
- [ ] PR 描述附批次 A 交付清单(Q1/Q2/Q3/S5 + flaky 根因修复)与两轮深审 PASS 证据链接
- [ ] 合并后 main 可手动 release-fork
**Completion evidence:** dev→main 晋级 PR #188 的 Typecheck、Unit Tests (linux)、E2E Tests (linux/windows) 全部通过并合入。

- [x] dev 最新 push 的 CI 四项检查全绿(Typecheck、Unit、E2E linux、E2E windows)
- [x] 豁免清单清零或逐项重新裁决留档
- [x] PR 描述附批次 A 交付清单(Q1/Q2/Q3/S5 + flaky 根因修复)与两轮深审 PASS 证据链接
- [x] 合并后 main 可手动 release-fork
23 changes: 23 additions & 0 deletions .scratch/batch-b/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# 批次 B 执行台账

**规划基线:** `dev@3e8368f37`(PR #190)

**当前状态:** 规格与票据已就绪;实现代码尚未开始。

## 审计结论

- 批次 A 已经 PR #188 晋级 `main`;残余修复 PR #189 与交接 PR #190 已进入 `dev`。
- U-1/U-2/mid-stream-stall 的 OpenSpec 已完成并通过校验;仓库规定 `/openspec/` local-only,跨 worktree 使用已追踪镜像 `.scratch/batch-b/abort-path-contracts.md`。
- 原始 `.opencode/promotion-review-round1/` 与 `.opencode/.dag-specs/evidence/` 是未追踪本地文件;跨 worktree 统一引用 `.scratch/batch-b/evidence.md`。
- O1 不是直接实现票:离线降级已完成,剩余 LKG 的持久化、键、失效和安全边界需先写小规格。
- S7 只有静态 bug 气味;先诊断,不能复现就无代码收口。P8 维持批 C 的观测候选,不阻塞批 B。

## 串行顺序

1. 01 U-1 → 02 U-2 → 03 mid-stream-stall;02/03 写同一测试文件,禁止并行。
2. 04 F3 → 05 F4;两票只清测试债,不顺带改运行时。
3. 06 O1 规格 → 07 O1 实现。
4. 08 S7 诊断;只有红灯成立才新建独立修复票。
5. 批 B 全部处置 + 批 C P8 观测记录关闭后,执行 09 的 dev→main 晋级与 release-fork。

每票从最新 `dev` 创建符合仓库规则的分支,单独 PR → `dev`,单独新任务执行。票据完成时将状态改为 `closed`,附 PR、merge commit 与验证命令。
53 changes: 53 additions & 0 deletions .scratch/batch-b/abort-path-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 批次 B:abort-path integrity 规格

**Status:** accepted
**Applies to:** 01 U-1、02 U-2、03 Transport mid-stream-stall
**Local OpenSpec source:** `openspec/changes/batch-b-abort-path-contracts/`(仓库规定 local-only;`openspec validate --changes` 已通过)

## 目标

三个边界目前只有实现/注释声明,没有真实失败路径证据:Session fork 嵌套发布失败时的批次回滚、HTTP timeout 对真实连接的取消传播、合法首帧后的逐帧间隔 timeout。本规格只补集成测试;红灯暴露违约时,才允许做对应契约所需的最小生产修复。

## Requirement 1:fork 复制批次原子回滚

系统 SHALL 在 `Session.fork` 的消息/part 复制批次中保持原子性:任一嵌套 durable event 发布失败时,同一外层事务内此前写入的复制事件及其投影全部回滚。

### Scenario:部分复制后嵌套发布失败

- WHEN fork 已创建目标 session,至少一个 message/part 发布完成,随后嵌套发布失败
- THEN fork 调用失败,目标 session 不存在本批复制出的 message/part projections 与 durable copy events
- THEN 源 session 的 message/part 保持不变
- THEN 复制事务外已经提交的目标 Session Created 记录可以保留

**设计裁决:** 必须扩展 `packages/opencode/test/session/fork-batch.test.ts` 的真实 SQLite fixture;adapter-only savepoint 测试不足以证明 EventV2/projector 共用外层连接。

## Requirement 2:provider timeout 取消真实 transport

系统 MUST 在 provider HTTP timeout 到期时,以现有 Transport/Timeout 结束 LLM stream,并取消仍在进行的真实 HTTP response stream,使 provider 端观察到连接或响应体取消。

### Scenario:真实 provider response 超时后仍保持打开

- WHEN loopback provider 已接收请求并返回超过 timeout 仍保持打开的 response stream
- THEN 客户端在有界时间内以现有 `LLMError` Transport/Timeout 失败
- THEN provider 在有界时间内观察到 response cancellation 或等价 request abort

**设计裁决:** 使用真实 `Bun.serve` loopback 与生产 fetch-backed client。以 response cancellation 为确定性主信号,request abort 可作补充;内存 HttpClient 和显式 Fiber interrupt 都不能替代本场景。

## Requirement 3:timeout 约束每个帧间隔

系统 SHALL 将 stream timeout 作为相邻数据帧之间的最大间隔,而不是只覆盖 response headers 或首帧等待。

### Scenario:合法首帧后永久停顿

- WHEN provider 在 timeout 内发出至少一个合法 SSE frame,随后不关闭且不再发送数据
- THEN timeout 前到达的 frame 已交付消费者
- THEN 停顿超过 timeout 后,stream 以现有 Transport/Timeout 失败

**设计裁决:** 使用 fence 证明首帧已交付,再用 TestClock 越过下一帧间隔;本场景验证 stream timing,不重复真实 socket 取消测试。

## 非目标与顺序

- 不要求把 fork session creation 与复制批次合并为同一事务。
- 不改变 timeout 默认值、错误词汇、retry policy 或 provider protocol。
- 01 → 02 → 03 串行落地;02/03 都修改 `packages/llm/test/transport-timeout.test.ts`。
- 若 Bun 在目标 CI 平台无法提供可重复的服务端取消信号,02 停在诊断结论,不能退化为重复断言 Timeout 错误。
Loading
Loading