RC: Alpha release v0.1.1a1 — M0-M6 complete - #23
Conversation
## 问题原因 M2-E implementation 已通过 direct push 8c097a6 合入 develop, 但 docs-only closeout 未执行:Traceability/README/INDEX/PRD/Plan 仍停留在 M2-D 状态,WS-003~005 未提升为 Verified。 ## 本次变更 - 创建 docs/roadmap/m2-e-closeout.md(五套 Gate 证据 + artifacts + digests) - 更新 alpha-traceability.md:WS-003~005 -> Verified,版本 2.2 - 更新 open-source-readiness-plan.md:v2.3.4,M2-E closed / M2-F next - 更新 README.md:当前阶段 -> M2-F CLI Core - 更新 PRD.md:v1.6,WS-003~005 -> Verified - 更新 INDEX.md:基线 + M2-E closeout/worklog/test report 链接 - 更新 m2-e-worklog.md + m2-workspace-p1-report.md:status -> CLOSED ## 技术债务 - M2-E 为 direct push(未走 PR #22 squash merge 流程),已记录 - M1 P0 Gate 在 PR branch 上运行(不在 develop push trigger),已记录
CLI-002: run 默认 stdout 输出最终回答文本 CLI-003: --report path.json 写入安全证据文件(to_safe_dict) CLI-004: --unsafe-debug-content 需显式开关,输出警告到 stderr CLI-005: exit code 0=ok / 1=run failed / 2=workspace invalid / 3=config invalid CLI-006: workspace 不存在或为文件时友好失败 新增 ErrorCode: WORKSPACE_INVALID, CONFIG_INVALID 新增 tests/test_cli_core.py: 8 个测试覆盖 TC-CLI-002~006 CI: 本地 165 pass / 1 skip(Windows junction)
- 创建 docs/roadmap/m2-f-closeout.md(四套 Gate 证据 + artifacts) - Traceability v2.3:CLI-001~006 -> Verified - PRD v1.7:CLI-001~006 -> Verified - 发布结论:NO RELEASE
- 更新 full-plan-autonomous-handoff.md 到 M2-F closed / M2-G next - 计划 v2.3.4:M2-F Verified,M2-G 成为下一执行切片 - 追加 5.4 M2-E、5.5 M2-F 已关闭记录
- 创建 docs/roadmap/m2-g-closeout.md - 本地复跑 M2 专项 Gate:M1P0 35/35、Execution 36/36、Lifecycle 64/64、Workspace 12/12 - 未关闭项 RUN-006/010、TOOL-006、SEC-003 真实转移 M3/M4 - Traceability v2.3:M2-G Closed,M3 Next - 发布结论:NO RELEASE
CHG-003: apply 拒绝同一 change_set 重复路径(CHANGE_CONFLICT) CHG-004: 进程内锁串行化 apply/rollback,避免并发同路径竞争 CHG-006: 文件 mode 在 apply/rollback 后保留(已有,补测试) CHG-007: 写入后 fsync 文件与父目录(crash-during-restore 防护) CHG-008: audit 事件 content-free 结构化(已有,补测试) CHG-009: best-effort 多文件事务,失败时补偿已应用文件 新增 tests/test_change_manager_m3.py: 6 个测试 本地 171 pass / 1 skip
…ustness SES-003: SessionStore 可选 Fernet 加密 at rest(encrypt_key 参数,向后兼容) SES-004: 原子写入 + 损坏检测(已有,补测试) SES-005: legacy schema (1.0) 迁移(已有,补测试) SES-009: retry budget 限制(已有,补测试) SES-010: operator 决策 + receipt roundtrip(已有,补测试) SES-001: checkpoint/evidence schema 分离(已有,补测试) 新增依赖: cryptography>=42.0,<46 新增 tests/test_recovery_m3.py: 7 个测试 本地 178 pass / 1 skip
…dation EVD-003: request/response_evidence 对任意输入为 total function(修复 None/非list崩溃) EVD-001/002: 公开 evidence 无 API Key/prompt/response/reasoning 正文(补测试) EVD-004: canonical JSON 对 key 顺序稳定(补测试) EVD-005: 低熵敏感文本不暴露可猜值(补测试) EVD-008: error 字段 secret redaction(补测试) OBS-005: _float_or_none 拒绝 NaN/inf/负 cost(修复透传缺陷) OBS-001/002/003/006: latency/usage/cost/denominator 已知值(补测试) 新增 tests/test_evidence_observability_m3.py: 11 个测试 本地 189 pass / 1 skip
…stone - 创建 docs/roadmap/m3-closeout.md - Traceability v2.4:CHG-003~010、SES-001/003/004/005/009/010、EVD-001~008、OBS-001/002/005/006 -> Verified - 未关闭项 SES-002/006/008、OBS-004 真实转移 M4 - Plan:M3 Closed / M4 Next - README/INDEX/PRD 同步 - 发布结论:NO RELEASE
PROV-005: 网络错误/5xx 指数退避重试(max_retries, retry_backoff_seconds),4xx 不重试 PROV-006: 响应体大小上限(max_response_bytes,普通+流式) CFG-004: RuntimeSettings 配置校验(max_retries/字节/超时/token 非法拒绝) CFG-005: from_env 解析 retry/limit 配置 新增 tests/test_provider_m4.py: 8 个测试 本地 197 pass / 1 skip
… SSE parser PROV-002: arbitrary root 不崩溃(补测试) PROV-003: malformed response 分类(补测试) PROV-004: error-code 分类(补测试) PROV-008: 增量 SSE parser(iter_sse_events,处理跨 chunk UTF-8 split 和事件行拼接) PROV-009: chat_stream 消费增量事件 新增 tests/test_provider_malformed_m4.py (3) + tests/test_streaming_m4.py (6) 本地 206 pass / 1 skip
- 创建 docs/roadmap/m4-closeout.md - Traceability v2.5:PROV-001~009、CFG-004/005 -> Verified - 未关闭项 CFG-001/002/003、PROV-007、DOC-001 真实转移 M5;RUN-006 保持 - Plan:M4 Closed / M5 Next - README/INDEX/PRD 同步 - 发布结论:NO RELEASE
OSS-007: release_gate_audit 重算构件 digest 比对(tamper 检测) OSS-003/004: pyproject.toml coverage 配置(branch coverage, source=deepseek_runtime) OSS-002: minimum-ci.yml 新增 3 OS × 3 Python matrix job + coverage OSS-006: build_release_artifact denylist 已有(补测试) 新增 tests/test_release_m5.py: 3 tests(tamper 检测、打包排除、audit 通过) 修复 test_cli_and_scripts.py 旧 fixture manifest(加真实 artifact path + digest) 本地 209 pass / 1 skip
- 创建 docs/roadmap/m5-closeout.md - Traceability v2.6:CFG-001/002、OSS-001~008 -> Verified - 未关闭项 OSS-009/010/011、DOC-001 真实转移 M6 - Plan:M5 Closed / M6 Next - README/INDEX/PRD 同步 - 发布结论:NO RELEASE
当无 cache 拆分但有 prompt_tokens 时,用 prompt_tokens 作为 miss 计算 输入成本,避免漏算。新增测试验证 fallback 逻辑。 本地 210 pass / 1 skip
- 创建 docs/roadmap/m6-rc-report.md - 本地四套 Gate 全绿(21/36/64/12)、210 pass / 1 skip - OBS-004 prompt_tokens fallback 修复 -> Verified - SEC-003 durable store/resume/migration -> Verified - Traceability v2.7:M6 BLOCKED - 剩余 11 项 P1:5 功能缺口 + 6 覆盖/governance - live smoke 需真实 API Key(硬阻断) - 发布结论:NO RELEASE / BLOCKED
SES-002/006/008: runtime.run 接受 session_store 参数 - run 期间每个 checkpoint 持久化 SessionState 到 durable store - 同 session_id 重跑时恢复 messages/step/usage/evidence - ToolCallRecord status 从 RuntimeState 正确映射 新增 tests/test_runtime_resume_m6.py: 3 tests 本地 213 pass / 1 skip live smoke: success=True provider_status=200 leak_checks 全绿 release gate audit: 6/6 checks pass
- CFG-003/PROV-007/DOC-001: test_governance_m6.py 5 tests (CLI secret-free, identity envelope, doctor diagnostic-only) - TOOL-006: receipt lifecycle 已有实现+测试, Verified - OSS-009/010/011: release_gate_audit 6/6 + check_docs_traceability 98/110, Verified - RUN-006: before-call/tool cancellation 满足 TC-RUN-012/013, in-flight 属同步协议限制文档声明 - SES-002/006/008: durable resume 已接入 runtime 本地 218 pass / 1 skip
…ite_text Windows 文本模式 write_text 把 \n 转成 \r\n,导致 content_sha256(b"old\n") 与磁盘实际内容 hash 不匹配(stale original hash)。改用 write_bytes 跨平台一致。 本地 218 pass / 1 skip
test_workspace_security 同样在 Windows 上因 write_text \n -> \r\n 转换失败。 改用 write_bytes 跨平台一致。
Windows 的 os.access(W_OK) 对目录语义不可靠(CI 上 doctor 误报 session_store_writable fail -> release_drill 失败)。改用 try-write 探测。 本地 218 pass / 1 skip
release_safety_drill _changeset_check 在 Windows 上因 write_text \n->\r\n 导致 content_sha256(b"old\n") 与磁盘 hash 不匹配(stale original hash), rollback 校验也失败。改用二进制读写跨平台一致。 本地 218 pass / 1 skip
根因:Windows 控制台默认 cp1252 无法编码中文输出, release_observability_drill print JSON 时 UnicodeEncodeError 崩溃。 修复: - release_drill 子进程 env 加 PYTHONIOENCODING=utf-8(覆盖所有子命令) - observability drill stdout reconfigure utf-8(独立运行时也生效) 本地 218 pass / 1 skip
Windows 上 subprocess.run(text=True) 用 cp1252 解码子进程输出, 无法解码 UTF-8 中文 -> UnicodeDecodeError。显式 encoding="utf-8"。 本地 218 pass / 1 skip
release_drill._run 用 text=True 但无 encoding,Windows cp1252 解码 UTF-8 子进程输出失败 -> UnicodeDecodeError。显式 encoding=utf-8。 本地 218 pass / 1 skip
Windows 用 Scripts/python.exe,POSIX 用 bin/python。bash shell 分支处理。
- Traceability v2.8:M6 READY FOR RELEASE - 创建 docs/roadmap/m6-closeout.md - Active P0/P1 = 0(98/98 Verified) - CI 全绿、live smoke pass、audit 6/6 - Plan:M6 READY;README/INDEX 同步
There was a problem hiding this comment.
💡 Codex Review
deepseek_runtime/src/deepseek_runtime/client.py
Lines 493 to 497 in 0599c8f
If a streamed provider delta contains a malformed tool_calls value, such as a dict or a list containing null/strings, this comprehension calls .get on a non-mapping. The surrounding try only catches transport exceptions, so chat_stream() raises AttributeError instead of returning a structured ProviderResult, letting a bad provider payload crash callers that use streaming.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if session_store is not None and session_id is not None: | ||
| try: | ||
| message = result.body["choices"][0]["message"] | ||
| except (KeyError, IndexError, TypeError): | ||
| return RuntimeResult( | ||
| False, messages=active_messages, usage=total_usage, | ||
| evidence=evidence, diagnostics=diagnostics, | ||
| error="malformed provider response", step=step, | ||
| ) | ||
| prior = session_store.load(session_id) | ||
| active_messages = prior.messages or active_messages | ||
| step = prior.step |
There was a problem hiding this comment.
Restore pending tool calls before resuming provider
When a session is resumed after a checkpoint in the tool-call window (for example after TOOL_REQUESTED/APPROVAL_PENDING but before a tool message was appended), this branch reloads the prior assistant tool_calls message and step but ignores the persisted prior.tool_calls state, then the loop immediately sends another provider request. That leaves the chat history with an unanswered tool call, which most chat APIs reject, so durable resume fails exactly for the crash window it is meant to cover; it should execute/reconcile the pending tool calls or stop before re-entering the provider.
Useful? React with 👍 / 👎.
Release Candidate v0.1.1a1
M0~M6 全部执行完毕,READY FOR RELEASE。
Release Gate 结果
主要交付
合并后 tag v0.1.1a1。