
Apache Maka 侧聊 Side Chat 简化消融实验以 209 项回归为边界的安全减码方法论【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka本篇技术指南以 Apache Maka 仓库中 side-chat-ablation-2026-09-11.md 实验快照为主体系统还原 PR #4901 针对「侧边对话」Side Chat / Side Conversation执行恢复机制所做的一次逐项消融ablation实验在固定对照提交上对生产源码做单项变换用 209 项既有测试判定每处「简化」到底能不能删。读者读完将掌握一套可复用的「以测试为边界的安全减码」方法论——包括实验分支、原型脚本与一次性 npm 命令的组织方式、单项消融与组合消融的判定规则、用输入探针补齐测试覆盖缺口的做法以及简化候选合入主线后如何完成真实 Electron 验收。背景为什么对 Side Chat 做消融实验Maka 的 Side Chat侧边对话允许用户在不打断主任务的情况下追问和只读探索其核心实现位于 use-quote-companion.ts当前约 1747 行配套的底层工具分散在features/workbar/tools/side-chat/目录下的quote-companion-core.ts、quote-companion-context-compaction.ts、quote-companion-panel-state.ts等模块中。这套机制在正常路径之外还必须处理一类极其棘手的异步恢复场景消息在排队queued与临时投影transient projection之间流转、Host 侧 Turn 的准入admission回执可能迟到、观察observation中断期间后继 Turn 可能已经完成、重连后需要恢复消息与 Turn 的归属。正因为如此实现中积累了执行身份恢复、窗口外 Turn 定向读取、终态证据保留、pending Map 清理、队列到临时消息的投影等多处防御性逻辑——它们看上去「重复」但每一处都对应一个曾经踩过的时序坑。本次实验的出发点很直接原实现不是这次实验找到的最简单写法。实验的目标不是证明「行数越少越好」而是用既有测试回答一个具体问题——哪些简化可以安全合入哪些简化一旦删除就会破坏恢复语义。方法与复现对照提交 内存转译 逐项变换实验设计的关键约束是「可复现、可归因、不污染生产」对照提交a450cc7e7675a4fbe2f7e141d2b5ddcc4668c7e3。所有单项变换都基于同一个对照提交保证每项结果可独立归因。环境Nodev24.14.0复用仓库现有的 npm / esbuild不添加任何依赖。变换方式每次只对同一个对照提交做一项生产源码变换通过 Node 加载钩子在内存中转译不覆盖源码或构建产物。所有单项验证通过后再最终测试五项简化组合combined-simplification。测试基线基础消融固定对照提交中的 hook 测试其余测试使用已构建的同版本产物。覆盖范围包括 hook、临时消息投影、服务适配、transcript range、执行 IPC、observer、队列状态和共享 Composer共209 项。探针隔离另用两类输入探针检查原测试遗漏详见下文「覆盖缺口探针」。探针与基础结果分别记录不把「删除代码后仍然通过测试」当作等价证明。实验脚本和一次性 npm 命令归档在本地分支experiment/side-chat-ablation-20260911未推送。下述验证记录对应 9 月 11 日的实验快照生产简化及回归测试随报告单独提交不包含一次性实验脚本。在实验分支、依赖和 workspace 构建产物准备好后运行npm run prototype:side-chat-ablation npm run prototype:side-chat-ablation -- baseline combined-simplification npm run prototype:side-chat-ablation -- --interactive脚本路径apps/desktop/src/renderer/features/workbar/tools/side-chat/side-chat-ablation.prototype.mjs。每项打印 JSON 结果变体、问题、非空行变化、退出码、通过数、失败数和失败测试。⚠️ 解读注意变体失败属于实验数据必须查看逐项退出码不能把外层脚本正常退出理解为所有变体通过。此外实验分支故意将 Node-only 一次性脚本放在被研究模块旁边但不要将这个脚本或 npm 命令合入生产——renderer 架构检查会拒绝它的 Node 环境依赖。单项消融结果13 个变体逐项判定下表均使用同一组209 项原有测试每行是独立变更不是逐步累积删除。这是整个实验的核心证据逐项列出变体 ID / 变更 / 通过失败 / 决策与证据变体 ID变更通过 / 失败决策与证据baseline原实现209 / 0对照no-execution-recovery删除执行身份恢复207 / 2保留取消消息不能清理观察中断期间的中间后续 Turn 不能恢复no-targeted-recovery删除窗口外 Turn 定向读取208 / 1保留A→B→C 中断后只有最新 C 的窗口不足以恢复 Barm-started-receiptstarted 回执直接激活 Turn205 / 4保留原判断迟到回执可能重新激活已完成 Turn或影响更新的活动 Turnno-retained-terminal-proof仅信当前窗口不查本地保留的终态208 / 1保留B 离开窗口不代表它没有完成no-durable-retirement不从 pending Map 清理已有持久化消息205 / 4保留持久化身份必须退出本地待处理投影unbatched-executions所有身份一次发给 Host208 / 1保留65 个身份必须拆成 641Desktop 上限仍为 4096no-terminal-admission-replay终态恢复不重放 admission208 / 1保留重连需要先恢复消息与 Turn 的归属no-queue-shadow删除队列到临时消息的投影209 / 0拒绝新增 Host 编辑探针失败原测试覆盖不足no-eager-transcript-read由 observation-ready 统一触发首次读取209 / 0采用减少 9 行移除重复初始读取no-dead-admission-branch删除早返回后的不可达 admission 分支209 / 0采用减少 6 行one-pending-reconciliation集中 own-Turn 过滤和 pending 清理209 / 0采用减少 10 行调用者无需重复过滤single-receipt-read-exit回执读取成功/失败共享后续判断209 / 0采用减少 10 行且修复读失败绕过保留终态的问题shared-query-validation两个 IPC 查询复用身份参数校验209 / 0采用减少 5 行保留独立查询和传输分批shared-recovery-updates恢复循环逐条复用归属/删除 helper209 / 0拒绝虽减少 25 行但重复扫描历史、逐条调度状态更新未做性能基准测试combined-simplification合并上述五项采用的变更209 / 0采用合计减少 40 行保留批量恢复更新从结果中提炼的三条方法论「测试通过」不等于「等价」no-queue-shadow、shared-recovery-updates两个变体在 209 项原有测试下都是 209 / 0但一个被拒绝探针发现覆盖缺口、一个被拒绝结构性成本重复扫描历史 逐条调度状态更新且未做性能基准。减少行数不是唯一选择标准。失败数会暴露语义边界凡是动到「执行身份恢复」「started 回执判断」「pending 退休」「admission 重放」的变体都会损失 1~4 项测试——这些失败恰恰是恢复语义的精确坐标。分批边界是硬约束unbatched-executions变体把 65 个身份一次发给 Host 导致 1 项失败证明 64 条传输分批是必须保留的传输契约而不是实现细节。分批与上限的源码证据分批约束可以在当前主线的 runtime-host-session-execution-ipc-main.ts 中找到对应实现常量DESKTOP_MESSAGE_QUERY_MAX_ENTRIES 4_096约第 133 行定义了 Desktop 侧单次查询的身份输入上限两个 IPC handlersessions:queryCancelledMessages与sessions:queryMessageExecutions都通过requiredMessageIds(messageIds)做统一参数校验该校验同时拒绝非数组、长度超过 4096、含非法身份以及重复身份约第 1051-1057 行校验通过后查询以MESSAGE_QUEUE_MAX_ENTRIES64为步长分批转发给 Hostfor (let from 0; from normalizedMessageIds.length; from MESSAGE_QUEUE_MAX_ENTRIES)。这正是消融表中shared-query-validation采用两个 IPC 查询复用校验但保留独立查询和传输分批与unbatched-executions保留65 个身份必须拆成 641两条结论在源码层面的落点。对应的批量边界回归测试位于 runtime-host-session-execution-ipc-main.test.ts其中queryMessageExecutions的 mock 会断言input.messageIds.length MESSAGE_QUEUE_MAX_ENTRIES。覆盖缺口探针测试没测到的两类输入原测试覆盖不足恰恰是no-queue-shadow差点被误删的原因。实验用两类输入探针专门补测探针原实现对应变体发现Host 将排队消息从queued follow-up改成Host-edited follow-up209 / 0删除队列投影208 / 1本地临时消息仍显示旧文本不能直接删除队列投影已保留 B 终态、B 离开窗口迟到 started(B) 的定向读取拒绝208 / 1共享读取出口209 / 0原 catch 直接重新激活 B简化后读失败只表示没有新增证据仍检查保留的终态第一类探针揭示了「队列 → 临时消息投影」的职责当 Host 编辑了已排队消息的文本时本地乐观队列里的临时消息必须同步更新否则界面会一直显示旧文本。这正是no-queue-shadow变体在原有测试全绿的情况下仍被拒绝的根本原因。第二类探针的价值在于原实现的 catch 分支在定向读取失败时会直接重新激活 Turn B——而 B 明明已经有保留的终态、并且已经离开窗口。简化后的「共享读取出口」把读失败解释为「没有新增证据」随后继续检查本地保留的终态从而修复了这条绕过路径。这两类输入此后已进入正式 hook 回归测试加强现有队列测试的 Host 编辑输入、将迟到回执测试参数化为读取成功与失败两种情形实际测试总数由 209 增为210且没有为实验脚本新增测试框架。生产候选40 行非空行的去向五项被采用的简化合并为combined-simplification合计减少40 行非空行落到三个生产文件use-quote-companion.ts非空行 1677 → 1642。统一 pending 清理、统一读取出口删除重复读取和不可达分支。保留了所有权恢复、定向历史读取、终态证据、队列投影及批量更新。runtime-host-session-execution-ipc-main.ts非空行 1038 → 1033。共享requiredMessageIds校验不改变身份规则、重复检查、4096 上限或 64 条传输分批。quote-companion-retry.test.ts覆盖上述 Host 编辑和读取失败场景当前文件中的回归用例围绕 hostTurn 状态机、steering、异步 compaction 终态互斥等时序展开。从当前 use-quote-companion.ts 的导入面可以直观看到被保留的机制都落在了哪些共享契约上activeHostTurn与chatTurnActivity来自application/contracts/session-executionarmLiveTurn、retainLiveTurn、reconcileLiveTurnBuffer等来自maka/ui的LiveTurnBuffer而projectQueuedTransientMessages、mergeTransientMessageProjection、reconcileTransientMessages来自 transient-message-projection.ts——后者的注释明确定义了「队列缺失不是取消或送达证明」这正是「队列投影不能删」这一结论的契约依据。验证与限制9 月 11 日快照实际候选重新构建后210 / 210项相关测试通过。Desktop main 构建、renderer 构建、Desktop 完整 typecheck、根 lint / format 检查、Desktop knip、git diff --check全部通过。Renderer 构建仍提示部分 chunk 超过 500 kB入口和第三方声明校验通过。该提示不是这次消融的性能测量。Renderer 架构 checker 的 103 项 fixture 测试通过移出一次性脚本后当前树与对照提交的架构检查通过。明确未做全仓测试、真实 Electron 断连/多后续消息手工验收、穷举异步时序。因此不能据此声称所有竞态已消除或实现已达到理论最简。9 月 12 日主线合并复核适配 transcript window 重构实验快照合入主线时面临一次重要上下文变化主线已删除旧的 Turn-ID history 导航并完成 Renderer transcript window 重构。复核工作同步主线12d3fb9332保留了上述五项简化并做了如下适配定向恢复改用新接口通过现有 HostlistTurns取得firstSequence再使用新的loadAround/loadAfter读取到目标终态仍受 settlement 时限约束不将缺少位置或回复视为完成。settlement 实现迁址迁入 session-message-settlement.ts更新调用方并删除旧实现与冗余内部转发。没有新增 Host 协议也没有恢复主线删除的导航接口架构清单同步移除了旧的 platform-to-legacy 依赖。补充用例跨页终态、缺少索引位置用例。清理旧dist并重新构建后Desktop 全量2527 / 2527、共享 UI419 / 419测试通过全仓 build / typecheck、lint / format、Desktop 与 UI knip、103 项架构 fixture 和相对主线的架构检查通过。此次相关回归为 209 项计数变化包含主线替换旧 transcript 测试。review 闭环逐项核对 PR #4901 的 3 条讨论评论、18 次 review 提交和 6 个行内线程。6 个线程均已关闭其中正常 handoff 的 P1 已由 reviewer 撤回迟到回执、终态/多后继恢复、pending 真正退休、64-ID 分批、等待 Host 准入均有实现和回归覆盖。review 正文提出的窗口外回复恢复也已按主线新接口重新验证。诚实的边界仍不声称完成真实 Desktop 的 Enter / ShiftEnter、多条追问、编辑/重排/撤回及断连重连手工验收独立人工批准也尚未获得。线程关闭不等同于界面验收或批准合并。9 月 12 日最新主线与真实 Desktop 验收最终合入主线83aa12a29c57e82bfe807e0913a35a90881cf6d0保留主线的SessionExecutionProjection、activeHostTurn和共享LiveTurnBuffer。迟到 admission 只证明归属不能覆盖 Host 的当前执行快照没有增加执行调度器或新协议。实际发现与修复真实验收逼出的缺陷回执丢失后的取消清理回执丢失后取消证明需要释放对应 admission已持久化或 owned 的消息也需要释放 admission 槽位否则消息恢复了、Composer 仍不能正常继续发送。新增 cancelled / owned 两条回归。普通后继消息不再依赖steeringEventIdProjector 现在从普通 durable user 恢复归属Desktop observer 在队列条目消失时查询现有 HostqueryMessageExecutions区分消费、取消和未决并在后继内容事件前发布归属。队列消失本身不再被当作撤回。该缺陷独立于 reviewer 在旧提交上已撤回的正常 handoff P1。断连期间终态 seed 与空队列断连期间 B/C 均完成后重连虽恢复回复旧队列仍可能显示 B。现在终态 seed 也会发布权威空队列并先恢复 admission / queue、再发布终态内容普通用户消息、空队列及事件顺序均有回归。Electron 主窗口拖放防护主窗口的捕获阶段 drop 防护会吞掉 Composer 内部拖放。队列改用专用 MIME 和目标标记主窗口允许该目标上的队列拖放验收使用真实 PlaywrightdragTo。问题question归位到所属 Turn截图发现初始问题落到回复后方。Admission、started 和 ownership recovery 现在将临时问题绑定到 Host Turn立即启动的 next-turn 追问、跨到后继 Turn 的 steering 会从待发送显示归位。ChatView 按消息实际归属的 Turn 放置问题完成、断连或后继开始不再把问题挪到回复之后。真实 hook → ChatView 回归先复现失败再验证发送回执 / admission 先后、历史读失败、终态、后继切换以及 raced steering 的 admission / ownership recovery 两条路径。所有 reviewer 评论核对表再次读取 PR #49013 条讨论评论、18 次 review 提交、6 个行内线程6 个线程均已 resolved。以下同时核对线程内容与 review 正文未将 resolved 状态当作实现正确性的证据意见本轮核验迟到 started(B) 不能重新激活已经完成的 B包括 B 在窗口外或读取失败执行状态只来自 Host projection定向恢复与保留终态回归通过正常 queued handoff P1保留 reviewer 的历史撤回结论最新主线实际 handoff 缺陷按上节单独修复并验收终态 successor 重连 admission以及 A→B→C 中间 B 归属恢复终态 seed 未决 ID 的 owned / cancelled / pending 查询两条已完成回复均恢复Durable twin 必须真正退出 pending Mapunknown ownership 仍可见复用reconcileTransientMessages仅传入侧聊实际可显示的 own-Turn durable 消息执行查询遵守每批 64 个 IDDesktop 输入上限 4096现有 IPC 边界分批65 个混合结果、重复/非法 ID、4097 个 ID 回归通过Follow-up 必须等待 Host admission两种 placement 均传{ waitForHostAdmission: true }服务适配测试覆盖仅在 review 正文提出的窗口外已完成 B 回复恢复现有 Turn index 的firstSequence transcript range 分页定向读取缺少位置/终态不算完成共享 transient 生命周期保留侧聊自己的 fork/quote/可见历史边界共用 projection / reconciliation 实现旧文件已迁移并删除未引入第二套 Host 执行权威实际 Desktop Enter / ShiftEnter、多条追问、编辑/重排/撤回、断连重连新增一个真实 Electron 窗口验收以下场景全部通过waitForHostAdmission: true的调用形态可以在 workbar-services-adapter.test.ts 的服务适配测试中看到如{ messageId: message-next, text: later }, { waitForHostAdmission: true }它保证 follow-up 只有在 Host 完成消息准入后才进入执行避免乐观排队与 Host 执行快照错位。验收与验证结果9 月 12 日真实 Electron 窗口验收由 side-chat-followups.spec.ts 承担它在隔离用户目录中运行实际 Electron main/preload、Host 和 renderer使用确定性 fake model。完整场景链为长回复中 Enter 排入三条消息 → 编辑 → 原生拖动重排 → 撤回 → ShiftEnter → 提升队列条目 → 完成两条普通后继 →关闭真实 Desktop transport、保留运行中的 Host让外部 Host client 在观察间隙完成两条后继再恢复观察断言两条回复可见、队列为空且无 Stop。该测试同时保护主窗口 drop 监听器与 main/preload 重连线路状态组合仍在低层回归中。E2E 总预算随最新 main 从 34 增为 35只新增一个窗口测试没有增加重试或延长时限。最新 Desktop 全量2565 / 2565、共享 UI426 / 426通过其中侧聊 hook63 / 63。Projector / observer75 / 75通过全仓 build / typecheck、lint / format、Desktop / UI knip、103 项架构 fixture、相对最新 main 的架构检查及 E2E budget 检查通过。最终真实 Electron 验收1 / 1通过约 11 秒四张截图已查看有序问题、普通后继回复、重连后两条回复与空队列均符合预期。这是自动化应用验收不代表独立人工批准。本地证据位于apps/desktop/e2e/test-results/side-chat-followups-Side-C-aa834-Host-handoffs-and-reconnect/trace.zip、side-chat-steering.png、side-chat-queue.png、side-chat-settled.png、side-chat-reconnected.png。复现命令先在根目录构建cd apps/desktop npx playwright test --config e2e/playwright.config.ts side-chat-followups.spec.ts遗留基线问题如实记录Host 全量仍有一项基线测试竞态不能称为全仓测试全绿1924 项中1911 通过、1 失败、12 跳过。production Host publishes and retires an implementation child patch的 fake provider 在约 0.1 秒内用完 5 次 PTY Read抛出PTY child did not publish its input response并断开 HTTPPTY 随后约 0.5 秒正常输出READY和CHILD_PTY_OK:ping但模型重试仍读到原工具结果最终触发 5 秒 terminal deadline。独立进程复现相同现象加载追踪所涉及的 693 个 tracked 源文件逐字节与上述 main 相同另外两个为构建生成的 model metadata / pricing 文件没有加载本 PR 修改的 projector。首次默认并发全量还出现过 Bash sandbox 测试超时该项单独运行通过。本轮未修改无关 Host 夹具、放宽时限或用重试掩盖失败。规范审查未发现硬性违反需求审查及实际验收中发现的上述问题均已修复并覆盖回归。GitHub 的独立人工 approval 仍待取得最终合并由人工决定。结语这份实验快照的复用价值这份归档文档的价值不止于 PR #4901 本身它示范了一条可以在其他复杂异步恢复模块上复用的减码路径锁定对照提交 → 每项变换独立可归因 → 用测试与探针双轨判定 → 把「拒绝」和「采用」连同证据一起存档 → 合入前用真实 Electron 验收兜底。尤其值得记住的三条边界是测试全绿不代表可以删探针会揭穿行数更少不代表更好shared-recovery-updates的教训传输分批与准入等待属于跨进程契约简化永远不能越过它们。相关文档side-chat-ablation-2026-09-11.md核心实现use-quote-companion.ts、runtime-host-session-execution-ipc-main.ts投影契约transient-message-projection.ts、session-message-settlement.ts回归测试quote-companion-retry.test.ts、runtime-host-session-execution-ipc-main.test.ts真实验收side-chat-followups.spec.ts【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考