我们向上游提的缺陷草案。每条都是「实测锚点 + 可复跑判据 + 可直接粘贴的正文」的整页材料, 不做只有结论的转述;编号沿用 issue 草案自身的序号。
| 编号 | 主题 | 日期 | 材料 |
|---|---|---|---|
| #22 | 一条 JS 主线程同时扛 HTTP 控制面与 agent loop,进程巡检每次枚举整张 /proc 表 —— 共享宿主(约 4.9k 进程)上主线程连续约 125 分钟贴 0.99 核;loopback 401 从 2 ms 涨到 0.61–0.76 s,会话列表最长 240 s。卡着时 perf:62% 周期在 syscall、proc_pid_readdir 21.8%、getdents64 13.1%;syscr 约 6.6 万次/秒,等效每秒 6–7 次全表快照。重启只缓和 5–10 分钟。含代码行号、最小复现与四级修法。证据:同一 pid 的 perf 与 /proc/<pid>/io 双采样;公开脱敏版。 | 2026-11-10 | 阅读 #22 草案 含 perf 符号与 syscr 速率 |
| #21 | 3FS vNext EC 7+3 转换后已恢复数据出现截断/内容不符 —— 5 节点 20 target、10 CR 链(每条 1 target)+10 EC 链、k=7/m=3;开启 ec_worker 存量转换并 GC 后,zst 抽样 14/20、data-restic 20/20、escrow 1/1 内容不符,一个 77,724,651 B 文件在 3FS 上变成 1,048,576 B。单 target 故障读测试显示丢 2 个 EC target 仍可读、再丢 2 个 CR target 即 EIO ⇒ 读路径仍依赖 CR 单副本。含环境、时间线、复现路径,以及 on-disk chunk 元数据定位到的具体代码路径。 证据:ZFS 备份完好,已按 shard checksum 回灌;本页为上游 triage 材料。 | 2026-10-24 | 阅读 #21 草案 含环境/时间线/复现步骤 |
| #20 | mch 机队架构升级:durable task graph + session control-plane split —— mch20 106MB / session/list 44s;mch16 415MB / 11h 无事件;mch1 T8 A→B→C 串行等待。提案:会话数据面/控制面分离(增量索引/侧车)+ durable task graph/lease + Task Card/写集锁/merge queue;先 Phase 0 只读影子,不重启、不切活跃 turn。目标门:热列表 p95≤1s、cycle time -20%、零重复执行。不强制 64,不把 child 数当效率。完整设计: ops/dsh/mch-fleet-supervisor/architecture-upgrade-20261020.md。 | 2026-10-20 | 阅读 #20 RFC 公开摘要;Phase 0 只读。 |
| #19 | session/list 重会话 119s–>200s 等待;cursor 字段未被使用(是否补分页待定) —— mch10 97 sessions 一次 119,334ms;另一次 >200s 客户端超时;mch25 两次 120s 读超时累计 240,096ms,不是单次。列表只读头部/投影缓存,不回放 79MB 日志。CI 3,000 会话约 3s 与本机版本/存储/负载未对齐,不能据此推断 97 行应远低于此;主线程排队是优先验证的假设。cursor 当前无调用方传入,补分页/删字段待评估;离主线程/缓存/compaction 是候选。相关 #6161(仍 open)、#1757、#5379。证据: /home/infra/log/dsh-invariants-rc2-highcap-20261019.log。 | 2026-10-19 | 阅读 #19 草案 按 DSH 反馈收紧:先 profile;分页待评估。 |
| #18 | 撞上轮次上限时 harness 直接把 goal 判 blocked —— 驱动层 ctx.goals.block(…) 绕过工具层自己公布的「同一阻塞条件连续 ≥3 轮才可标 blocked」契约,「用满预算」与「真受阻」在数据面/提示词面/用户面完全同形;附带 hasRoundCap 只排除 0、且 create 与 update 两条写入路径不同源承接 #17(上限从哪来)说「到点之后怎么落」: dsh-goal-round-driver/lib/index.js:125-130 命中 roundsStarted >= maxGoalRounds 即 ctx.goals.block(… , {code:"round-limit", message:"Goal reached its configured limit of N rounds."});而同仓 dsh-tool-goal/lib/index.js:196 给模型的正文是「同一阻塞条件连续 ≥3 轮才可标 blocked」、:200/:360 用 blockedAfter=3 与 GOAL_TOOL_BLOCK_THRESHOLD 在工具层把关 ⇒ 内部路径不受这条约束、且模型收到的是 <goal_blocked> 收尾指令(:95)却根本没有阻塞条件可讲。:209-211 hasRoundCap(v){return v!==void 0 && v!==0} 只排除 schema 零填充,:340(update/edit)用它、:295(create)却用 === void 0 ⇒ 两条写入谓语不同源。验收判据五条:P1 两条路径终态字段必须可辨;P2 驱动层上限路径不许静默绕过阈值/授权;P3 同批取值下 create/update 接受集一致、非正数与非整数 loud 拒;P4 停机后有用户可执行的「提高上限并继续」;P5 尺子带阴性对照。诚实边界:出厂原件逐行静态核实(行号已核),未做受控运行时复现;create 的 schema 是否另有 .int().positive() 未逐字核。 | 2026-09-30 | 阅读 #17 草案 本条承接件:仓内 ops/dsh/goal-round-cap/README.md(issue #18 草案,含逐行指针与验收判据;外发页尚未生成) |
| #9 | 关停期投影注销竞态:一次可预期的清理异常把整个 web 服务打死 —— ctx dispose 先删掉 inbox 投影注册,仍在飞的 AbortSignal.onAbort 再走 cancel → clear → current() 读到 undefined 直接 throw,而顶层 uncaughtException 一律 process.exit(1)链条五环,每一环都从出厂原件逐行核到行号:① 注册是 ctx.effect(dsh-agent-loop:1559 → dsh-session-projection:68-102),disposer 随 ctx dispose 运行、把 key 从 registrations 删掉;② 读侧 stateOf(dsh-session-projection:127-131)对缺 key 宽容(返回 undefined);③ 关停 ⇒ 注册没了;④ 拆完之后才跑的 abort:dsh-subagent-in-process-driver:200 → dsh-agent-loop:817 cancel → :94 clear → :85 nextStep → :175 current() → :177 throw;⑤ dsh-app-boot:3811 onException → proc.exit(1)。三环缺一都不会打死服务,所以三处都可独立修。★ 同仓反证:本机 ops/dsh/gateway/gateway.mjs:249-258 对同一事件用的是 uncaughtException (kept alive) —— 一个仓里两个组件策略相反。实测 6 次 / 3 户(zyj2 3、mch1 2、mch8 1),每次都紧跟一条 stop-cancel … reason=timeout,且每次换 session UUID ⇒ 时序竞态,不是数据问题。顺带证伪一条假设:曾以为「崩溃留下半截会话毒死启动」,36 席扫 4,801 件后推翻(逐字节副本启动正常 3/3、崩溃后 2 秒就起来、那批半截件从未被 resume、且子代理会话里 23–27% 本就是半截形态)⇒ 半截不能当崩溃指纹,别再走这条路。诉求:①关停期清理幂等(读不到 pending 就是"没有待处理输入")②调 dispose 次序或让 abort 订阅随同一 effect 注销 ③顶层区分关停期与运行期异常(关停期降级为记录),参考 gateway 的 kept-alive。诚实边界:链条是静态逐行核出,没有受控复现拿到运行时交错证据;stable/master 未测。 | 2026-09-30 | 阅读草案 含五环逐行链条、抛点/顶层处理器原文、复跑命令与诚实清单 |
| #8 | 每次起子进程都阻塞地探一次 systemd scope —— spawn 的 inclusive 从空闲时的 0.3% 涨到 16.8%,其中 spawnSync 自耗 9.0%(纯阻塞,事件循环停摆)带 JS 符号的 CPU profile( SIGUSR1 进 inspector,不重启现场,500 µs 采样)实测:空闲实例连发 6 次 session/list 后,spawn inclusive 0.3% → 16.8%,probeLinuxScope 9.0%,spawnSync self 9.0%(4,074 ms);而"枚举 / header / 投影 / 排序 / 编码"合计 <2% 且两臂持平 —— 这条路径的成本中心在"起进程",不在"读数据"。调用链:spawn ← spawnSync ← probeLinuxScope@dsh-subprocess-local/lib/index.js:73 ← selectContainmentMode:1384 ← spawn:1356,即每次 spawn 都跑一轮 systemd-run --user --scope … systemctl --user show …。代码里有 linuxDeepProbePassed 缓存位,实测未生效(未逐分支验证)。影响面是所有起子进程的功能(会话列表、工具执行、workflow/subagent 启动…),不只 session/list;因此单列,与 #7 的 /proc 轮询是两个独立缺陷,叠加才导致"零字节"。#7 修好而本件不修,列表仍要 3.6–4.4 s。诉求:能力探测进程级缓存一次;从同步路径上挪走(异步探测 / 启动时预热)。含三臂对照(全部自跑)、inclusive 归因表、复跑命令与验收判据。 | 2026-09-30 | 阅读草案 含三份原始 .cpuprofile 的分析口径与复跑命令 |
| #17 | goal 的轮次上限是「模型自己填的工具参数」 —— 用户端零可见、零可配,长任务会在第 N 轮静默停机(界面上就是 Rounds: 60/60)先纠一个常见误判: 60 不是 DSH 的缺省值。DSH 侧只有两层:插件 schema defaultMaxGoalRounds: z.number().default(256)(packages/goal/goal/src/index.ts:187)与部署配置 $DSH_HOME/cordis.patch.yml 里由 ops/dsh/set-goal-rounds.py 写入的 10000;解析式是 request.maxGoalRounds ?? defaultMaxGoalRounds(:158-161)⇒ 模型只要传了 create_goal(max_goal_rounds=…),前两层一起失效,而该参数在工具描述里只有一句「Optional positive safe-integer limit」,无下限、无与部署默认的任何比较(packages/goal/tool-goal/src/index.ts:216-219 / :227)。判别实验(扫 25 户两通道共 20,457 份会话持久化件,100% 可读,其中 155 个会话带 goal):上限为 60 的 25 个会话 25/25 都能对上一条显式传参;上限为 256 的 14 个只有 2 个显式、其余 12 个取 schema 缺省;另一户同一会话三次 create 全都没传参 ⇒ 2026-09-20 16:39 得 256(早于补丁写入)、当晚 23:27 与 09-21 09:50 各得 10000(晚于补丁 + 重启)—— 部署配置这条链是好的,被静默旁路的是它。模型自选的取值跨 5 个数量级(3 … 100000),实测 15 个会话真撞墙(判据 = 真实 block 事件里 blockedReason.code == "round-limit",其中上限 60 撞 4 次)。三条缺陷面:①零可见(dsh-client-ui-* 包里无一处引用 maxGoalRounds,用户只有 /goal 的一次性只读输出 Rounds: n/max)②零可配(/goal 自述无轮次参数;dsh-api-session-controller/lib/index.js 里 goal 出现 0 次、宿主侧没有写接口;edit/resume 还要求人类轮次)③撞墙后只有一行英文 Goal reached its configured limit of N rounds.、没有任何续期入口。诉求:把轮次上限做成用户可读可写的设置;让模型不能无声压过部署默认(移除该参数 / 加下限 / 低于默认时要求确认);round-limit 停机给「提高上限并继续」的动作。含量具 ops/dsh/scan-session-goals.py(12 断言自测)与英文正文。 | 2026-09-22 | 阅读草案 含两张与证据同源的图、代码指针与英文正文 |
| #16 | 输出上限截断 tool call 时 harness 静默丢弃且不续跑 —— 一次响应撞上单次输出上限(max-tokens)时,dsh-llm 会把这次响应里的全部 tool-call 丢掉、dsh-agent-loop 立即结束该 turn、子代理判 failed;全程没有一处告诉模型「你的调用没执行」,界面只提示「发送『继续』可让模型接着输出」——而被丢弃的调用不在对话里,「继续」也不会重放它。实测:同一父会话 17 个子代理里 4 席死于此路径,4/4 都带一个写不完的 write(参数 54,534 / 69,047 / 83,842 / 90,252 字符,JSON 全部未闭合),而同一请求的输入上下文只用了 6.2%–10.2%;4 席合计 19.8 分钟墙钟、128,001 输出 token、交付 0 件,父代理据此误记成「耗尽上下文」,纠正动作打在了「读文件太多」这个不相干的一侧。同题第三席改成「先写较小骨架再迭代」即 completed(阳性对照)。诉求:让这件事成为 harness 的自发行为 —— ①被丢弃的调用必须留痕(模型可见)②有界自动续跑,而不是让用户手打「继续」③文案与归因分清「输出上限」与「上下文窗口」④给大文件一条分片写的路(write 今天只有 file_path+content,没有 append)。 | 2026-09-22 | 阅读草案 含三张与证据同源的图、代码指针与英文正文 |
| #15 | 请在设置页暴露「子代理并发度」 —— workflow 并发上限 maxConcurrentAgents 今天不可配,缺省值被静默压到 min(16, CPU-2)判别实验:home 配置层写 48 + 只重启该户 ⇒ 运行期探针实测最大重叠 16(补丁前)/ 64(把代码兜底改成 512 后),48 从未出现;而同刻 --dump-config 显示 maxConcurrentAgents: 512 / disabled: false。结构性原因:真跑的引擎由 agent preset 组合实例化(presets/standard/agent.cordis.yml:222 的条目 config 里只有 provider),而 $DSH_HOME/cordis.patch.yml 只叠在 host/profile 层,host 面同 id 行还被随包 web app disabled: true。缺省值:z.natural().default(0) + config===0 ? Math.min(16, max(1, availableParallelism()-2)) —— 256 核机器上就是 16,整份引擎文件只有 2 处宿主侧出现该字段(无打印/校验/告警),GUI 与日志都不显示有效值。升级面:内核按 [app-dir]/app-alpha-<版本> 目录安装 + 原子翻 symlink,新目录是上游原件 ⇒ 手工修补失效、并发静默掉回 16,而实例体检(活性 + 入口码)看不出来。含四条缺陷面的原始命令与原始输出、结构性原因与英文正文;本次请求(用户要求):把「子代理并发度」做成 DSH 设置页里的一项设置(能改、写进真正生效的那一层、显示有效值、与 per-run 预算联动校验)。 | 2026-09-20 | 阅读草案 含运行期探针原始输出与英文正文 |
| #13 | 长时高扇出 workflow 作业在 DSH 上不可靠:单进程单主线程封顶吞吐 + run 没有可恢复的持久化身份(进程重启后父会话只拿到「outcome is unknown」)面一(缺陷):run 只活在进程内注册表( dsh-tool-workflow/lib/index.js:38 的 new Map()),结果只经同步 await run.result 交付并在 finally 里 dispose(:231-262),写进会话流的收尾记录只有 {runId, stopReason}、不含终值(:76-82);模块自述 background collection remains deferred(:10)。面二(功能诉求):随包已带 out-of-process 接缝(dsh-subagent/lib/types/out-of-process.js、dsh-subprocess/-local、dsh-acp/-app)却只装配 spawn/fork 两个 in-process driver(dsh-base/cordis.patch.yml:331-339),随包已有三处 new Worker() 先例(workflow 编排、run_code、代际校验)。2026-09-16 两次实测(10:14:45 / 10:29:51,已脱敏):363 项 / 256 在飞的裁决 run 被每用户网关自愈重启腰斩,10 分钟只落 12 项,只能靠外部副作用反推。原 #13 + 原 #14 已合并为一条。 | 2026-09-16 | 阅读草案 含时间线原文、装配锚点、验收判据与英文正文 |
| #12 | 控制面一元 RPC 在主线程饱和时被饿死:同一份约 0.5 s CPU 的 session/list 被拉到 34 s – ≥45 s,越过 45 s 即触发自愈重启、腰斩在途工具调用权威只读重放(经网关固定 rpcId 6 发):wall 504.6–638.5 ms(中位 517.4)、主线程 CPU 375.5–533.6 ms(74.4–84.0% of one core)、 rows=660、1,578,662 B(sha 6/6 相同)。隔离副本实测放大律:K=1→8 并发把单发 wall 从 561.0 抬到 2152.7 ms(3.548×),而单发 CPU 反降到 0.690×,同窗 canary 中位 3.2 ms ⇒ 895× 对照;strace 实测一发 list = 3333 次 fs 调用 / 665 行 = 5.012 次每会话。看门狗 RED 37 条 = 读超时 20(45010–45045 ms)+ 算完但超预算 6(34.3–44.4 s)+ 网关 refused 10 + reset 1;腰斩累计 4 会话 / 20 条。关停三点对照(systemd 复刻件实测):修复前(无 cancel + 0.3 s)403 ms / wrote_cancel=no / repair=yes;补丁 launcher(默认 6 s)2690 ms / yes / no;显式 cancel 2134 ms(cancel 11.2 ms)/ yes / no ⇒ 0.3 s 硬杀才是丢结果的原因、有界宽限正是解药(第四轮「宽限无用」的结论只对 headless 载体成立,已被第五轮推翻)。生产当刻配对样本已补齐(user-d 户 17:48–18:07:主线程 ≈99.8%、轻请求 canary p50 174 ms、list 180 s / 90 s 超时;同刻看门狗三轮判「慢 ≠ 坏,不重启」⇒ 该户未被重启,旧码会重启 ≥2 次);user-a 侧常驻仪器 STALL_CAUGHT=0,仍在等。含未排除项(libuv 线程池 / 响应侧背压)与英文正文。 | 2026-09-15 | 阅读草案 含代码 file:line 与只读复现 |
| #11 | 每个 session/follow 都注册 { global: true } 监听器:global 绕过作用域过滤,每事件成本随跟随流数线性增长用随包真实 cordis 实测(非复刻模型):每监听器每事件约 1.62 µs,线性拟合 r² = 1.0000,64 条跟随流下单次事件仅「选取」就要约 105 µs;且 selected_per_emit 恒等于 N,直接证明这些 global 监听器没有经过作用域过滤。进程内每个会话的事件都要付这笔钱。自包含,含零依赖复现脚本。 | 2026-09-14 | 阅读草案 含零依赖复现脚本 |
| #10 | 进程是唯一的并行单位:同一 Host 内所有会话与所有 subagent 共用一条 JS 主线程 实测 JS 主线程贴到 98.2% of one core,而整个进程只用掉 2.03 个核(宿主 256 核、load1 9.7);随包只有 in-process subagent 驱动,加并发只排队不提吞吐——8 秒窗口内 K=1/4/8 分别完成 2/4/0 次 RPC(K=8 那 8 次是排空后才完成的);同刻无关的定开销请求 p99 变差 3.6×、样本数掉 51%,单次停顿 831.9 ms。含零依赖复现探针与核验报告。 | 2026-09-14 | 阅读草案 含零依赖复现探针与核验报告 |
| #9 | /api/remote.mux 心跳判死是静默的:漏 2 次 Pong 即 terminate(),无日志 / 无指标 / 无 Close 帧实测容忍窗口 6.0 秒(最后被回答的 Pong 之后三跳 2 秒);判死不发 Close 帧,浏览器只见 1006 空 reason 并显示「自动重连中」;Ping 与所有会话流的数据帧共用同一条 TCP(写路径单链、不看 bufferedAmount)。含零依赖复现探针。 | 2026-09-13 | 阅读草案 含零依赖复现探针 |
| #8 | session/list 是 fail-closed 的全量扫描:一个脏目录就让整张列表消失用户报「历史会话不见了」的真实成因:侧边栏整张列表只由这一次 RPC 提供,七类脏状态任一都会让它整张抛(工作区还在、会话全空),且「编码检查失败」被按进程缓存、重启前不可恢复;接口无分页无缓存,实测 2957 行 / 1.28 MB / 9.7–11.9 秒。 | 2026-09-13 | 阅读草案 含可跑 oracle 与最小补丁 |
| #7 | session/list 永不返回一元 RPC 上零字节挂起 ≤300 秒、连响应头都没有,而同一实例的兄弟接口 100 毫秒返回(已排除 11 项原因)。 | 2026-09-08 | 阅读草案 |
| — | 模型不可路由锁死发送框(stale routable composer lock) 模型 catalog 一旦进入 loading/error,旧的 routable:false 残留,发送按钮 disabled 直到整页刷新。 | 2026-09-05 | 阅读草案 |
| 1–6 | 上游本体缺陷 6 条合集 含复现步骤与对照测试。 | 2026-09-05 | 阅读合集 |