better-dsh 0.0.0 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +294 -4
  3. package/control-prompt.md +37 -0
  4. package/cordis.patch.yml +53 -0
  5. package/docs/00_adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  6. package/docs/00_adr/0002-masking-is-presentation-only.md +15 -0
  7. package/docs/10_plans/A2A-messaging-channel-test-archive.md +256 -0
  8. package/docs/10_plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  9. package/docs/10_plans/dashr-blueprint-review.md +201 -0
  10. package/docs/10_plans/dashr-blueprint.md +561 -0
  11. package/docs/10_plans/dashr-compaction-window-and-archive.md +307 -0
  12. package/docs/10_plans/dashr-profile-layer-feasibility.md +367 -0
  13. package/docs/10_plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  14. package/docs/10_plans/dashr-security-sandbox-analysis.md +187 -0
  15. package/docs/10_plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  16. package/docs/10_plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  17. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  18. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  19. package/docs/10_plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  20. package/docs/10_plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  21. package/docs/10_plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  22. package/docs/10_plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  23. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  24. package/docs/10_plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  25. package/docs/10_plans/recallable-compaction.md +147 -0
  26. package/docs/10_plans/spike-tag-repro.mjs +102 -0
  27. package/docs/10_plans/upstream-analysis.md +128 -0
  28. package/docs/50_test-reports/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  29. package/docs/50_test-reports/kernel-provisioning.md +44 -0
  30. package/docs/50_test-reports/repl-kernel-provisioning-test-report.md +87 -0
  31. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-local-test-report.md +81 -0
  32. package/docs/50_test-reports/upstream-dsh-0.1.2-alpha.5-report.md +93 -0
  33. package/docs/50_test-reports/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  34. package/docs/50_test-reports/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  35. package/docs/50_test-reports/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  36. package/docs/50_test-reports/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  37. package/docs/50_test-reports/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  38. package/docs/50_test-reports/v0.1.8d_artifacts/README.md +138 -0
  39. package/docs/50_test-reports/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  40. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  41. package/docs/50_test-reports/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  42. package/docs/50_test-reports/v0.1.8d_artifacts/functions.json +592 -0
  43. package/docs/50_test-reports/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  44. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  45. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  46. package/docs/50_test-reports/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  47. package/docs/50_test-reports/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  48. package/docs/50_test-reports/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  49. package/docs/50_test-reports/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  50. package/docs/50_test-reports/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  51. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  52. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  53. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  54. package/docs/50_test-reports/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  55. package/docs/50_test-reports/v0.2.0b_artifacts/hashline-probe.md +5 -0
  56. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  57. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  58. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  59. package/docs/50_test-reports/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  60. package/docs/50_test-reports/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  61. package/docs/50_test-reports/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  62. package/docs/50_test-reports/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  63. package/docs/50_test-reports/v0.2.1d-/345/256/236/346/265/213/346/212/245/345/221/212.md +67 -0
  64. package/docs/50_test-reports/v0.2.1e-P1-/345/256/236/346/265/213/346/212/245/345/221/212.md +136 -0
  65. package/docs/50_test-reports/v0.2.1ef-dev-audit-report.md +73 -0
  66. package/docs/50_test-reports/v0.2.1f-plugin-shipped-ui-patches/345/256/236/346/265/213/346/212/245/345/221/212.md +102 -0
  67. package/docs/60_exploration-and-research/cordis-research.md +350 -0
  68. package/docs/60_exploration-and-research/dsh-web-profile-package-map.md +186 -0
  69. package/docs/60_exploration-and-research/dsh-web-ui-slot-system-research.md +310 -0
  70. package/docs/60_exploration-and-research/dsh-webui-strip-boundary-research.md +300 -0
  71. package/docs/60_exploration-and-research/ios-chat-app-bridge-research.md +324 -0
  72. package/docs/60_exploration-and-research/web-frontend-composability-research.md +191 -0
  73. package/docs/REPL-/345/267/245/345/205/267/350/260/203/347/224/250-/346/210/252/346/226/255/350/257/212/346/226/255.md +110 -0
  74. package/docs/adr/0001-bridge-tool-layer-not-service-layer.md +14 -0
  75. package/docs/adr/0002-masking-is-presentation-only.md +15 -0
  76. package/docs/distro-blueprint.md +81 -0
  77. package/docs/dsh-webUI-with-rlm-mode.png +0 -0
  78. package/docs/plans/A2A-messaging-channel-test-archive.md +256 -0
  79. package/docs/plans/code-mode-vs-rlm-ipython-comparison.md +137 -0
  80. package/docs/plans/dashr-blueprint-review.md +201 -0
  81. package/docs/plans/dashr-blueprint.md +561 -0
  82. package/docs/plans/dashr-compaction-window-and-archive.md +307 -0
  83. package/docs/plans/dashr-profile-layer-feasibility.md +367 -0
  84. package/docs/plans/dashr-sandbox-escalation-semantics-gap.md +171 -0
  85. package/docs/plans/dashr-security-sandbox-analysis.md +187 -0
  86. package/docs/plans/dashr-surface-invariant-and-omp-imports.md +97 -0
  87. package/docs/plans/ipython-kernel-interactive-interface-test-report.md +152 -0
  88. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft.md +146 -0
  89. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v3.md +50 -0
  90. package/docs/plans/kernel-refactoring/Dash-IPython-Control-Prompt-draft_v4.md +79 -0
  91. package/docs/plans/kernel-refactoring/Dash-vs-PrimeAgent-systemprompt-toolcatalog-comparison.md +138 -0
  92. package/docs/plans/kernel-refactoring/RLM-system-prompt-injection-gap-report.md +161 -0
  93. package/docs/plans/kernel-refactoring/V0.1.5-development-plan.md +109 -0
  94. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_dsh.md +50 -0
  95. package/docs/plans/kernel-refactoring/actinoable-surface-to-llm-in-agent-runtime_prime.md +113 -0
  96. package/docs/plans/recallable-compaction.md +147 -0
  97. package/docs/plans/spike-tag-repro.mjs +102 -0
  98. package/docs/plans/upstream-analysis.md +128 -0
  99. package/docs/repositioning-and-rebranding.md +102 -0
  100. package/docs/v0.1.8-improved-/345/256/236/346/265/213/346/212/245/345/221/212.md +142 -0
  101. package/docs/v0.1.8-/345/256/236/346/265/213/346/212/245/345/221/212.md +193 -0
  102. package/docs/v0.1.8b-/345/256/236/346/265/213/346/212/245/345/221/212.md +96 -0
  103. package/docs/v0.1.8c-/345/256/236/346/265/213/346/212/245/345/221/212.md +127 -0
  104. package/docs/v0.1.8d-/345/256/236/346/265/213/346/212/245/345/221/212.md +150 -0
  105. package/docs/v0.1.8d_artifacts/README.md +138 -0
  106. package/docs/v0.1.8d_artifacts/code-mode-repl-only.observation.md +74 -0
  107. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.jsonl +3890 -0
  108. package/docs/v0.1.8d_artifacts/dsh-session-session-4a293388-9ae1-474b-87a0-9e17bb556d94.w-sample-0435.jsonl +544 -0
  109. package/docs/v0.1.8d_artifacts/functions.json +592 -0
  110. package/docs/v0.1.8d_artifacts/skills-catalog.snapshot.md +30 -0
  111. package/docs/v0.1.8d_artifacts/tools-sdk.output-schemas.json +1236 -0
  112. package/docs/v0.1.8d_artifacts/tools-sdk.python.txt +592 -0
  113. package/docs/v0.1.8d_artifacts/tools-sdk.typescript.txt +516 -0
  114. package/docs/v0.1.8d_artifacts/wire-vs-transcription.diff.md +54 -0
  115. package/docs/v0.1.8e-/345/256/236/346/265/213/346/212/245/345/221/212.md +224 -0
  116. package/docs/v0.1.9a-/345/256/236/346/265/213/346/212/245/345/221/212.md +168 -0
  117. package/docs/v0.2.0b-/345/256/236/346/265/213/346/212/245/345/221/212.md +123 -0
  118. package/docs/v0.2.0b_artifacts/f2probe/Cargo.lock +7 -0
  119. package/docs/v0.2.0b_artifacts/f2probe/Cargo.toml +6 -0
  120. package/docs/v0.2.0b_artifacts/f2probe/src/bin/messy.rs +8 -0
  121. package/docs/v0.2.0b_artifacts/f2probe/src/main.rs +4 -0
  122. package/docs/v0.2.0b_artifacts/hashline-probe.md +5 -0
  123. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.lock +7 -0
  124. package/docs/v0.2.0b_artifacts/slowprobe/Cargo.toml +7 -0
  125. package/docs/v0.2.0b_artifacts/slowprobe/build.rs +4 -0
  126. package/docs/v0.2.0b_artifacts/slowprobe/src/main.rs +13 -0
  127. package/docs/v0.2.1-/345/256/236/346/265/213/346/212/245/345/221/212.md +110 -0
  128. package/docs/v0.2.1b-/345/256/236/346/265/213/346/212/245/345/221/212.md +86 -0
  129. package/docs/v0.2.1c-/345/256/236/346/265/213/346/212/245/345/221/212.md +66 -0
  130. package/lib/client/index.js +473 -0
  131. package/lib/index.d.ts +736 -0
  132. package/lib/index.js +11518 -0
  133. package/lib/kernel-env-hxaihi9C.js +195 -0
  134. package/lib/kernel-env.d.ts +80 -0
  135. package/lib/kernel-env.js +3 -0
  136. package/lib/py-sdk-BCaOGYz7.d.ts +125 -0
  137. package/lib/py-sdk-CbgYiX8O.js +691 -0
  138. package/lib/py-sdk.d.ts +2 -0
  139. package/lib/py-sdk.js +3 -0
  140. package/package.json +325 -4
  141. package/scripts/kernel-provision.mjs +35 -0
  142. package/index.js +0 -3
@@ -0,0 +1,13 @@
1
+ fn main() {
2
+ let mut total: u32 = 0;
3
+ for i in 0..10 {
4
+ total += i;
5
+ }
6
+ let label: u32 = "out-of-range-anchor";
7
+ println!("{total} {label}");
8
+ let _unused = 1;
9
+ let _also = 2;
10
+ let _third = 3;
11
+ let _fourth = 4;
12
+ let _fifth = 5;
13
+ }
@@ -0,0 +1,110 @@
1
+ # v0.2.1 实测报告(挂载核验:工具面 + REPL + MCP 桥接)
2
+
3
+ - 部署:commit `06e516a`(describe `v0.2.0c-3-g06e516a`),版本 `0.2.1`,profile web
4
+ - 部署位 `~/.dsh/profiles/web/node_modules/@pgmi-builds/better-dsh/lib/index.js` 与工作区 `dashr/lib/index.js` **md5 逐字节一致**(`a5490f0b635f6dfc9109b3ed026d2298`,构建于 Sep 1 00:50)——运行态与工作区 lib 同步,非陈旧部署
5
+ - 被测内容:本轮为「挂载核验」而非功能特性验收——REPL 挂载态、工具面 mask 不变式、MCP 桥接 best-effort 语义、control/catalog prompt 的 hint 到位情况
6
+ - 实测人:被测 Dash Agent 运行时本体(第一人称),第一人称 `eval` 探针直接读 `dir(tool)`
7
+
8
+ ## 部署核验(实测前置)
9
+
10
+ - 源码版本 `0.2.1`(dashr/package.json),工作树 HEAD `06e516a`;`git describe` = `v0.2.0c-3-g06e516a`。
11
+ - 工作树有未提交改动(`dashr/src/fallbacks/*` 删除、package.json/build-client 修改等,与 v0.2.1 fallbacks vendoring Path B 对齐);但 `dashr/lib/index.js` 已构建且与部署位 md5 一致,**lib 面代表运行态**。
12
+ - mask 名单在 lib 内(`MASKED_TOOL_NAMES` / `WIRE_MASKED_NAMES`,`src/index.ts:166`):`skill`、`send_message`、`report`、`list_agents`、`subagent`、`subagent_fork`、`interrupt_agent`、`workflow`、`ralph` 九名。
13
+
14
+ ## §1 REPL 挂载(✅ 正确)
15
+
16
+ - [x] `eval` 传输工具在位,跑在真实 IPython kernel(`sys.version` = **3.14.4**;README 文档的 managed venv 默认 CPython 3.11 未命中——当前用宿主 python 或显式 `DASHR_KERNEL_PYTHON`,非缺陷,见 O1)。
17
+ - [x] 会话持久化(state codification)成立:一笔 cell 赋的 dict 探针在下一笔 cell 原样读回。
18
+ - [x] `tool` 命名空间类型 `_DashrBindingHolder`;`__dashr_injected__` 在位(兼容面未动)。
19
+ - [x] `dir(tool)` 返回 **24 个排序绑定名、零 dunder**(introspection 契约 F9 成立)。
20
+ - [x] `eval` 自排除成立:`'eval' in dir(tool)` = `False`(self-call prevention,spec 唯一例外)。
21
+
22
+ ## §2 工具面 mask 不变式(⚠️ 一处回归)
23
+
24
+ - [x] 三桥在位:`agent`、`agent_message`、`agent_workflow`(registry 工具,非手写桥 schema)。
25
+ - [x] `llm_completion` 在位。
26
+ - [x] hashline 编辑家族 `edit`/`undo_last_edit` 在位;URL 包装 `read`/`write`/`grep`/`glob` 在位。
27
+ - [x] mask 九名中 **8 名双面零出现**:`skill`、`send_message`、`report`、`list_agents`、`subagent_fork`、`interrupt_agent`、`workflow`、`ralph`。
28
+ - [x] **回归**:`subagent` 双面泄漏——wire 工具声明在列(签名 `{description, prompt, run_in_background?}`,无 `mode`,即**宿主原生 subagent**,非 dashr `agent` 桥),且 `'subagent' in dir(tool)` = `True`。
29
+ - v0.2.0b 报告明确记录「mask 九名双面零出现」,本轮 `subagent` 回潮,属 **v0.2.0c→v0.2.1 区间引入的回归**。
30
+ - 部署 lib 与工作区同步(md5 一致),排除「陈旧部署」解释——是运行期 mask 未生效,非名单缺项。
31
+ - 最可能机制:mask 接线(`src/index.ts:1036-1039`)对整表 `restrict({deny})` 抛错后逐名降级,`subagent` 单名 `restrict` 抛「non-restrictable layer」被 catch 静默跳过(唯一静默跳过路径)。**宿主层根因待确认**(见建议 1)。
32
+
33
+ ## §3 MCP 桥接 best-effort + 非平坦定义(✅ 语义正确)
34
+
35
+ - [x] wire 面 14 个 MCP 工具(3 server:`orch-a2a` / `web-reader` / `zai-vision`),**0 个进 REPL 绑定**——自动桥接按 `isFlatBindableName` 机械跳过,符合 spec「Non-flat names SHALL be skipped」。
36
+ - [x] best-effort 的「能力不丢」成立:这 14 个 MCP 工具仍以**直接工具调用**形式可达(wire 声明在列),只是不能在 cell 内 `tool.<name>` 命中。
37
+
38
+ ### 「非平坦」的精确口径(纠正常见误读)
39
+
40
+ `isFlatBindableName`(`src/py-sdk.ts:447`)四条件**同时**满足才叫「平坦(flat-bindable)」:
41
+
42
+ 1. 匹配 `^[A-Za-z_][A-Za-z0-9_]*$`(纯 ASCII 标识符);
43
+ 2. 不以 `_` 开头;
44
+ 3. 非保留字(ECMAScript ∪ Python 并集);
45
+ 4. 非 5 个保留绑定全局(`console`/`__dsh_main__`/`__builtins__`/`__name__`/`__debug__`)。
46
+
47
+ **`__` 中缀本身不构成非平坦**——`__` 是合法 Python 标识符字符。实测:
48
+
49
+ - `'mcp__server__tool'.isidentifier()` = `True`(纯 `__` 中缀、无连字符 → 合法,可平坦绑定);
50
+ - 真实 MCP 名 `mcp__orch-a2a__a2a_agents` 的 `isidentifier()` = `False`。
51
+
52
+ **真正的元凶是连字符 `-`**(server 段 `orch-a2a`/`web-reader`/`zai-vision`),不是 `__`。所以「包含 `__` 就叫非平坦」是常见但不精确的 shorthand:`__` 是 MCP 命名约定的**作用域分隔符**,而让它非法的是名字里混进的 `-`(及任何非 `[A-Za-z0-9_]` 字符)。
53
+
54
+ ## §4 prompt hint 到位情况(✅ 已说明,属事实局限,非 defect)
55
+
56
+ 用户的判定标尺:hint 缺失 → defect/discrepancy;hint 已在而运行期确实做不到 → 事实局限。**结论落在后者**。
57
+
58
+ - [x] **hint 在位**。system prompt 的「Calling tools from the scripting pad」段(=`dashr:tool-catalog` 节的 `REPL_BRIDGE_INSTRUCTIONS`,`src/py-sdk.ts:616`)逐字给出:
59
+ > Tool names that are not plain identifiers (for example MCP names with hyphens or `__` infixes) have no `tool.<name>` member — call those as direct tool calls.
60
+ - [x] 运行期确实如此(§3 已证:14 MCP 工具 0 绑定,仅直接调用可达)。**文档与实现一致,是已声明的边界,不是缺说明的 defect。**
61
+ - [~] 次要观察 O2:hint 只在 **catalog 段**(`dashr:tool-catalog`)给出;**control 段**(`dashr/control-prompt.md`,「Tools inside a cell」写的是「every native tool is a member of the `tool` object」)**未提**非平坦例外。二者同在 system prompt、且 control 段的「native tool」措辞与 MCP 工具不在同一范畴,故不算自相矛盾;但若未来 control 段独立渲染(脱离 catalog 段),hint 会随 catalog 段一起消失——记录为提示性观察。
62
+
63
+ ## §5 eval 工具描述与行为不一致(❌ discrepancy)
64
+
65
+ - **现象**:`eval` 的 model-facing 描述承诺「top-level `await` and `return` work」——`EVAL_DESCRIPTION`/`EVAL_CELL_PARAM_DESCRIPTION`(`src/index.ts:205-217`),control 段 `control-prompt.md:8` 同文。运行期顶层 `return` 是 SyntaxError。
66
+ - **复现(本会话第一人称)**:cell `x = 41; print(...); return "cell finished"` → `SyntaxError: 'return' outside function`(`_DashrTopLevelReturnChecker` 于 AST 访问期抛出,`src/bootstrap.ts:231-250`);去掉 return 即正常。行为有测试固化:`test/runtime.spec.ts:92`「rejects a top-level 'return' as a SyntaxError, like a native IPython cell」。
67
+ - **机制**:kernel 按纯 IPython REPL 语义运行 cell——module scope(globals=locals)、`PyCF_ALLOW_TOP_LEVEL_AWAIT` 编译 + `eval`/`await` 执行模块协程(`src/bootstrap.ts:255-280`);顶层 `return`/`yield` 由 checker 显式判 SyntaxError,嵌套函数/类/λ 内 return 语义保留(与原生 Python 一致)。
68
+ - **根因**:描述文本是旧设计残留——blueprint(`docs/plans/dashr-blueprint.md:499`「top-level return = rewriter 改写为 `_DashrReturn`(BaseException)」)在 08-19 原生语义重构后**未随实现同步更新**;实现侧注释(`src/python.ts:6`、`src/bootstrap.ts:257-260`)写的是正确语义。**contract 对模型撒谎:承诺了 kernel 刻意拒绝的特性。**
69
+ - **影响**:模型按描述在 cell 内写顶层 `return`(本会话即发生),白费一轮往返。
70
+ - **await 条款核实(非 discrepancy)**:描述中「top-level `await` works」行为为真——kernel 确以 `PyCF_ALLOW_TOP_LEVEL_AWAIT` 编译并运行模块协程;且该能力是环境特性而非纯 Python(实测见会话讨论),故保留该条款必要且准确,仅 `return` 条款需修正。
71
+
72
+ ## 结果
73
+
74
+ **总体判定:REPL 正确挂载;工具面存在 1 处回归(`subagent` 泄漏)+ 1 处描述不一致(eval 顶层 `return` 承诺与行为相悖,await 条款属实);MCP 桥接 best-effort 有文档说明、属事实局限而非缺陷。**
75
+
76
+ ### 通过项
77
+
78
+ | # | 项 | 证据 |
79
+ |---|---|---|
80
+ | P1 | REPL 挂载 | eval 传输在位、IPython 3.14.4、dict 探针跨 cell 持久、`dir(tool)` 24 名零 dunder |
81
+ | P2 | 三面例外不变式 | `eval` 自排除(`'eval' in dir(tool)`=False) |
82
+ | P3 | 桥接家族 | `agent`/`agent_message`/`agent_workflow` + `llm_completion` + hashline `edit`/`undo_last_edit` + URL 包装四件套在位 |
83
+ | P4 | MCP best-effort | wire 14 MCP 工具 → 0 REPL 绑定;能力经直接调用保留 |
84
+ | P5 | 非平坦语义 | `isFlatBindableName` 机械跳过;`__` 中缀合法(实测 `isidentifier()=True`)、连字符是元凶(实测 `False`) |
85
+ | P6 | hint 到位 | catalog 段逐字声明非平坦例外,与运行期一致 |
86
+
87
+ ### 观察与欠账
88
+
89
+ | # | 级 | 观察 |
90
+ |---|---|---|
91
+ | D1 | **P2(回归)** | `subagent` 双面泄漏(wire + REPL),v0.2.0b「mask 九名零出现」→ 本轮回潮;部署 lib 同步排除陈旧部署;疑 `restrict` 单名降级静默跳过,宿主层根因待确认 |
92
+ | O1 | 记录 | kernel Python 3.14.4,README managed venv 默认 3.11 未命中(宿主 python 或显式 `DASHR_KERNEL_PYTHON`);非挂载缺陷 |
93
+ | O2 | 提示 | 非平坦 hint 只在 catalog 段(`dashr:tool-catalog`);control 段(`control-prompt.md`)措辞「every native tool」未提例外。当前二者同屏无矛盾;若 control 段未来独立渲染则 hint 可能失陪 |
94
+ | O3 | 提示 | hint 原文「hyphens or `__` infixes」并列举例略宽:`__` 中缀单独是合法标识符,真正非法的是 `-`。措辞方向正确(真实 MCP 名两者兼有),不算错误,但可收紧为「non-identifier characters such as hyphens」 |
95
+ | D2 | **描述不一致** | eval 描述承诺「top-level `return` work」,运行期为 SyntaxError(`_DashrTopLevelReturnChecker` 显式判错,`test/runtime.spec.ts:92` 固化);旧 rewriter 设计残留文本未随 08-19 原生语义重构更新(`src/index.ts:205-217`、`control-prompt.md:8`)。await 条款实测为真,不属此 discrepancy |
96
+
97
+ ### 建议
98
+
99
+ 1. **D1 回归定位**:在宿主层复核 `tools.restrict({deny:['subagent']})` 为何抛错/被跳过——确认 `subagent` 是否落在 non-restrictable 层(对比 v0.2.0b 到 v0.2.1 的 fallbacks vendoring 是否改变了该工具注册层)。修复优先级高于本轮其它项。
100
+ 2. O3 的一行措辞收紧:把 bridge instructions 里的 `hyphens or \`__\` infixes` 改为 `non-identifier characters (e.g. hyphens)`,避免模型把 `__` 误读为禁用符。
101
+ 3. O2 若在意,可在 `control-prompt.md` 的「Tools inside a cell」补半句非平坦例外,与 catalog 段互为印证。
102
+ 4. **D2 契约修正**:`EVAL_DESCRIPTION`/`EVAL_CELL_PARAM_DESCRIPTION`(`src/index.ts:205-217`)与 `control-prompt.md:8` 的「top-level `await` and `return` work」改为「top-level `await` works(kernel 以 `PyCF_ALLOW_TOP_LEVEL_AWAIT` 编译并运行模块协程,同 IPython cell);顶层 `return` 是 SyntaxError——cell 以 module scope 运行」。await 条款保留(行为为真,且该能力非纯 Python,正需向模型声明)。
103
+
104
+ ## D1 后续处理(2026-09-01,v0.2.1b)
105
+
106
+ **根因已确认(源码核实 + 会话日志实证)**:standard preset(`dsh-agent-presets/presets/standard/agent.cordis.yml`)的 `tool-subagent` 行配置 `modelSelectionSettings: true` → dsh-tool-subagent 的 `agent/created` 监听走 `candidate.ctx.inject([...])`,把 subagent 工具注册到**该 agent 自己的层**(own layer);registry `restrict` 只过滤 inherited 名(global + ancestors),own-layer 名永远可见、不可 restrict(dsh-tools `view()` 对 own.tools 无条件 visible)→ `restrict({deny:['subagent']})` 抛「unknown global tool」→ DASHR mask catch 静默跳过 → 全表面泄漏。其余八名(subagent_fork / workflow / ralph 等)无 modelSelectionSettings → composition 层 → 可 restrict → 正常。**v0.2.1 报告的 fallbacks 假设不成立**(06e516a 全为 LLM failover 机制)。
107
+
108
+ **v0.2.1b 决策(用户拍板,临时方案)**:接受暴露,不做 mask/覆盖——`subagent` 从 `MASKED_TOOL_NAMES` 移除(九名 → 八名);在 `control-prompt.md` 自由文本注解 `subagent` 为 `agent`(统一 agent-spawn 入口)的 alias、两者经同一 runtime 委托,保持模型面逻辑自洽。彻底方案(部署配置 modelSelectionSettings: false / DASHR own-layer 防线 / 上游修复)另行 change。
109
+
110
+ **实现状态**:v0.2.1b change(`openspec/changes/v0-2-1-fixes-and-escalation-guidance/`)内 D1/D2/O2/O3/escalation-guidance 全部落地,测试与部署核验见该 change 任务清单。
@@ -0,0 +1,86 @@
1
+ # v0.2.1b 实测报告(v0-2-1-fixes-and-escalation-guidance 第一人称复核)
2
+
3
+ - 部署:commit `247326a`(`v0.2.1a`),版本 `0.2.1-b`(package.json),profile web,宿主已重启、本会话运行于更新后的运行时
4
+ - 被测内容:**仅本 change**(`openspec/changes/v0-2-1-fixes-and-escalation-guidance/`)的四个面——D1 subagent 接受暴露 + alias 注解、D2 eval 描述契约、O2/O3 非平坦措辞、escalation-guidance 注入。不复核既往 feature/change
5
+ - 实测人:被测 Dash Agent 运行时本体(第一人称);注入探针直接读自身 system prompt 的 runtime-context 快照,工具面探针经 `dir(tool)` 与 wire 声明
6
+ - 对应任务清单:tasks.md 5.3「宿主重启新会话后复核」——本报告即该复核的记录
7
+
8
+ ## 部署核验(实测前置)
9
+
10
+ - 工作树 HEAD `247326a`(describe `v0.2.1a`);本 change 源码改动(`src/index.ts` / `src/py-sdk.ts` / `control-prompt.md` / 测试)为未提交工作树改动,但 `dashr/lib` 已重建且与部署位逐字节一致,**lib 面代表运行态**。
11
+ - md5 核验(工作区 `dashr/lib` ↔ 部署位 `~/.dsh/profiles/web/node_modules/@pgmi-builds/better-dsh/lib`):
12
+
13
+ | 文件 | 工作区 | 部署位 | 一致 |
14
+ |---|---|---|---|
15
+ | index.js | `284722a77b1f7fc310a24d0e22d69bb0` | 同左 | ✅ |
16
+ | py-sdk.js | `85691cac2d669fef46f257281f63a44d` | 同左 | ✅ |
17
+ | py-sdk-CbgYiX8O.js(实际实现 chunk) | `8410d97db290eceb1b3ba69cdc8edb86` | 同左 | ✅ |
18
+
19
+ - lib 产物内容抽查:`MASKED_TOOL_NAMES = new Set([skill, send_message, report, list_agents, subagent_fork, interrupt_agent, workflow, ralph])`(index.js:10894-10903,**八名、无 subagent**);escalation 注入句出现 1 次;`!sandboxPolicy` fail-closed 分支在位;eval 描述含「top-level `return` is a SyntaxError」;py-sdk chunk 措辞为「non-identifier characters, e.g. hyphens」且全文 0 处 `infixes`。
20
+
21
+ ## §1 D1:subagent 接受暴露 + control prompt alias 注解(✅)
22
+
23
+ - **源码**:`MASKED_TOOL_NAMES`(`src/index.ts:166`)已移除 `subagent`(九名 → 八名),注释记录 v0.2.1b 决策——standard preset 的 `modelSelectionSettings: true` 使 subagent 注册到 agent own 层、registry restriction 不可达,故接受暴露并以 control prompt 注解替代 mask。
24
+ - **control-prompt.md** 自由文本含 alias 注解(逐字):
25
+ > Delegation: `agent` is the unified agent-spawn entry; `subagent` is its native alias — both delegate through the same runtime, so call either.
26
+ - **wire 面(本会话 system prompt 工具声明)**:`subagent` 在列且签名 `{description, prompt, run_in_background?}`(无 `mode`,宿主原生 subagent,与 v0.2.1 判定一致);`agent` 在列且带 `mode`(dashr 桥);其余八名(skill / send_message / report / list_agents / subagent_fork / interrupt_agent / workflow / ralph)**双面零出现**。
27
+ - **REPL 绑定(第一人称 `dir(tool)` 探针)**:
28
+ - `'subagent' in dir(tool)` = **True**(有意保留)|`'agent' in dir(tool)` = True
29
+ - 八名泄漏 = **[]**(全部按预期 mask)
30
+ - `eval` 自排除 True、0 dunder、`_DashrBindingHolder` / `__dashr_injected__` 在位、共 28 个平坦绑定
31
+ - **功能冒烟(alias 注解推荐的直接调用面)**:`subagent` 实际委托成功——`fc86211b-3253-459b-8ed5-e0a8ec35a76c` 创建并结算,返回 `SUBAGENT-ALIAS-OK`。接受暴露不是摆设,委托链路真实可用。
32
+
33
+ ## §2 D2:eval 描述契约与运行期语义一致(✅)
34
+
35
+ - **描述文本**(`EVAL_DESCRIPTION` `src/index.ts` ~212 与 `control-prompt.md:8` 同一句式,本会话 system prompt 渲染逐字):
36
+ > `eval` takes two required arguments: `cell` (one Python program; top-level `await` works; top-level `return` is a SyntaxError — the cell runs in module scope; …)
37
+ - **无 return 承诺**:全文本不再出现「top-level `return` work」;await 条款保留(行为为真)。
38
+ - **行为实证(第一人称)**:提交含顶层 `return` 的 cell → 运行期抛 `SyntaxError: 'return' outside function`,traceback 定位 `_dashr_run_program` → `_DashrTopLevelReturnChecker().visit(parsed)` → `visit_Return` 显式判错(`src/bootstrap.ts:231-280` 路径)。**描述与行为一致,D2 契约修正成立**。
39
+ - **await 条款实证**:cell 内 `await asyncio.sleep(0)` → `await-ok`;await-in-comprehension `[0, 1, 2]`。kernel 以顶层 await 运行模块协程,描述属实。
40
+ - `test/runtime.spec.ts:92`「rejects a top-level 'return' as a SyntaxError」在套件全绿之列。
41
+
42
+ ## §3 O2/O3:非平坦措辞精确化(✅)
43
+
44
+ - **catalog 段**(`REPL_BRIDGE_INSTRUCTIONS`,`src/py-sdk.ts:616`)已改为(部署 chunk 逐字核验,且全文 **0 处 `infixes`**):
45
+ > Tool names that are not plain identifiers (non-identifier characters, e.g. hyphens) have no `tool.<name>` member — call those as direct tool calls.
46
+ - **control 段**(`control-prompt.md`「Tools inside a cell」)已补非平坦例外句,与 catalog 同义(见 §1 引用段)——v0.2.1 报告 O2 的「hint 只在 catalog 段」已闭合。
47
+ - **行为不变式**:MCP 非平坦名仍 0 绑定(本会话 0 个 `mcp*` 进 REPL),能力经直接调用保留;`'mcp__cordis-a2a__a2a_agents'.isidentifier()` = False、`'mcp__server__tool'.isidentifier()` = True——元凶确为连字符而非 `__`,措辞收紧方向与实现一致。
48
+
49
+ ## §4 escalation-guidance 注入(✅,第一人称最强证据)
50
+
51
+ - **源码**(`src/index.ts:1099-1118`):`ctx.systemPrompt.context({ name: 'dashr:escalation-guidance', order: ESCALATION_GUIDANCE_ORDER = 116, text })`;text 为 use-time 求值——`sandboxPolicy?.resolve({ session: context.agent?.session })`,`mode === 'workspace-write'` 返回注入文本,否则空串;service 缺失 / 无 agent 时 fail-closed(空串)。注册处注释注明依赖 upstream CONTEXT_ORDERS(110/115/120)。
52
+ - **模式矩阵测试**(`test/presentation.spec.ts:208-281`,v0.2.1b model-surface contracts):order 116 在位 / workspace-write 注入 / read-only、danger-full-access 空 / 无 sandboxPolicy service 空——套件全绿。
53
+ - **本会话 runtime-context 快照(第一人称实测)**——当前为 workspace-write 模式,快照逐行:
54
+
55
+ ```
56
+ Current DSH file policy: workspace-write. Any available operation enforced by the
57
+ DSH file sandbox may modify files under the session workspace: "/home/u1/workspaces/dashr". …
58
+
59
+ Approval policy: ask. Operations that require approval may ask through the configured
60
+ answerers; without an available answerer, the request fails closed.
61
+
62
+ Restricted operations may be retried once with sandbox_permissions for single-call
63
+ escalation, pending user approval.
64
+ ```
65
+
66
+ 注入句**精确等于** D3 披露文本(`Restricted operations may be retried once with sandbox_permissions for single-call escalation, pending user approval.`),且**紧贴 `approval:policy`(115)之后、`subagent:delegation`(120)之前**——order 116 位置成立,渲染在 policy 段落同一快照内。
67
+
68
+ ## §5 测试套件
69
+
70
+ - `npx vitest run`:**31 files,392 passed | 3 skipped(395),exit 0**(109.89s)——与 tasks 2.3 / 4.3 预期(395 全绿、presentation.spec 19/19)一致。
71
+
72
+ ## 观察(非缺陷)
73
+
74
+ | # | 级 | 观察 |
75
+ |---|---|---|
76
+ | O-1 | 记录 | 部署位残留陈旧 chunk `py-sdk-DRmSaN8R.js`(md5 `77cd3ed0…`,内容寻址 chunk,未被引用、无加载风险)——清理可选 |
77
+ | O-2 | 记录 | 本会话 kernel python = 部署 `.venv-kernel` 的 **3.11.15**(traceback 实证 `.venv-kernel/lib/python3.11`)——v0.2.1 报告 O1「managed venv 3.11 未命中、用宿主 3.14.4」在本次重启后已命中 managed venv;环境事实 |
78
+ | O-3 | **已修正为缺陷** | REPL 内工具调用截断的**真实原因**:非阻塞问题,而是任何 `tool.*` RPC 都触发 `registry[TOOL_RUNTIME_SCHEDULER]` 为 undefined → `scheduler.prepare` TypeError → driver 无 catch 的 unhandled rejection → harness `installFailLoud` 判定 fatal → **daemon 崩溃重启** → repair 合成「interrupted」。4/4 复现(17:39/17:41/17:57/18:02),journald 铁证。详见 `docs/REPL-工具调用-截断诊断.md`;修复后需重跑探针矩阵 |
79
+
80
+ ## 结果
81
+
82
+ **总体判定:v0.2.1b 四项目标(D1 接受暴露 + alias 注解、D2 eval 描述契约、O2/O3 非平坦措辞、escalation-guidance order-116 注入)在新会话运行态下全部成立,无回归、无 discrepancy。**
83
+
84
+ - v0.2.1 报告的两处问题均已按本 change 落地闭合:D1 回归 → 转为有意暴露 + 注解(功能冒烟通过);D2 描述不一致 → 描述与运行期语义一致(顶层 return 实测 SyntaxError)。
85
+ - 注入矩阵在 workspace-write(本会话实际模式)下第一人称可见,read-only / danger-full-access 不注入由单测矩阵覆盖。
86
+ - tasks.md 5.3(宿主重启新会话复核)完成:control 段 alias 注解 ✓、eval 描述无 return 承诺 ✓、escalation 注入文本位于 `approval:policy` 之后 ✓。
@@ -0,0 +1,66 @@
1
+ # v0.2.1c 实测报告(v0-2-1c-repl-tool-crash-fix 第一人称实测)
2
+
3
+ - 部署:版本 `0.2.1-c`(package.json,工作区与部署位一致),profile web;用户已执行部署同步 + daemon 重启(19:23:19),本会话运行于更新后的运行时
4
+ - 被测内容:**本 change**(`openspec/changes/v0-2-1c-repl-tool-crash-fix/`)的六.1(drive 加 catch)+ 六.2(scheduler 防御)在活体 daemon 上的回归核验基线(六.5);六.3 根因归属复核
5
+ - 实测人:被测 Dash Agent 运行时本体(第一人称);探针经 `eval` cell 内 `tool.<name>(...)` 直接调用 REPL 子分派桥——与 v0.2.1b 崩溃复现矩阵完全同路径
6
+ - 对应任务清单:tasks.md 6.1 / 6.2 / 6.3(以及 3.2 活体复核)——本报告即该核验的记录
7
+
8
+ ## 部署核验(实测前置)
9
+
10
+ - 版本:`dashr/package.json` 与部署位 `~/.dsh/profiles/web/node_modules/@pgmi-builds/better-dsh/package.json` 均为 `0.2.1-c` ✅
11
+ - md5 核验(工作区 `dashr/lib` ↔ 部署位 lib):
12
+
13
+ | 文件 | 工作区 | 部署位 | 一致 |
14
+ |---|---|---|---|
15
+ | index.js | `861fb9d3fb108015fb1d665d00d789b2` | 同左 | ✅ |
16
+ | client/index.js | `8b1548613b5d68ef4606f4729b0af312` | 同左 | ✅ |
17
+
18
+ - `diff -rq lib/` 两侧 **LIB DIRS IDENTICAL**(含删除陈旧 chunk 后的完整目录对比)✅
19
+ - lib 产物内容抽查:六.2 loud 错误文本(`the tools service resolved by this composition lacks the TOOL_RUNTIME_SCHEDULER symbol …`)在 index.js 中出现;六.1 lane backstop(`settling queued dispatches as errors`)在源码 `src/index.ts:642-652` 在位 ✅
20
+ - daemon 重启:journal 显示 19:23:19 旧进程(pid 443984)SIGTERM 优雅停止 → 同一秒新进程(pid 532389→532407→532567)启动;自重启至今 **0 条 fatal / TypeError / FAILURE / restart** ✅
21
+
22
+ ## §1 4 探针矩阵(六.5 回归核验,第一人称)
23
+
24
+ 对照 v0.2.1b 诊断矩阵(`docs/REPL-工具调用-截断诊断.md` §一),同 cell 内容在**本会话(v0.2.1c 运行态)**重跑:
25
+
26
+ | # | cell 内容 | v0.2.1b 结果 | v0.2.1c 实测结果 | 判定 |
27
+ |---|---|---|---|---|
28
+ | 1 | `await tool.subagent({… run_in_background: false })` | 截断(daemon 崩溃 17:39:17) | cell 收到 `ToolCallError`,消息点名 `TOOL_RUNTIME_SCHEDULER` symbol + scope/service view 上下文 | ✅ 返回结果非截断 |
29
+ | 2 | `await tool.subagent({… run_in_background: true })` | 截断(daemon 崩溃 17:41:15) | 同上 | ✅ 返回结果非截断 |
30
+ | 3 | `await tool.bash({… run_in_background: true })` | 截断(daemon 崩溃 17:57:05) | 同上 | ✅ 返回结果非截断 |
31
+ | 4 | `await tool.read({path: "dashr/package.json"})` | 截断(daemon 崩溃 18:02:27) | 同上 | ✅ 返回结果非截断 |
32
+
33
+ - **4/4 全部返回可见结果**(loud `ToolCallError`,含完整上下文消息),**零截断、零 daemon 崩溃**。每次探针后 daemon 继续存活、后续 cell 正常执行——与 v0.2.1b 的「探针即杀进程」形成对照。
34
+ - 探针实际收到的错误消息(4/4 逐字一致):
35
+ > `eval: the tools service resolved by this composition lacks the TOOL_RUNTIME_SCHEDULER symbol (a scope/service view instead of the native ToolRuntime instance) — REPL sub-dispatch cannot run; check the harness mount wiring (packages/core/tools) resolving the plugin's tools service`
36
+ - **对照结论**:v0.2.1b 同路径的「裸 `undefined.prepare` TypeError → driver 无 catch → unhandled rejection → installFailLoud fatal → daemon exit(1) → repair 合成 interrupted-tool-result」链条已被六.1+六.2 打断。错误现在**在 cell 内可见**,binding promise 正常 settle,进程零外泄。
37
+
38
+ ## §2 journald 守护进程日志(六.5 铁证)
39
+
40
+ - 自重启时刻 19:23:19 起:`journalctl --user -u dsh.service --since "19:23:19"` grep `fatal|TypeError|FAILURE|restart|crashed|exit` → **0 条匹配**;journal 尾部仅启动 INFO(MCP 注册、dsh web URL)。
41
+ - 对照:v0.2.1b 的 17:39:17 / 17:41:15 / 17:57:05 / 18:02:27 四条 fatal load failure(`Cannot read properties of undefined (reading 'prepare')`)**不再出现**。
42
+ - 会话日志侧:本会话(`session-6c013361…`)**0 条 `interrupted-tool-result`** repair 事件——无截断指纹。且因六.2 guard 在 `binding()` 内、`start()` 之前抛错(`src/index.ts:695-697` 先于 `tool/code-dispatch-start` append),本次探针连半程 dispatch 日志都没有留下——错误在最早点被拒绝,不产生部分状态。✅
43
+
44
+ ## §3 根因归属与交付边界(六.3 活体复核)
45
+
46
+ - 活体探针结论:**生产组合仍把 `runtimeCtx.tools` 解析为缺 `TOOL_RUNTIME_SCHEDULER` 实例 symbol 的 scope/service 视图**——4/4 探针的 loud 错误本身就是活体证据(错误消息由 guard 在 symbol 判空时抛出,证明运行态确实取不到 symbol)。
47
+ - 与诊断文档 §四/§七的推演一致:测试组合(根作用域原生实例,symbol 在位)全绿,生产组合(preset realm / plugin tree 发布路径带 shadow 标记 → `getTraceable` 返回原型而非实例)缺 symbol——**差异在 harness 侧(dsh-alpha),作为外部依赖记录**。
48
+ - **本 change 的 dashr 交付边界 = 「不崩溃 + loud 错误」——已达成**(§1+§2 实证)。「调度器真正可用、REPL 子分派真实执行」取决于 harness 挂载修正(dsh-alpha),不在本 change 交付物内。
49
+
50
+ ## §4 测试套件
51
+
52
+ - `npx vitest run`(本轮实测重跑):**31 files、396 passed | 3 skipped = 399 绿、exit 0**(109.41s)——与 tasks.md 记录的 399 全绿一致,含 3 个 v0.2.1c 韧性回归用例(缺 symbol 视图 → loud 错误;`scheduler.prepare` 抛错 → binding settle 可见错误;classify 抛错 → lane backstop settle 且进程存活)。本轮实测的活体行为与这三个用例的断言一一对应。
53
+
54
+ ## 观察(非缺陷)
55
+
56
+ | # | 级 | 观察 |
57
+ |---|---|---|
58
+ | O-1 | 记录 | REPL 内 `tool.*` 子分派目前**不可用**(调度器 symbol 缺失,loud 错误可见)——这是 harness 侧外部依赖,非本 change 回归;dashr 侧防御保证了「不可用」以可见错误呈现而非进程崩溃 |
59
+ | O-2 | 记录 | 本次守护进程重启(19:23:19)由用户执行,重启后本会话续跑于新 lib(部署位 md5 与工作区一致);journal 无旧崩溃残留以外的任何异常 |
60
+
61
+ ## 结果
62
+
63
+ **总体判定:v0.2.1c 的目标在活体 daemon 上全部成立——六.1(drive 加 catch)阻断 unhandled rejection 外泄、六.2(scheduler 防御)把裸 TypeError 转为 cell 可见 loud 错误;4 探针矩阵 4/4 返回结果而非截断,journald 自重启后 0 条崩溃,会话日志 0 条 interrupted-tool-result 修复事件。**
64
+
65
+ - tasks.md 6.1(4 探针矩阵 4/4 非截断)✅、6.2(journal 无新崩溃)✅、6.3(本报告)✅、3.2(活体复核:根因确认在 harness,dashr 可及范围防御已实施,harness 侧记录为外部依赖修复)✅。
66
+ - 交付边界已按设计执行:dashr 侧「不崩溃 + loud 错误」;「调度器真正可用」依赖 dsh-alpha 挂载修正,需在 harness 侧 change 中跟进。
@@ -0,0 +1,67 @@
1
+ # v0.2.1d 实测报告(v0-2-1d-tool-runtime-scheduler-mount 第一人称实测)
2
+
3
+ - 部署:lib 版本 `0.2.1-d`(工作区 `dashr/package.json` `0.2.1-d`;部署位 lib 逐字节一致,package.json 版本字段漂移见 O-1),profile web;部署同步 18:19:03、daemon 重启 18:38:12,本会话运行于更新后的运行时
4
+ - 被测内容:**本 change**(`openspec/changes/v0-2-1d-tool-runtime-scheduler-mount/`)——根因更正(dual-copy)下的「registry 获取保持原样」裁决(D2)、guard 自诊断增强(2.2)、symbol 同一性回归测试(2.4)、活体 4 探针矩阵回归基线(4.1/4.2)
5
+ - 实测人:被测 Dash Agent 运行时本体(第一人称);探针经 `eval` cell 内 `tool.<name>(...)` 直接调用 REPL 子分派桥——与 v0.2.1b 崩溃矩阵、v0.2.1c loud 错误矩阵完全同路径
6
+ - 对应任务清单:tasks.md 4.1 / 4.2 / 4.3(以及 2.2 / 2.4 交付物落位复核)——本报告即该核验的记录
7
+
8
+ ## 部署核验(实测前置)
9
+
10
+ - 版本:工作区 `dashr/package.json` = `0.2.1-d` ✅;部署位 package.json 版本字段仍为 `0.2.1-c`(**元数据漂移,非代码漂移**,见 O-1)
11
+ - md5 核验(工作区 `dashr/lib` ↔ 部署位 `~/.dsh/profiles/web/node_modules/@pgmi-builds/better-dsh/lib`):
12
+
13
+ | 文件 | 工作区 | 部署位 | 一致 |
14
+ |---|---|---|---|
15
+ | index.js | `56db6ef89f2750dc8fa4b11fefad7654` | 同左 | ✅ |
16
+ | client/index.js | `8b1548613b5d68ef4606f4729b0af312` | 同左 | ✅ |
17
+
18
+ - `diff -rq lib/` 两侧 **LIB DIRS IDENTICAL** ✅
19
+ - 时间线:部署位 lib/index.js mtime `18:19:03` → daemon `Stopping 18:38:11` → `Started 18:38:12`(journal)——**重启晚于同步,运行代码即新 lib** ✅
20
+ - 产物内容抽查:v0.2.1d guard 新错误文本在部署 lib/index.js 中逐字在位——含 `Most likely a dual-copy dsh-tools` 诊断、`This plugin resolves @deepseek-ai/dsh-tools from: ${resolvedFrom}` 自诊断路径、`only schemastery and cosmokit belong there` 部署纪律提示 ✅(源码位 `src/index.ts:691-709`,`createRequire(import.meta.url).resolve(...)` 取插件位解析路径)
21
+
22
+ ## §1 4 探针矩阵(4.1 回归核验,第一人称)
23
+
24
+ 对照 v0.2.1b 诊断矩阵(`docs/REPL-工具调用-截断诊断.md` §一)与 v0.2.1c 实测矩阵,同路径 cell 在**本会话(v0.2.1d 运行态)**重跑:
25
+
26
+ | # | cell 内容 | v0.2.1b | v0.2.1c | v0.2.1d 实测结果 | 判定 |
27
+ |---|---|---|---|---|---|
28
+ | 1 | `await tool.subagent({… run_in_background: false})` | 截断(崩溃 17:39:17) | loud 错误 | **真实结果**:前台 runId `7c7b6b1e…`,子代理真实执行并输出 `PROBE-OK`(5.4s) | ✅ |
29
+ | 2 | `await tool.subagent({… run_in_background: true})` | 截断(崩溃 17:41:15) | loud 错误 | **真实结果**:受理返回 `{"kind":"continuable","subagentId":"90d8e8f9…"}`,子代理异步完成,关闭消息 `4247`(= 137×31,答案正确)——端到端闭环 | ✅ |
30
+ | 3 | `await tool.bash({… run_in_background: true})` | 截断(崩溃 17:57:05) | loud 错误 | **真实结果**:job `bash-1`,`job_output` 收割 stdout `PROBE3-BG-OK\nPROBE3-BG-DONE\n`,status completed(2.0s) | ✅ |
31
+ | 4 | `await tool.read({path: "dashr/package.json"})` | 截断(崩溃 18:02:27) | loud 错误 | **真实结果**:11591 字符真实内容(hashline 锚点格式),`"version": "0.2.1-d"` 可见 | ✅ |
32
+
33
+ - **4/4 全部返回真实执行结果**——既非 v0.2.1b 的截断/崩溃,也非 v0.2.1c 的 loud `ToolCallError`。三版本同路径对照:崩溃 → 可见错误 → **真实可用**,递进完整。
34
+ - 探针 2 的响应形态为 continuable subagent(durable `subagentId`)而非 jobId,`job_output` 不适用;子代理结果经 runtime 落地通知回收(本会话已收到,payload 正确)——与 job 型后台(探针 3 的 `bash-1`)是两种正常形态,记入 O-2。
35
+
36
+ ## §2 journald 守护进程日志(4.2 铁证)
37
+
38
+ - 自重启时刻 `18:38:12` 起(探针全部完成后于 18:43 复扫):`journalctl --user -u dsh.service --since "18:38:12"` grep `fatal|TypeError|FAILURE|crashed|exit(1)` → **0 条匹配**;journal 仅 19 行正常启动 INFO(MCP 注册、`Successfully registered all tools`、dsh web URL)。
39
+ - 对照:v0.2.1b 的 17:39:17 / 17:41:15 / 17:57:05 / 18:02:27 四条 fatal load failure 已不再出现;v0.2.1c 时点的 loud 错误路径本轮探针一次都未触发(4/4 走正常调度器)。
40
+ - 4 探针执行期间及之后 daemon 持续存活(pid 1951131),后续 cell 正常执行——探针不再是「进程杀手」,而是普通工具调用。
41
+
42
+ ## §3 根因更正与交付边界复核(design Context/D2 活体确认)
43
+
44
+ - **4/4 真实结果即根因更正的活体终验**:现行生产拓扑(① 层 symlink 清理后)下 `runtimeCtx.tools` plain read 返回带 `[TOOL_RUNTIME_SCHEDULER]` 的原生实例——design「shadow 视图从未在活体上出现、真实根因是部署拓扑 dual-copy」的裁决由本轮矩阵再次确认。候选 A/B/C/D 无需实施,registry 获取保持 `const registry = runtimeCtx.tools` 原样(源码走查未见改动,符合 D2)。
45
+ - **v0.2.1d 交付物落位**:
46
+ - guard 自诊断(2.2):源码 `src/index.ts:691-709` + 部署产物逐字在位;本轮 4/4 探针正常路径未触发该分支(预期行为——guard 只在 dual-copy 复发时发声)。
47
+ - symbol 同一性回归测试(2.4):`test/bridge.spec.ts:586` 用例 `v0.2.1d — the mounted ToolRuntime is keyed by the SAME symbol this plugin imports (dual-copy invariant)` 在位,断言经本文件 import 的 symbol 读出 scheduler 且 `prepare/dispatch/finalize/finish` 四方法为函数。
48
+ - 交付边界:本 change 的目标「REPL `tool.*` 子分派真实执行并返回结果」**已在活体上达成**;防御纵深保留(v0.2.1c 判空 guard + v0.2.1d 自诊断文本)作为未来 dual-copy 事件的第一现场。
49
+
50
+ ## §4 测试套件
51
+
52
+ - `npx vitest run`(本轮实测重跑):**31 files、400 passed = 400 绿、exit 0**(127.95s)——399 旧用例 + 1 新 symbol 同一性用例,与 tasks.md 2.2 记录一致;含 v0.2.1c 的 3 个韧性回归用例与 v0.2.1d 的 dual-copy invariant 用例,本轮活体行为(真实调度、guard 未触发、零崩溃)与套件断言一一对应。
53
+
54
+ ## 观察(非缺陷)
55
+
56
+ | # | 级 | 观察 |
57
+ |---|---|---|
58
+ | O-1 | 记录 | 部署位 package.json 版本字段仍为 `0.2.1-c`(工作区 `0.2.1-d`)——部署同步只携带 `lib/`,版本元数据漂移与既有 profile 锁版本漂移同类;lib 已逐字节一致,无碍运行,建议下次部署同步时连带 package.json |
59
+ | O-2 | 记录 | 探针 2 后台 subagent 的响应形态是 continuable(`subagentId`)而非 job(`jobId`),收割走 runtime 落地通知而非 `job_output`;探针 3 后台 bash 则是 job 形态——两种后台形态并存为设计使然,报告记录以免后续误判 |
60
+ | O-3 | 记录 | agent 的 bash 执行环境内 `systemctl --user` 总线不可达(`No data available`),daemon 状态改经 `journalctl --user -u dsh.service` 取证成功——环境观察,非被测对象问题 |
61
+
62
+ ## 结果
63
+
64
+ **总体判定:v0.2.1d 的目标在活体 daemon 上全部成立——REPL `tool.*` 子分派真实可用(4 探针矩阵 4/4 返回真实执行结果,前台/后台/bash/读写四形态全覆盖);自重启(18:38:12)起 journal 0 条崩溃;guard 自诊断与 symbol 同一性回归双交付物在源码、产物、测试三层落位;测试套件 400 全绿。**
65
+
66
+ - tasks.md 4.1(4 探针 4/4 真实结果)✅、4.2(journal 0 崩溃)✅、4.3(本报告)✅;2.2 / 2.4 交付物复核 ✅。
67
+ - 三版本递进就此闭环:v0.2.1b(崩溃复现)→ v0.2.1c(不崩溃 + loud 错误)→ **v0.2.1d(真实可用 + dual-copy 根因更正 + 自诊断防御)**。根因(部署拓扑 dual-copy symbol 分裂)已由 symlink 清理消除,不变量已由回归测试与 guard 自诊断双锚锁定。
@@ -0,0 +1,136 @@
1
+ # v0.2.1e-P1 实测/观察记录(eval REPL 语义 · 沙箱后端 · 内核 fs reach —— alpha.5 对齐输入)
2
+
3
+ - 日期/实例:2026-09-03;Dev/Test 1 源码级 4999 实例(checkout `dsh-v0.1.2-alpha.5` detached `db6bdc3576`,`DSH_HOME=.dsh-test`);workspace `@pgmi-builds/better-dsh` = `0.2.1-d`(版本波 v0.2.1e 前置)
4
+ - 被测:`eval`(dashr-repl 持久 IPython 内核)执行引擎与 cell 语义;agent 原生 `bash` 的进程沙箱后端可用性;eval 内核进程的 fs reach 边界
5
+ - 实测人:被测运行时上的 Dash Agent(第一人称);探针经 `eval` cell 双路径——cell 内裸 Python 与 cell 内 `tool.*` 绑定——及原生工具
6
+ - 定位:v0.2.1e-P1(align upstream alpha.5)的**输入记录**——openspec/changes 尚无 v0-2-1e scaffold,本报告不预设验收点,只落事实/裁定/待决,供 phase owner 续建 tasks.md
7
+ - 关联记录:`upstream-dsh-0.1.2-alpha.5-local-test-report.md`(同实例 2026-09-02);`v0.2.1d-实测报告.md`(0.2.1-d 波收口);change `2026-09-02-kernel-provisioning-completeness`(venv 供给,403/403 全绿)
8
+
9
+ ## §1 探针事实(本会话实证)
10
+
11
+ | # | 探针 | 实测结果 | 判定 |
12
+ |---|---|---|---|
13
+ | 1 | 引擎身份:cell 内 `import IPython` + sys 探针 | IPython **9.17.1** / ipykernel **7.3.0** / `ZMQInteractiveShell`;`sys.executable` = `…/packages/better-dsh/better-dsh/.venv-kernel/bin/python`(**CPython 3.11.15**,plugin 管理 venv,与 kernel-provisioning 任务 4.1「kernel ready: python 3.11.15」吻合);进程身份 uid 1000 (u1);**内核 cwd = 本 agent 会话工作区 `/home/u1/workspaces/temp`**(解释器在 checkout venv、cwd 在工作区,两处不同目录) | eval 是**真持久 IPython 内核**,非逐调用子进程 |
14
+ | 2 | 跨 cell 状态:`x = 42` 后次 cell 读 | 值仍在 → 单内核进程跨 cell 存活 | REPL 状态语义 ✅ |
15
+ | 3 | cell 语义:裸表达式 / 语句 cell | 模块作用域;末表达式值回传、`None` 抑制(displayhook 式) | ✅ |
16
+ | 4 | 顶层 `return`:`return 42` | `SyntaxError: 'return' outside function`,由**包装侧 `_DashrTopLevelReturnChecker` AST visitor 主动抛**(wrapper pre-parse,`_dashr_run_program` 帧内),非内核自然报错 | 语义有意强制,对齐 native IPython cell |
17
+ | 5 | `%` 行 magic:`%time x = 6 * 7` | wrapper `_dashr_ast.parse` 即 `SyntaxError: invalid syntax`——**行 magic 不转换**,内核未收到该行 | 与「pure IPython REPL semantics」宣称(`src/python.ts`、README)的可见偏差 → C1 |
18
+ | 6 | cell 内 `tool.*`:`await tool.glob({…})` | 返回 4 个真实文件(`v0.2.1{,b,c,d}-实测报告.md`),与原生调用同路径同结果 | REPL 内工具调用 = 工具面另一入口,非新能力 → §2 平面 A |
19
+ | 7 | agent 原生 bash:`pwd`(workspace-write) | **拒**:`no sandbox backend is usable on this host`(bubblewrap / Landlock / sandbox-exec / ACL 全缺),runner 拒绝非受限执行;仅 `danger-full-access`(需审批)可跑 | 环境事实,非插件缺陷 → §3 |
20
+
21
+ ## §2 裁定:fs reach 的两个平面(用户裁定 + 推理确认)
22
+
23
+ - **平面 A —— 被认可的工具面**:cell 内 `tool.*` 与 agent 原生工具调用走**同一条 bridge → tool-service 路径**(同一校验/掩码/策略/日志,auto-bridge 机制见 `src/bridges/index.ts`)。read/write 等原生工具**本就持真实 fs**——它们的收窄(workspace-write、mask)来自工具面的策略层,不是虚拟化。
24
+ - **平面 B —— 解释器裸达**:cell 内裸 Python(`open`/`os`/`shutil`/…)以内核进程身份执行,达 = host 用户(u1/1000)的达。
25
+ - **裁定 ①**:「内核有 host-user fs reach」**在 REPL 使用场景本来就是如此**——交互式 IPython/Jupyter 内核即以启动用户身份运行、持其全达;better-dsh 供给受管 venv 内核 = 「用户的 Python REPL」,未做 OS 级逐调用沙箱是 REPL 的固有语义,**不是插件开的洞**。此前把这点标为 caveat 的措辞收回。
26
+ - **裁定 ②**:本 agent 运行场景中 eval 只是 agent 的工具之一;原生工具本就有真实 fs 达 → 内核达相对工具套件**不是异常**。因此 **eval 的强制边界 = 平面 A(工具面)+ 掩码/策略,不是平面 B(解释器)**。
27
+ - 推论:安全评审/对齐评审不应把 B 平面裸达记作 sandbox escape 缺陷;若 alpha.5 侧期望 run_code OS 级逐调用受限,**有状态持久内核无法廉价满足**(逐调用沙箱与驻留状态互斥)——是设计取舍而非缺陷(关联 `10_plans/dashr-blueprint.md` phase 2 fork-server 复用父内核状态的方向)。
28
+
29
+ ## §3 沙箱后端环境观察(非插件缺陷)
30
+
31
+ - 本会话 agent bash:`workspace-write` → 拒(no sandbox backend usable on this host)。文件工具(read/grep/glob)、`eval`、cell 内 `tool.*` 均不受影响——各自独立的强制面,不依赖该进程沙箱后端。
32
+ - 对照 v0.2.1b–d 矩阵期:v0.2.1d 报告 §1 探针 3(cell 内 `tool.bash` 后台 job 真实执行)与 §2(journalctl 取证)证明**当时 agent bash 可用** → 同 4999 实例、不同会话/时刻的 backend 可用性存在差异(daemon profile / 装配差异?)。**环境 delta,未定位**,列为 O-1,请 phase 复看是否与 alpha.5 的沙箱装配相关。
33
+ - 影响:需 bash 的取证路径(如 journalctl)在本会话须走 `danger-full-access` 审批,或改用无 bash 取证路径。
34
+
35
+ ## §4 对 v0.2.1e-P1(alpha.5 对齐)的输入(待决清单)
36
+
37
+ | # | 议题 | 证据/出处 | 建议去向 |
38
+ |---|---|---|---|
39
+ | C1 | `%` 行 magic 不转换 vs 「pure IPython REPL semantics」宣称 | §1-5;`src/python.ts`、README、`control-prompt.md` 措辞 | 决策:pre-parse 前对顶层 magic 行做变换(对齐真 IPython cell),或文档化「line magic 不支持」;配套回归用例 |
40
+ | C2 | 进程沙箱 backend 缺失 → agent bash 在 workspace-write 不可用 | §1-7、§3 | 核 alpha.5 是否改动沙箱装配/backend 探测;文档补 backend 要求与 `danger-full-access` 升级语义(关联 `10_plans/dashr-sandbox-escalation-semantics-gap.md`) |
41
+ | C3 | 内核身份双位:解释器在 `…/better-dsh/.venv-kernel/bin/python`、cwd 在 agent 工作区 | §1-1 | alpha.5 若改 runtime 启动布局,核对 kernel spawn 路径/cwd 语义不漂移;文档化 |
42
+ | C4 | eval 强制边界陈述(= 平面 A + 掩码;B 平面裸达 = REPL 固有语义) | §2 | 沉淀为文档(README 安全一节或 ADR),防安全评审误读 |
43
+ | C5 | venv 供给与 alpha.5 联动 | change `2026-09-02-kernel-provisioning-completeness`(403/403 全绿) | alpha.5 对齐波不重开供给任务;其 5.2 未决项(prod 装机路径)在 alpha.5 版本复跑一次 |
44
+
45
+ ## 观察(非缺陷)
46
+
47
+ | # | 级 | 观察 |
48
+ |---|---|---|
49
+ | O-1 | 记录 | 沙箱 backend 可用性会话间差异(同 4999 实例:v0.2.1d 矩阵期 bash 可用 → 本会话拒)——环境 delta,未定位 |
50
+ | O-2 | 记录 | 内核解释器与 cwd 分处两目录(venv 在 checkout、cwd 在 agent 工作区),勿误判「内核在插件目录运行」 |
51
+ | O-3 | 记录 | openspec/changes 尚无 v0-2-1e scaffold、workspace package.json 仍 `0.2.1-d`——本报告为 v0.2.1e 波首个落盘件,任务编号(P1…Pn)待 phase owner 对齐 |
52
+
53
+ ## 结果
54
+
55
+ ---
56
+
57
+ ## §5 Phase-owner 后补(2026-09-03,wrap-up)
58
+
59
+ ### 5.1 版本与构建落位
60
+
61
+ - workspace `@pgmi-builds/better-dsh` 版本 `0.2.1-d` → **`0.2.1-e`**(canonical + monorepo 副本 + tsdown 重建,9 files / 514.94 kB;O-3 关闭)。change 对应关系:v0.2.1e 波 = alpha.5 对齐;P1 = `2026-09-02-kernel-provisioning-completeness`(**10/11**,唯一遗留 5.2 的 prod 装机路径核验,按定义留发布时;403/403 全绿、EROFS 模拟、无 uv 兜底、冷启动 spin-up 供给详见该 change tasks 注记与 `docs/kernel-provisioning.md`)。
62
+
63
+ ### 5.2 C2/O-1 关闭:沙箱后端缺失根因 = 嵌套沙箱,非构建、非上游
64
+
65
+ - **复现**:在 agent 沙箱化 bash 内执行 bwrap 功能探测(`packages/sandbox/sandbox-local` 的 `defaultProbeBwrap` 同形命令)→ `bwrap: No permissions to create a new namespace`(exit 1)。前一代 4999 daemon 正是从沙箱化 bash 后台任务启动的——daemon 继承沙箱环境,自身再 spawn bwrap 即嵌套,探测必败 → `SANDBOX_UNAVAILABLE`(bwrap/Landlock/…全判缺)。
66
+ - **对照解释**:v0.2.1d 期实例的 daemon 启动自非嵌套上下文 → 探测通过、bash 可用。上游 alpha.5 的 workspace-write 沙箱本身无恙;我们的 build 也无恙。
67
+ - **修复**:daemon 改经 `systemd-run --user` 启动于沙箱之外(unit `dsh-4999-test`,与 prod 的 systemd 形态对齐;stdout/stderr 落 `.scratch/dsh-4999.log` 取 token)。当前 token:`qzwIUV1nwVsixUfW8sa-sgodW8uSQAyCzi7XHtflfAc`。**验收建议**:在 4999 开 session 跑任意 bash 命令(如 `pwd`)——应正常沙箱执行而非 `SANDBOX_UNAVAILABLE`。
68
+ - **约定固化**(AGENTS.md 已更新):agent 从沙箱会话重启 4999 一律走 systemd-run --user;勿从沙箱化 bash 直接拉 daemon。
69
+
70
+ ### 5.3 C 编号处置表
71
+
72
+ | # | 处置 |
73
+ |---|---|
74
+ | C1(line magic 不转换) | 留 v0.2.1e 波后续任务(failover 阶段后的收口池):决策「pre-parse 变换顶层 magic 行」vs「文档化不支持」+ 回归用例 |
75
+ | C2(沙箱后端缺失) | **已关闭**(本节 5.2,根因+修复+约定) |
76
+ | C3(内核解释器/cwd 双位) | 留收口池:alpha.5 布局语义核对 + 文档化(本轮 AGENTS.md/供给文档已部分覆盖) |
77
+ | C4(eval 强制边界陈述) | 留收口池:README 安全一节或 ADR 沉淀 §2 裁定(防安全评审误读) |
78
+ | C5(venv 供给联动) | **已收敛**:kernel change 10/11,prod 装机路径随发布复跑 |
79
+
80
+ ### 5.4 波内范围调整(user 裁决 2026-09-03)
81
+
82
+ - 两个 user 私人 Web UI patch(loopback auth / mobile responsiveness)**移出本波**:change 目录迁至 `openspec/deferred/`(内容保留)——user 对这批 patch 有新想法,将合并到后续 change 一起做。本波 active = kernel(收口)+ model-failover(下一阶段,Phase 2)。
83
+ **总体判定:本会话实测回答了两个开放疑问——(a) `eval` 是否真 IPython REPL:是**(持久 `ZMQInteractiveShell` 内核,模块作用域/displayhook/顶层 return 语义对齐 native IPython cell;唯一可见偏差是 `%` 行 magic 不转换,C1);**(b) 内核 host-user fs reach 是否缺陷:否**——REPL 场景固有语义,eval 的强制边界在工具面(平面 A)而非解释器(平面 B),见 §2 裁定。无阻断性发现。C1–C5 作为 v0.2.1e-P1 tasks.md 的骨架输入;phase owner 建 v0-2-1e change 后按 C 编号回填验收。
84
+
85
+ ### 5.5 Phase 2 收口补记(2026-09-03)
86
+
87
+ failover settings 面(`model-failover-settings-surface`,9/9):原生链路核实定论——settings 行 = client bundle 内 slot 注册(`ctx.slots.inject('settings.general.item', …)`),FailoverRow 与 locale/ui-chat 原生行同构,**无纯服务端注册替代面**;副本构建用 `tsx scripts/build-client.ts` 直跑(`npm run` 死于 npm 自身 workspace 枚举,vendor/CLAUDE.md ENOTDIR);4999 boot graph 含插件行、HTTP 200 与产物字节一致;**user GUI 确认 FailoverRow 呈现**;全量 403/403 + tsc 0 错。v0.2.1e 本地 commit + tag 落位。
88
+
89
+ ## §6 复测(daemon 重启后,2026-09-03)——§5.2 验收判据实测确认
90
+
91
+ 应 owner 要求,重启后对 §1 探针 1–7 全量复测:
92
+
93
+ | # | 探针 | 重启前(§1) | 重启后复测 | 判定 |
94
+ |---|---|---|---|---|
95
+ | 1 | 引擎身份 | IPython 9.17.1 / ipykernel 7.3.0 / `ZMQInteractiveShell`;exe `.venv-kernel/bin/python`(3.11.15);uid 1000;cwd = agent 工作区 | **完全一致** | 稳定 ✅ |
96
+ | 2 | 跨 cell 状态 | `x = 42` 存活 | `restart_marker` 前置 cell 设 → 后置 cell 读到 | 会话内持久 ✅ |
97
+ | 2b | 跨重启状态(新增) | — | 重启前 `x` **不在**新内核 globals | 记录 → O-4 |
98
+ | 3 | 完成值回传 | 末表达式值回传、None 抑制 | 裸 `40 + 2` → 完成值 `42` | ✅ |
99
+ | 4 | 顶层 `return` | 包装侧 `_DashrTopLevelReturnChecker` 主动抛 | 同错同帧 | 稳定 ✅ |
100
+ | 5 | `%` 行 magic | `_dashr_ast.parse` 即 SyntaxError | 同错同处 | 稳定 ✅(C1 仍成立) |
101
+ | 6 | cell 内 `tool.*` | `tool.glob` → 4 文件 | → 6 文件(目录新增本报告 + v0.2.1f 报告) | ✅ 真实 fs |
102
+ | 7 | agent bash(workspace-write) | **拒**:no sandbox backend usable | **可用**:`pwd`→工作区;越界只读(dashr/docs、`/etc/hostname`)放行 | ✅ = §5.2 验收判据 |
103
+
104
+ - 探针 7 即 §5.2 的验收建议(4999 开 session 跑任意 bash)——**实测通过**:本次 daemon 经 `systemd-run --user` 启动于沙箱外(§5.2 修复),bwrap 探测不再嵌套失败;workspace-write 沙箱正常生效(只读越界放行、写仍限工作区)。
105
+ - §1-7 与 §3 首条(bash 拒)为**修复前**事实,与 §5.2 根因(嵌套沙箱)一致,已被探针 7 取代;O-1 转闭。
106
+ - 版本再漂移记录:§5.1 记 `0.2.1-e`;复测时 workspace package.json 已 **`0.2.1-f`**(v0.2.1f plugin-shipped-ui-patches 波落盘,dir 内已有同名报告)。本报告标题标签 v0.2.1e-P1 为 owner 指定(§5.3/5.4 已作 C 编号与波内处置)。
107
+
108
+ 新增观察:
109
+
110
+ | # | 级 | 观察 |
111
+ |---|---|---|
112
+ | O-4 | 记录 | daemon 重启后内核为**全新命名空间**(重启前 `x` 不在)——「会话内持久」而非「跨重启持久」;若需跨重启续命须核 snapshot/restore(dill 快照)是否启用 |
113
+
114
+ ### O-4 处置(2026-09-03 收口):dill 快照 = opt-in,未开非故障;4999 已开并跨重启实证
115
+
116
+ - **定性**:快照/恢复链(turn-end 落盘 + `agent/disposed` 落盘 + 插件卸载全量落盘;首次启动恢复;死亡→复活链)以 `snapshotDir` 配置为总开关(`z.string()` 无默认,文档明示 "none when absent")——4999 此前未配置,「重启后全新命名空间」是预期行为,不是 bug。
117
+ - **启用**:`.dsh-test/profiles/web/cordis.patch.yml` dashr-repl 行加 `snapshotDir: /home/u1/workspaces/dashr/.dsh-test/snapshots`。
118
+ - **实证**(CDP 聊天驱动,session `69b311b1`):turn 1 `x=42` → `state.dill` 落盘(manifest `names:["ToolCallError","tool","x"]`)→ **daemon 重启** → 同会话 `print(x)` → session 落盘含 `namespace restored from the turn-1 snapshot` 且结果 **42** → turn-2 快照落盘。跨重启续命成立。
119
+ - 发布层默认仍 opt-in(每用户 DSH_HOME 路径由部署方定),测试实例已开。
120
+
121
+ ## §7 dill 快照/恢复 —— 第二独立实证(本会话 `8e966430`,2026-09-03)
122
+
123
+ 补 owner O-4 处置的第二条独立证据链,覆盖** dill 特有对象类型 + per-principal 隔离**(owner 证为简单 `x=42` + 根因/启用):
124
+
125
+ | # | 步骤 | 证据 |
126
+ |---|---|---|
127
+ | 1 | dill 能力门 | venv `dill 0.4.1` 可 import;cell 内 roundtrip lambda/闭包/类实例全过(`fn(21)=42` / `closure()=10` / `obj.tag=dill-probe`) |
128
+ | 2 | 播种 | turn-1 设 `marker` / `plain` / `fn`(lambda) / `closure` / `obj`(类实例) / `Probe`(类) |
129
+ | 3 | turn-end 落盘 | `<snapshots>/session-8e966430/state.dill`(3816 B) + `manifest.json`(`snapshotFormat:1, turn:1, skipped:false`,names 全含) |
130
+ | 4 | 可回放预检(免重启) | 对真实 `state.dill` `dill.load` → 全对象恢复且可用 |
131
+ | 5 | daemon 重启 | user 重启(`systemd-run --user`) |
132
+ | 6 | restore-on-first-boot | 同会话新内核:`[dashr] namespace restored from the turn-2 snapshot` |
133
+ | 7 | 复活核验 | `marker` / `plain` / `fn(21)=42` / `closure()=10` / `obj.tag` / `Probe` 全在位;**`x` 正确缺位**(属另一会话 `69b311b1`,证明 per-principal 键控精确) |
134
+ | 8 | 恢复后再写 | turn-3 快照落盘(`sizeBytes:7512`),链续写正常 |
135
+
136
+ 判定:dill 快照/恢复链**端到端闭环**——(a)dill 独有能力(lambda/闭包/类实例)在 dump→load→restore 全程无损;(b)per-principal 隔离精确(跨会话不串)。restore 依据「重启前最后一个好快照」(本会话为 turn-2 而非 turn-1),与 README「skipped 保留上一份好快照」语义一致。**O-4 正式关闭**(与 owner O-4 处置互为印证)。
@@ -0,0 +1,73 @@
1
+ # v0.2.1ef 开发审计报告 — ship-in-our-plugin 原则合规核查
2
+
3
+ > 2026-09-03 · 审计对象:change `2026-09-02-kernel-provisioning-completeness`(v0.2.1e)+ change `2026-09-03-plugin-shipped-ui-patches`(v0.2.1f)· 审计基准:upstream checkout `dsh-v0.1.2-alpha.5`(`db6bdc3576`)+ canonical `dashr/`(0.2.1-f)
4
+
5
+ ## 0. 一句话结论
6
+
7
+ **✅ 合规** —— 两个 change 的全部代码与声明式 patch 都落在 `@pgmi-builds/better-dsh` 包内随 npm 发布;四条官方扩展面(bundle patch 行 / 公开事件 / `dsh.client` 声明 / CSS·slot 注入)各就各位;upstream checkout 除 AGENTS.md 早已存档的环境级 patch 外**零改动**。唯一待办是把 0.2.1f 部署上 prod,让手改 patch 退役从「机制可行」变成「事实发生」。
8
+
9
+ **审计原则(user 总裁决)**:不管是 UI change 还是所有 change,都必须 ship in our plugin,而不是需要去 patch 源码。
10
+
11
+ ## 1. 审计方法
12
+
13
+ 四个维度交叉验证:
14
+
15
+ 1. 两份 design.md 的 Decision 逐条提取(D1–D6 / D1–D4);
16
+ 2. canonical `dashr/src/` + `cordis.patch.yml` + `package.json` 实现落点核对;
17
+ 3. upstream checkout `git status` / `git diff` 污染检查(区分环境 patch vs change patch);
18
+ 4. 两份实测报告(`v0.2.1e-P1-实测报告.md`、`v0.2.1f-plugin-shipped-ui-patches实测报告.md`)的运行证据回填。
19
+
20
+ ## 2. Change 1:kernel-provisioning-completeness(v0.2.1e)
21
+
22
+ | 设计要求 | 实现落点(均在插件包内) | 判定 |
23
+ |---|---|---|
24
+ | D2 三级触发 | ① `scripts/kernel-provision.mjs`(postinstall,在 npm `files` 发布清单);② `src/index.ts` apply 段 spin-up fire-and-forget `resolveKernelEnv`(不阻塞挂载、失败只 log);③ 首用 lazy 在 DashrRuntime(`kernelAutoInstall` 默认 true) | ✅ |
25
+ | D2/D6 fail-open | postinstall 任何失败 → 三条修复路提示 + `exit 0`,安装永不失败;零交互(无任何请求批准的路径) | ✅ |
26
+ | 插件领地边界 | `PACKAGE_ROOT = resolve(dirname(lib), '..')` → venv 落 `<包>/.venv-kernel`;实测(v0.2.1e 报告 §1-1)解释器在 `…/better-dsh/.venv-kernel/bin/python`(包内,CPython 3.11.15) | ✅ |
27
+ | D3 cache 邻位 | `UV_CACHE_DIR`/`UV_PYTHON_INSTALL_DIR` → `<venvDir>/../.uv-cache`(包内)+ `UV_LINK_MODE=copy`(`kernel-env.ts:133-138`);只读 HOME 无关 | ✅ |
28
+ | D4 版本锁 | `KERNEL_PYTHON_VERSION='3.11'` / `IPYKERNEL_VERSION='7.3.0'` / `DILL_VERSION='0.4.1'` 常量,pip/uv 命令带精确 pin | ✅ |
29
+
30
+ ## 3. Change 2:plugin-shipped-ui-patches(v0.2.1f)
31
+
32
+ | 腿 | 设计机制 | 实现 | 判定 |
33
+ |---|---|---|---|
34
+ | P2 fence | bundle patch 行整行重述 `connection` | `dashr/cordis.patch.yml` 末行:`trustedHosts: !!js (process.env.DSH_TRUSTED_HOSTS ?? '').split(/\s+/).filter(Boolean).concat(ctx.webRuntime.trustedHosts)`;随包发布(`files` 含 patch.yml + `exports` 暴露 `./cordis.patch.yml`)。这是**官方声明式 patch 线**(上游注释明示的扩展式),不是改上游文件 | ✅ |
35
+ | P2 isLoopback | `webserver/index-inject` 公开事件注入 boot script | `src/web-trust.ts`:`ctx.inject(['webServer'])` 条件挂载 + `ctx.on('webserver/index-inject')` 监听(emit 时新鲜读 config);host webserver 包仅 type-only import;防覆盖守卫 + JSON 嵌入 authorities;空态完全惰性 | ✅ |
36
+ | P3 mobile | client 半 CSS + 增量手势 | `src/mobile/gesture.ts`(纯函数)+ `src/mobile/client/index.ts`:CSS `<style data-plugin>` 注入(模块系统 `claimStyles` 认领的一等公民路径)、`ctx.layout.toggleSidebar()` 官方服务、右栏走 Better Sidebar DOM toggle(`[data-dsh-toggle-cluster]`);配置经页面全局 `__DASHR_MOBILE__`(client 半无 loader config,页面全局即配置通道);client 半经 package.json `dsh.client` 声明注册(`inject` 含 `@deepseek-ai/dsh-client-ui-layout`) | ✅ |
37
+ | D4 手改 patch 退役 | alpha.3 vendored 手改(`isLoopbackHostname` 双侧改)被取代 | 机制面完全取代(fence = patch 行,isLoopback = boot script);**prod 退役待部署**(见 §6) | ✅ 机制 / ⏳ 部署 |
38
+
39
+ ## 4. Upstream checkout 污染检查
40
+
41
+ `git status` 全部改动面(tag `dsh-v0.1.2-alpha.5`,detached `db6bdc3576`):
42
+
43
+ | 改动 | 定性 |
44
+ |---|---|
45
+ | `M package.json`(+`unrun` devDep) | 环境级:本机 Node 22.22.1 loader 链所需(AGENTS.md 已存档) |
46
+ | `M packages/client/tsdown.client.ts`(REPOSITORY_ROOT 探测) | 环境级 patch #1(AGENTS.md 已存档,缺此 build 即挂) |
47
+ | `M pnpm-workspace.yaml`(storeDir / verifyDepsBeforeRun / allowBuilds) | 环境级 patch #2(只读 store 重定向);`zeromq`/`@pgmi-builds/better-dsh` allowBuilds 条目是**包管理器构建脚本许可门**,非源码 patch,且设计显式容错(postinstall 被跳亦无妨,spin-up 是主路径) |
48
+ | `M pnpm-lock.yaml` | workspace install 正常产物 |
49
+ | `?? packages/better-dsh/` | 插件本体挂载位(workspace 成员),非 patch |
50
+ | `?? .graphifyignore` / `graphify-out/` | 无关图表工具产物 |
51
+
52
+ **两 change 在 upstream 侧的源码改动数 = 0。** canonical `dashr/` 与 monorepo 副本 src 树 + `cordis.patch.yml` 逐字节同步(diff 为空)。
53
+
54
+ ## 5. 附带核查
55
+
56
+ - **hashline edit 升级透传修复**(v0.2.1f 附录,commit `e27fdec`):落在 `src/url-schema/vendored/hashline/`——插件**自带的 vendored 副本**,随插件发布,合规。prod(3080,npm 0.2.1-d)仍带此 bug,随下个发布版本收敛。
57
+ - **4999 profile 层配置**(`.dsh-test/profiles/web/cordis.patch.yml` 的 `trustedPageAuthorities` / `snapshotDir`):官方分层里的用户 config(operator 信任声明 / 快照开关),非源码侵入——分层语义本就允许用户层覆盖插件行。
58
+
59
+ ## 6. 待办(非违规)
60
+
61
+ 1. **prod 部署 0.2.1f**(v0.2.1f 报告 §6 遗留):按年龄门精确版本流程(`dsh plugin add @pgmi-builds/better-dsh@0.2.1-f`)+ `trustedPageAuthorities`/`DSH_TRUSTED_HOSTS` 配置 + 旧手改 patch 清单 retired。部署完成前,prod 仍在跑 0.2.1-d + 旧手改文件。
62
+ 2. `ownsHost` off-label 风险 + connection 行形状漂移:已进 upstream-alignment S7 查表(两项)。
63
+
64
+ ## 7. 结论
65
+
66
+ 原则守住了:**所有 change 的代码与声明式 patch 都在 `@pgmi-builds/better-dsh` 包内随 npm 发布**——
67
+
68
+ - kernel 供给三级(postinstall / spin-up / lazy)全在插件领地,venv + uv-cache 落包内;
69
+ - P2 双腿 = bundle patch 行(fence)+ 公开事件 boot script(isLoopback);
70
+ - P3 = client 半官方注册(CSS 注入 + 增量手势);
71
+ - upstream checkout 除既有环境 patch 外零改动。
72
+
73
+ alpha.3 时代「升级即丢」的手改源码模式已在机制层面终结;剩余动作仅为一次版本化部署。