| 1 | # Session termination / 暂停与恢复机制 |
| 2 | |
| 3 | ## Contract / 契约 |
| 4 | |
| 5 | Reasonix keeps the Go runtime, v4 physical log, SQLite projections and Desktop |
| 6 | Stop RPC. Cancellation now stages explicit message mutations and accepts them |
| 7 | with the terminal facts in one atomic commit. `history/replace` remains available |
| 8 | for import and intentional history edits, but is not the cancellation commit. |
| 9 | `model/context-replace` intentionally retains the exact provider workset. |
| 10 | |
| 11 | 保留 Go 运行时、v4 物理日志、SQLite 投影和 Desktop Stop RPC。暂停清理先生成明确 |
| 12 | 消息变更,再与回合终结事实一起原子提交;导入和显式编辑仍可使用 `history/replace`。 |
| 13 | 暂停不替换整段展示历史,`model/context-replace` 继续保存精确模型工作集。 |
| 14 | |
| 15 | | Owner / 所有者 | Responsibility / 职责 | |
| 16 | | --- | --- | |
| 17 | | `internal/control/termination_policy.go` | Pure legacy cleanup policy, including fallback input, complete tool pairs, LocalOnly and compaction. / 无副作用的既有清理策略,包括真实输入兜底、完整工具对、LocalOnly 和摘要。 | |
| 18 | | `internal/control/termination.go` | Detached plan, turn identity, atomic terminal acceptance and bounded Flush. / 独立计划快照、回合身份、原子终结和有界持久化。 | |
| 19 | | `internal/session/recovery.go` | Deterministic tool/interaction/step closure shared with restart recovery; never reruns a tool. / 运行终结与重启共享确定性收尾,不重跑工具。 | |
| 20 | | `internal/session/transcript_metadata.go` | Bounded input previews and stable identities survive externalized history; retractions repair catalog and reply anchors. / 历史外置后保留输入身份及截断预览,撤回同步修复目录及回复锚点。 | |
| 21 | |
| 22 | The input-preview metadata grows with input identities, not message bodies. |
| 23 | History pages and recent-message windows remain bounded. Synthetic cleanup also |
| 24 | tracks the active turn's committed IDs, so compaction cannot hide messages that |
| 25 | must be retracted; absence from the model working set does not authorize deleting |
| 26 | older display history. Unresolved side-effect records use the existing |
| 27 | `Session.Replace` retention policy before IDs are assigned and events prepared. |
| 28 | |
| 29 | 输入预览元数据随输入身份数量增长,不保留完整消息正文;分页和最近消息窗口保持 |
| 30 | 有界。合成回合还按当前回合已提交的 ID 撤回,避免压缩移走模型上下文后漏删,也 |
| 31 | 不会因旧消息不在模型窗口中而删除旧历史。未决副作用记录在分配稳定 ID、生成事件 |
| 32 | 之前应用已有 `Session.Replace` 保留规则,避免提交后产生额外临时消息。 |
| 33 | |
| 34 | ## Events and ordering / 事件与顺序 |
| 35 | |
| 36 | `message/retract` is required. Its strict payload is |
| 37 | `{"messageIds":["stable-id"],"reason":"diagnostic-only"}`. IDs must be nonempty, |
| 38 | trimmed and unique. Writers sort cleanup IDs. A missing/already retracted ID is a |
| 39 | projection no-op. Later upsert restores the ID at a higher version; raw events and |
| 40 | content blobs are retained. Unknown fields remain errors. |
| 41 | |
| 42 | `message/retract` 为 required 事件。严格载荷如上,ID 非空、无重复且无首尾空白; |
| 43 | 清理写入按 ID 排序。投影对不在当前视图或已撤回的 ID 不操作;同 ID 可由后续 |
| 44 | upsert 以更高版本恢复。原始事件和正文不物理删除,未知字段仍拒绝。 |
| 45 | |
| 46 | Normal termination order is cancellation signal, worker exit, planning, terminal |
| 47 | gate, atomic acceptance, executor synchronization, independent 15-second Flush, |
| 48 | then completion publication. The existing cooperative cancellation grace remains |
| 49 | 15 seconds. Within the batch the order is message changes, model context, tool / |
| 50 | interaction / step closure, recovery state, then turn end. |
| 51 | |
| 52 | 正常顺序为立即发取消信号、等待协作退出、生成计划、进入终结门闩、原子接受、 |
| 53 | 同步 executor、独立 15 秒 Flush、发布完成;协作取消宽限期仍为 15 秒。Batch 内 |
| 54 | 顺序为消息变更、模型上下文、工具/交互/步骤收尾、恢复状态、回合结束。 |
| 55 | |
| 56 | `turn-finalize:<turnID>` identifies the unique terminal operation. The runtime |
| 57 | checks execution generation and open turn while holding its commit gate. The |
| 58 | controller additionally checks the captured execution token. Accepted terminal |
| 59 | retries only flush; persistence failure keeps `recovery_required` and disarms |
| 60 | automatic Goal continuation. Repairs after a closed turn use a deterministic |
| 61 | `turn-repair:<payload hash>` operation and never add another turn end. |
| 62 | |
| 63 | 唯一终结键为 `turn-finalize:<turnID>`。runtime 在提交门闩内检查执行代际及开放 |
| 64 | 回合,controller 还检查执行 token;已接受终结只重试 Flush。持久化失败保持 |
| 65 | `recovery_required` 并停止 Goal 自动续跑。已关闭回合的修复使用确定性的 |
| 66 | `turn-repair:<载荷哈希>`,不重复追加 `turn/end`。 |
| 67 | |
| 68 | Watchdog uses accepted model state, captured input/prefix identities and accepted |
| 69 | compaction summaries. Sealing rejects late business output; it does not prove a |
| 70 | tool process exited. Started tools without a result remain unknown; dispatched |
| 71 | tools without start evidence are not-started. Existing results are not duplicated. |
| 72 | Stop receipts acknowledge acceptance only, and switching another session does |
| 73 | not wait for this session's disk cleanup. Old callbacks retain their session and |
| 74 | turn identity. No polling service or provider-visible diagnostic text is added. |
| 75 | |
| 76 | watchdog 根据已接受模型状态、捕获的输入/前缀身份和摘要封存。封存拒绝迟到业务 |
| 77 | 输出,但不代表工具进程已退出:已启动无结果记 unknown,仅派发无启动证据记 |
| 78 | not-started;已有结果不补写。Stop receipt 仅确认请求已接受,切换其他会话不等待 |
| 79 | 本会话磁盘清理。旧回调保留原会话/回合身份,不新增轮询或模型可见诊断文字。 |
| 80 | |
| 81 | ## Upgrade and rollback / 升级与回退 |
| 82 | |
| 83 | Physical codec stays v4; new sessions use storage revision 2. Readers accept |
| 84 | revisions 1 and 2. A revision-1 writable open validates the log and acquires the |
| 85 | exclusive lease before atomically publishing and syncing revision 2. It does not |
| 86 | rewrite the event log. Read-only open neither upgrades nor repairs. Fault tests |
| 87 | cover rejected leases, invalid logs and failed atomic manifest publication. |
| 88 | |
| 89 | 物理 codec 仍为 v4,新会话 revision 2;新版读取 revision 1、2。旧会话可写打开 |
| 90 | 在日志验证和独占租约成立后原子同步新版 manifest,不改原日志;只读打开不升级、 |
| 91 | 不写修复。故障测试覆盖租约冲突、损坏日志和 manifest 原子发布失败。 |
| 92 | |
| 93 | History projection is version 8, search version 4, recovery projection version 5, |
| 94 | catalog metadata version 3. Old derived caches rebuild on demand. Retraction |
| 95 | expires MVCC rows without resetting version watermarks; changed visible-turn |
| 96 | ordinals get new rows so previous snapshot cursors keep their previous view. |
| 97 | Retracted inputs and replies disappear from current catalog/fork navigation. |
| 98 | |
| 99 | 历史投影版本 8、搜索版本 4、恢复投影版本 5、目录元数据版本 3;旧缓存按需重建。 |
| 100 | 撤回使 MVCC 当前行过期,不重置版本水位;变化的回合序号写新版本行,旧快照仍可读。 |
| 101 | 撤回输入与回复后,当前目录和 fork 导航同步更新。 |
| 102 | |
| 103 | **Do not lower manifest revisions to roll back.** An old executable cannot safely |
| 104 | read revision 2. A code rollback must retain revision-2 decoding and projections, |
| 105 | or restore a complete pre-upgrade backup into a separate location. Do not mix an |
| 106 | old manifest with a new event log. |
| 107 | |
| 108 | **禁止降低 manifest 版本号实现降级。** 旧程序不能安全读取 revision 2。代码回退 |
| 109 | 必须保留新版解码和投影,或将完整升级前备份恢复到独立位置;不得混用旧 manifest |
| 110 | 和新事件日志。 |
| 111 | |
| 112 | ## Verification record / 验证记录 |
| 113 | |
| 114 | Baseline: `b21deef03eb859c2e923f1f6dd8a8ee1b0d4493e`, with the existing decoder and |
| 115 | message-version repair retained. Packages were built from the implementation |
| 116 | working tree before its PR commit; they are local verification artifacts. |
| 117 | The local verification date is 2026-09-16, macOS arm64. |
| 118 | |
| 119 | 基线为上述提交,保留已有解码器与消息版本修复。验证包从 PR 提交前的实现工作树 |
| 120 | 构建,仅作为本地验证产物。 |
| 121 | 本地验证日期为 2026-09-16,平台为 macOS arm64。 |
| 122 | |
| 123 | | Evidence / 证据 | Result / 结果 | |
| 124 | | --- | --- | |
| 125 | | Policy and HTTP bytes / 策略及 HTTP 字节 | Seven fixtures through OpenAI-compatible, Anthropic thinking/signature and Responses adapters compare expected cleanup, new cleanup and persisted reopen requests byte-for-byte. / 七组夹具经三个真实 HTTP adapter 比较原预期、新清理及重开请求,逐字节一致。 | |
| 126 | | Deterministic termination / 确定性终结 | Double Stop, watchdog late output, accepted-before-fsync failure, fallback input, synthetic compaction, side-effect recovery retention and zero pause history replacements pass. / 连续 Stop、watchdog 迟到输出、接受后 fsync 失败、输入兜底、合成压缩、副作用恢复记录和零暂停历史替换通过。 | |
| 127 | | Projections / 投影 | History/search, snapshot MVCC, ID restoration, catalog/recent, fork targets, reply repair, checkpoint and cache-free reopen covered. / 历史搜索、快照、恢复 ID、目录、最近消息、fork、回复修复、检查点和无缓存重开均覆盖。 | |
| 128 | | Old binary / 旧二进制 | Built from baseline: lease held prevents upgrade; after upgrade warm history, cold read and write return unsupported storage version. / 从基线编译:旧租约阻止升级;升级后旧版热缓存、冷读、写入均报不支持版本。 | |
| 129 | | Frontend / 前端 | typecheck, transcript tests and Chromium transcript browser suite passed; no render errors, duplicate nodes or anchor drift. / 类型检查、transcript 单测和 Chromium 浏览器套件通过。 | |
| 130 | | Full root module / 根模块全量 | Latest full invocation passed (control 208.632s, session 113.589s, agent 161.773s, CLI 130.414s). A previous full run failed at the known WSL clipboard timeout; its isolated pass was not counted as a full-suite pass. The final reply-anchor refinement also passed its focused session suite. / 最近全量通过,耗时如左;此前一轮已知 WSL 剪贴板超时及单独重跑记录仍保留,不以单独通过代替全量。最后的回复锚点细化另通过 session 定向套件。 | |
| 131 | | Desktop module / Desktop 模块 | Independent `go test ./...` passed (277.720s); cancellation/cutover/recovery race suite passed (49.662s). The reversed compatibility-message order found in earlier runs was fixed before these passes. / 独立模块全量与相关 race 通过;此前发现的兼容消息反序问题已修复。 | |
| 132 | | Runtime races / 运行时并发 | session/control targeted race passed; the final watchdog-summary and termination race suite passed (11.918s). / session/control 定向 race 通过,最终 watchdog 摘要及终结 race 通过。 | |
| 133 | | Native macOS / macOS 原生 | Production-mode local ZIP exercised renderer→service Stop, old/new session switches, return, continuation, restart and clean exit using a local HTTP fixture. No real vendor credentials used. / 生产模式本地 ZIP 通过 renderer→service 暂停、旧/新会话切换、返回、继续、重启和正常退出,使用本地 HTTP 夹具,无真实厂商凭据。 | |
| 134 | | Windows ARM64 / Windows ARM64 | Passed on the local Parallels Windows 11 ARM64 VM (10.0.26200): native session tests 37.118s, control tests 23.632s, six Desktop regressions 7.630s. The complete portable ZIP passed production-mode renderer/service Stop → old/new conversation → return → continue → restart, unique transcript record IDs, visible reopened content and normal shell/service exit. / 已在本机 Parallels Win11 ARM64(10.0.26200)通过原生 session、control 和六个 Desktop 定向回归;完整便携 ZIP 通过生产模式暂停→旧/新会话→返回→继续→重启,记录 ID 无重复、重开内容可见,壳及服务正常退出。 | |
| 135 | |
| 136 | The local packages are verification evidence, not signed/notarized production |
| 137 | releases. Native runtime reproduction is now covered on macOS ARM64 and Windows |
| 138 | 11 ARM64; Windows x64 hardware was not exercised. Check the task's final result |
| 139 | for module runs and package identities; earlier interrupted/failed attempts are |
| 140 | not counted as passes. |
| 141 | |
| 142 | 本地包仅作为验证证据,不是正式签名/公证发布。现已覆盖 macOS ARM64 与 |
| 143 | Windows 11 ARM64 的原生运行复现,未测试 Windows x64 硬件。最终模块运行结果 |
| 144 | 及包身份以任务最终结果为准;中途失败或中断不算通过。 |
| 145 | |
| 146 | Final tested ZIP: `dist/Reasonix-darwin-arm64.zip`, version |
| 147 | `v0.0.0-termination-local`, source revision `b21deef…+dirty`, SHA-256 |
| 148 | `a3640d502d784194a95e1b96c27eb0ae9f39212eead5698b638e3cb9a6aecd55`. |
| 149 | It was extracted into a fresh directory and passed strict deep codesign |
| 150 | verification before the production-mode renderer/service scenario. The DMG was |
| 151 | built, but this record qualifies the ZIP, not a separate DMG install run. |
| 152 | |
| 153 | 最终验证对象为上述版本和哈希的 ZIP(包含未提交改动),重新解压到干净目录, |
| 154 | 通过严格深度签名结构检查后执行生产模式 renderer/service 流程。DMG 已构建, |
| 155 | 但没有把 ZIP 验证冒充为另一次 DMG 安装验证。 |
| 156 | |
| 157 | Windows follow-up (2026-09-16): all changed source files were SHA-256 checked |
| 158 | against the macOS working tree before the VM build. The repository's complete |
| 159 | `desktop-build.sh windows/arm64` flow produced both the NSIS installer and the |
| 160 | portable archive. The initial NSIS permission failure was resolved by copying |
| 161 | the system-owned toolkit into the dedicated test directory; product code and |
| 162 | the original toolkit permissions were unchanged. |
| 163 | |
| 164 | Windows 补验(2026-09-16):构建前逐一比对所有改动文件的 SHA-256,确认与 macOS |
| 165 | 工作树一致。在虚拟机内执行仓库完整 Windows ARM64 打包流程,生成 NSIS 安装器 |
| 166 | 和便携 ZIP。最初 NSIS 工具目录权限不足,通过复制工具到专用测试目录解决, |
| 167 | 未修改产品代码或原工具目录权限。 |
| 168 | |
| 169 | Tested archive: `dist/Reasonix-windows-arm64.zip`, version |
| 170 | `v0.0.0-termination-local`, SHA-256 |
| 171 | `859f720c74c59c86da62edc4a19bbf34aa166db63e3da0264771337ede253637`. |
| 172 | The archive passed structural verification (463 entries), was freshly extracted |
| 173 | to a dedicated disposable directory, and ran its bundled ARM64 Electron |
| 174 | and Go binaries with no development or service-path overrides. Both the legacy |
| 175 | submit RPC and the display/submission-ID RPC scenario passed; the latter also |
| 176 | waited for the startup overlay to leave and checked visible restored content. |
| 177 | The NSIS installer was built, but an install/uninstall cycle was not performed. |
| 178 | |
| 179 | 实测便携包版本及哈希如上,463 个包条目的结构校验通过,重新解压后直接运行包内 |
| 180 | ARM64 Electron 和 Go 服务,未使用开发模式或外部服务路径。旧提交 RPC 与带展示 |
| 181 | 文本/提交 ID 的 RPC 两条流程均通过,后者还等待启动遮罩退出并确认恢复内容已 |
| 182 | 渲染。NSIS 安装器已构建,但未执行安装/卸载周期。 |
| 183 | |
| 184 | Local evidence is retained separately: Windows build, session/control, |
| 185 | Desktop and native-run logs, plus continued/restarted window screenshots. These |
| 186 | use disposable homes and a loopback HTTP fixture, not user session data or vendor |
| 187 | credentials. No production release is represented by this record. |
| 188 | |
| 189 | 本地另行保留构建、session/control、Desktop、原生运行日志以及继续和 |
| 190 | 重启后的窗口截图。全部使用临时数据目录和回环 HTTP 夹具,没有使用用户会话数据 |
| 191 | 或厂商凭据。本记录不代表正式发布。 |
| 192 | |
| 193 | PR review follow-up: restoring a retracted input in a repair batch without a |
| 194 | live turn now preserves its original turn ownership through checkpoint and |
| 195 | full-log reopen. The regression first failed with a hidden original turn and |
| 196 | then passed after retaining an identity-only tombstone. This follow-up has |
| 197 | focused session/control, race and lint evidence; the package hashes above |
| 198 | predate it and must not be treated as rebuilt final-head packages. |
| 199 | |
| 200 | PR 评审补充:不带活动回合的修复批次恢复已撤回输入时,现在保留原回合归属, |
| 201 | 覆盖检查点及全量日志重开。回归先复现原回合仍被隐藏,再以仅含身份的撤回记录 |
| 202 | 修复。此补充有 session/control 定向、race 和 lint 证据;上方包哈希早于此修复, |
| 203 | 不能作为重新构建后的最终提交包证据。 |
| 204 | |
| 205 | Integration with the ProjectTree/session-recovery changes on `main-v2` retains |
| 206 | their cold-history preparation, complete-batch indexing and authored-preview |
| 207 | rules. The bounded catalog reducer now shares input metadata with the execution |
| 208 | projection, including retracted/restored ownership, while discarding message |
| 209 | bodies and full turn boundaries. All four derived projection versions advance |
| 210 | beyond both branches so an older cache cannot mask either side's changes. |
| 211 | |
| 212 | 与主分支 ProjectTree/会话恢复修复整合后,保留冷历史准备、完整批次索引和用户 |
| 213 | 原文预览规则。有界目录重建器共享执行投影的输入元数据及撤回/恢复归属,同时 |
| 214 | 丢弃消息正文和完整回合边界。四类派生投影版本均超过双方原版本,确保旧缓存不会 |
| 215 | 掩盖任一方的修复。 |
| 216 |