dsh-ptc-plus 0.5.3 → 0.5.6

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 (49) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +3 -3
  3. package/client.cjs +3326 -2881
  4. package/compiler-core.cjs +127 -127
  5. package/compiler-core.cjs.map +2 -2
  6. package/docs/README.md +1 -0
  7. package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +2 -2
  8. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +4 -4
  9. package/docs/architecture.md +1 -1
  10. package/docs/capability-planning-components.md +6 -6
  11. package/docs/capability-projection.md +1 -1
  12. package/docs/capability-surface.md +133 -0
  13. package/docs/client-ui.md +17 -15
  14. package/docs/client-visual-contract.md +7 -7
  15. package/docs/installation.md +14 -7
  16. package/docs/panel-concept.md +171 -0
  17. package/docs/publishing.md +1 -1
  18. package/docs/release-notes.md +1 -1
  19. package/docs/releases/v0.5.4.md +79 -0
  20. package/docs/releases/v0.5.5.md +41 -0
  21. package/docs/releases/v0.5.6.md +41 -0
  22. package/docs/runtime-reference.md +14 -0
  23. package/docs/verification.md +1 -1
  24. package/index.js +117 -30
  25. package/internal/binding-adoption.js +103 -11
  26. package/internal/capability-command-receipt.js +99 -15
  27. package/internal/capability-environment.js +1108 -348
  28. package/internal/capability-plan.js +18 -2
  29. package/internal/capability-policy.js +13 -0
  30. package/internal/capability-selection.js +330 -0
  31. package/internal/direct-surface-owner.js +17 -4
  32. package/internal/edit-transport-owner.js +3 -2
  33. package/internal/host-tool-sdk.js +17 -29
  34. package/internal/message-sources.js +21 -0
  35. package/internal/program-bindings.js +13 -4
  36. package/internal/runtime-bridge-owner.js +9 -9
  37. package/internal/runtime-config.js +10 -0
  38. package/internal/session-log-view.js +47 -5
  39. package/internal/settings-compat.js +6 -0
  40. package/internal/user-bindings-owner.js +20 -3
  41. package/package.json +45 -31
  42. package/src/client-authoring-view.js +7 -8
  43. package/src/client-capabilities-view.js +871 -948
  44. package/src/client-capability-sort.js +22 -9
  45. package/src/client-copy.js +116 -294
  46. package/src/client-settings-view.js +90 -33
  47. package/src/client-styles.js +67 -19
  48. package/src/client.js +46 -21
  49. package/internal/capability-delivery-proof.js +0 -70
@@ -15,17 +15,17 @@ npm run test:client:visual
15
15
 
16
16
  ## Coverage
17
17
 
18
- All fixture families exercise light and dark reference palettes, English and Chinese, and widths 320, 390 and 1440 px. Reference tokens deliberately exercise both foreground polarities; they do not claim to reproduce official or customized themes. The separate model-free packed acceptance uses DSH's public theme settings on an unmodified official Host, reuses the oracle for dock actions and the global workbench, and retains its existing actual editor, permission, session-log and layout assertions.
18
+ All fixture families exercise light and dark reference palettes; the families that render localized copy also exercise English and Chinese; each family uses the widths its own inventory declares, which include 320, 390, 1440 and 1920 px. Reference tokens deliberately exercise both foreground polarities; they do not claim to reproduce official or customized themes. The separate model-free packed acceptance uses DSH's public theme settings on an unmodified official Host, reuses the oracle for dock actions and the global workbench, and retains its existing actual editor, permission, session-log and layout assertions.
19
19
 
20
20
  | Surface | Actual controls | Visual states and evidence |
21
21
  | --- | --- | --- |
22
- | Settings and settings dialog | Disclosure, section navigation, fixed close button, action, numeric input, select, checkbox switch, capability search and independently scrolling choices | Normal, keyboard focus, disabled feedback; hover for commands/disclosure/navigation/close; large dialog containment, wide navigation/content columns and narrow stacking, header and navigation frame remain fixed during owned settings-column wheel scrolling and section selection; borderless title pointer/Space toggle, smaller static module captions and icon/arrow navigation rows are checked; shared parent-scroll counterexample is rejected; desktop native/fallback navigation at 240/420/600px heights reveals every Tab-focused switch/button and Enter target, including native Host insets, and rejects removal of the navigation scrolling constraint; 64px native Host overlay insets at 900px and 240px heights retain the dialog and close hit target; narrow 320/390×240 native dialogs also reveal each selected heading and focused section control, and reject restored stacked navigation; 48 long capability names, row nonoverlap and first/last choice reachability in both locales at narrow/wide widths; typed capability workbench exercises compatible type/source filters plus strategy/availability filters, stable sorting, unavailable preference removal, saved versus frozen Skill disclosure, tab arrow-key focus, one-shot filter, inheritance and row-editor windows that stay inside the viewport without moving navigation or the document; the row-editor window keeps every field flat (no disclosure rows, captioned description and source sections, a labeled common-baseline switch) |
22
+ | Settings and settings dialog | Disclosure, section navigation, fixed close button, action, numeric input, select, checkbox switch, capability search and independently scrolling choices | Normal, keyboard focus, disabled feedback; hover for commands/disclosure/navigation/close; large dialog containment, wide navigation/content columns and narrow stacking, header and navigation frame remain fixed during owned settings-column wheel scrolling and section selection; borderless title pointer/Space toggle, smaller static module captions and icon/arrow navigation rows are checked; shared parent-scroll counterexample is rejected; desktop native/fallback navigation at 240/420/600px heights reveals every Tab-focused switch/button and Enter target, including native Host insets, and rejects removal of the navigation scrolling constraint; 64px native Host overlay insets at 900px and 240px heights retain the dialog and close hit target; narrow 320/390×240 native dialogs also reveal each selected heading and focused section control, and reject restored stacked navigation; 48 long capability names, row nonoverlap and first/last choice reachability in both locales at narrow/wide widths; typed capability workbench exercises the one surface's table (five columns, one saved cell writing one field through the settings writer, and a sort control on every column whose cell is a comparable word), and the inheritance-rules window that stays inside the viewport; the settings batch is covered by the client cases; the page itself owns no second list, no row-editor window and no filter window |
23
23
  | Official plugin settings page | Section navigation, settings switches, numeric inputs and selects | Actual page renderer with padded columns and locally scrolling content; container-width stacking at 600px within a wide viewport; live pointer and Enter navigation at 320/390/1440px in both locales/themes retain nonzero document and Host-container scroll offsets; native `scrollIntoView()` counterexample must move an outer ancestor |
24
24
  | Global workbench and dialog | Selection, enable switch, icon commands, action buttons, input, instructions, search | Normal, focus, hover where the control or its owner supplies it, disabled feedback, long-label geometry |
25
25
  | Draft dock and enlarged review | All three actions, disclosure, separate resize/close icon controls, author attention badge | Native and absent-Button fallback matrix; normal, hover, focus, disabled, actual busy rendering; Enter saves exactly once; combined 320×240/320/400 short-width cases with long source and RPC errors, expanded reading thresholds and near-top anchors |
26
26
  | REPL | Observation selection, search, tabs, definition disclosure, four binding-name kinds | Normal and keyboard focus, definition hover, light/dark name readability, long inventory and source geometry |
27
27
  | Sparkle menu | Binding rows, disabled-group disclosure, authoring/revision/management/settings and fixed Back | 48 mixed entries; enabled-first counts and default collapse; native/fallback, English/Chinese, light/dark at 390×600, 320×420 and 320×240; independently scrolling catalog, fixed footer, actual action hits and keyboard access; single disabled entry with long purpose, 14px/21px and 24px/36px carrier typography; root and revision rows retain explicit enabled state and distinct green/gray badge text and backgrounds, with a same-color counterexample |
28
- | Session capability workbench | Modal catalog, grouped Tools/Skills/MCP servers and resources/MCP tools, source and state filters, shared Select, detail choice and fixed Discard / Apply to session / Apply to global | 80 ordinary tools plus Skill and MCP entries prove untruncated reachability; native/fallback, English/Chinese and light/dark at 320×240, 390×600, 768×720 and 1440×900; resolved Modal identity and actual DOM prove the native/fallback path; closed/open category Select screenshots, bounded modal, independent catalog scrolling, owned 13px body typography under a 24px/36px carrier, vertically centered SVG choice glyphs, detail choice and command application, phone list/detail drill-down, Home/End, arrow opening, typeahead and closed-trigger Tab navigation, separate Select portal containment, first Escape dismissal and trigger focus return, followed by Modal dismissal and focus return to the sparkle button |
28
+ | Session capability workbench | Modal catalog, one table in supply order narrowed by the category and source filters, shared Select, one control per fixed address, the batch window, the receipt column, and one declared visual state per session-column word (row stripe, state mark, tinted control), plus the saved column's own state word | 80 ordinary tools plus Skill and MCP entries prove untruncated reachability; native/fallback, English/Chinese and light/dark at 320×240, 390×600, 768×720 and 1440×900; resolved Modal identity and actual DOM prove the native/fallback path; bounded modal, independent catalog scrolling, owned 13px body typography under a 24px/36px carrier, vertically centered SVG choice glyphs, per-cell command application, `enabled`/`closed`/`automatic`/`inherit` and `use`/`skip`/`damaged` each proving their own row state, mark state and control tone, the saved column proving its own `enabled`/`closed`/`automatic` state words and the chip or trigger tone that carries them, closed-trigger Tab navigation, separate Select portal containment, first Escape dismissal and trigger focus return, followed by Modal dismissal and focus return to the sparkle button |
29
29
  | Command card | Action and native source disclosure | Readable/reachable actions, focus, disabled feedback; saved card remains compact; capability refresh shows only its outcome in one 13px/20px line without a command header, duplicate status or original-result disclosure; catalog count stays compact, all rows remain accessible in an independently scrolling table, and original result disclosure preserves exact JSON |
30
30
  | Tool row | Official DisclosureRow and fallback summary, inspection action, running/error/stopped status and description | Typography hierarchy, long descriptions, absent/multiple feature labels and long details; text containment, nonoverlap, preview spacing and separation from the following message; Enter expansion and inspection, focused inspection becomes visible; passive bounded hover/focus previews, clipping escape, viewport containment and unchanged conversation wheel ownership |
31
31
 
@@ -43,7 +43,7 @@ The draft oracle measures the CSS-owned preview budget and compact header contro
43
43
 
44
44
  The sparkle-menu typography oracle also requires the public Menu class slot to retain a bordered, rounded card with padding and shadow when Host CSS loads after plugin installation; injected border, radius and shadow removal must fail on the native surface. It requires a plugin-owned 13px/18px content base, 13px disclosure captions and binding names, 12px purposes and 11px states, all with 18px line-height and the inherited font family. It measures text ranges within their row for vertical clipping and checks the caret center against the caption line center, rather than its potentially stretched flex box; injected caption stretching must fail. Horizontal name/purpose ellipsis remains valid. Native/fallback fixtures reproduce a single disabled binding under larger carrier typography, preserve the full purpose title, reject injected inherited font-size and line-height, and accept a smaller carrier. The mixed-catalog root and revision paths and packed official-Host acceptance share the same oracle.
45
45
 
46
- The sparkle-menu oracle requires at least 24 px of catalog reading space, viewport containment, nonoverlapping catalog and footer, no outer scrolling, and fully reachable footer actions of at least 24 px height, including the capability-refresh command shortcut. The root starts with the enabled group without a scope caption, disabled-group disclosure uses a neutral rounded surface, binding states use green enabled and gray disabled pills in both root and revision lists; the oracle rejects missing state attributes or indistinguishable text/background colors, and authoring plus utility actions use two-column buttons with centered captions, balanced icon gutters and a soft fill without borders. The oracle measures caption centering against each button and rejects visible button borders. Command shortcuts fill the empty composer and close the menu; they never execute a command or overwrite unsent text. All settings and workbench switches use the official 36×20 capsule and 16px thumb with public theme tokens. Both checkbox pseudo-element and button/span switch thumbs are measured. The off-state oracle requires exact official geometry and token colors with a distinguishable thumb; checked states retain the contrast assertion and same-color thumb counterexample. MCP server source availability and disclosure use independent selectors with the shared Select appearance contract; browser fixtures change source availability from closed to parent rules while retaining child disclosure preferences. Capability workbench fixtures use the shared refresh component and verify explicit target selection, management-off synchronization and read-only reload separation. Per-row pick checkboxes with the first-column select-all drive the batch window in both the settings list and the session workbench; the session batch lists exactly the picked rows, stages without running commands, and keeps every action reachable at the smallest captured viewport. Scrolling the expanded mixed catalog and the revision list in both directions must leave footer geometry unchanged. Injecting a shared outer scroll container must fail the oracle; restoring the layout must pass. Actual catalog writes must retain a focused control whose center is inside the catalog clip and passes hit testing: collapsed disable, expanded enable, revision Back, and pending close/reopen are covered. Removing the reveal by resetting only the catalog scrollTop must fail this focus oracle; restoring it must pass. Page scroll and footer geometry remain unchanged. Packed official-Host acceptance repeats the mixed-catalog checks through the isolated profile and exercises actual management and settings actions.
46
+ The sparkle-menu oracle requires at least 24 px of catalog reading space, viewport containment, nonoverlapping catalog and footer, no outer scrolling, and fully reachable footer actions of at least 24 px height, including the capability-refresh command shortcut. The root starts with the enabled group without a scope caption, disabled-group disclosure uses a neutral rounded surface, binding states use green enabled and gray disabled pills in both root and revision lists; the oracle rejects missing state attributes or indistinguishable text/background colors, and authoring plus utility actions use two-column buttons with centered captions, balanced icon gutters and a soft fill without borders. The oracle measures caption centering against each button and rejects visible button borders. Command shortcuts fill the empty composer and close the menu; they never execute a command or overwrite unsent text. All settings and workbench switches use the official 36×20 capsule and 16px thumb with public theme tokens. Both checkbox pseudo-element and button/span switch thumbs are measured. The off-state oracle requires exact official geometry and token colors with a distinguishable thumb; checked states retain the contrast assertion and same-color thumb counterexample. Source-layer availability and disclosure are edited in the inheritance-rules window with the shared Select appearance contract; the client cases change a source rule's availability from a written word to the layer above while retaining the disclosure that rule layer holds, and the inheritance-rules window is measured inside the settings viewport. The shared refresh component and its explicit target selection, management-off synchronization and read-only reload separation are covered by the client cases. Per-row pick checkboxes (the header carries none) drive the session workbench's batch window, and a server row has no pick checkbox because the batch writes object entries while that row's own saved cell edits `mcpServers.<server>` on its own (§8.1a); the settings batch is exercised by the client cases instead of this fixture. The session batch lists exactly the picked rows, stages without running commands, writes one record per picked row, and stays a small in-viewport surface with no horizontal overflow. Scrolling the expanded mixed catalog and the revision list in both directions must leave footer geometry unchanged. Injecting a shared outer scroll container must fail the oracle; restoring the layout must pass. Actual catalog writes must retain a focused control whose center is inside the catalog clip and passes hit testing: collapsed disable, expanded enable, revision Back, and pending close/reopen are covered. Removing the reveal by resetting only the catalog scrollTop must fail this focus oracle; restoring it must pass. Page scroll and footer geometry remain unchanged. Packed official-Host acceptance repeats the mixed-catalog checks through the isolated profile and exercises actual management and settings actions.
47
47
 
48
48
  ## Limits
49
49
 
@@ -60,6 +60,6 @@ The layout and fallback inventories execute through `scripts/browser-case-runner
60
60
  Selection-required development entries are `test:client:layout:focus` and `test:client:fallback:focus`. They reject execution without `--case` before generating fixtures or starting Chromium; `--list` remains available. An independent layout run uses `test:client:fixtures` to select the two actual-renderer export owners. The complete visual gate retains the full Client suite once and every browser case. Runners report elapsed time; focused measurements remain separate from complete evidence.
61
61
 
62
62
 
63
- 能力工作台的单项规则显示独立的可用性与说明方式选择,默认与类别规则、常用集/统计/预算分配各有明确标签。
64
- 窄屏下两项选择换行并保持在列表边界内;会话工作台在原生与回退 Modal 中都能逐维提交,停用不丢失说明草稿。
65
- 聚焦浏览器的 `capability-workbench` 与 `session-capabilities` 场景使用当前组合配置和双维目录事实,验证控件可达、主题可读和维度命令读取确认;五列表头通过键盘循环三态排序且保留当前事实与草稿,短提示和统计参数直接可达。批量弹窗验证真实目标、取消不写与窄屏边界;筛选、继承规则与单项编辑同时验证独立小窗边界,观察说明验证灰色、基线对齐、自然换行和不溢出。会话能力另包含 320×420 与 1920×1080 的主题、语言及 native/fallback 组合。
63
+ 能力面的两个地址各显示自己那一对取值:能力行的保存·启用/保存·披露在设置入口是控件、在会话入口是陈述(服务行的保存·披露格写 `各成员自定`,不承载控件),本会话·启用/本会话·披露只在会话入口出现、是控件;两处共用同一份词表,默认与类别规则、常用集/统计/预算分配各有明确标签。
64
+ 窄屏下两项选择换行并保持在列表边界内;会话工作台在原生与回退 Modal 中都能逐维提交,停用不禁用行与控件,写不进去时命令通道的拒绝原文成为底栏回执。
65
+ 聚焦浏览器的 `capability-workbench` 与 `session-capabilities` 场景使用当前组合配置和双维目录事实,验证控件可达、主题可读和维度命令读取确认;设置入口五列、会话入口七列加回执列,会话入口另验证按供给顺序列出、每个可比较值的列表头带排序控件而回执列不带,设置入口验证五列、逐行控件与勾选计数。本会话列的四种能力状态(`enabled`/`closed`/`automatic`/`inherit`)与绑定行的三种取用状态(`use`/`skip`/`damaged`)分别断言行、格与标记携带同一状态值,并断言对应样式规则存在;`closed` 行另断言名称与来源降级显示。继承行(本会话没有记录)只在本会话列写 `inherit`、回执写「未写下」,页面不为它另造一个「答案」字形;服务层为某一维作答的成员行断言本会话列仍写 `inherit`、回执点名那一层、且行上没有第二组「答案」状态值;保存列同时断言自己的状态字(`data-state`)与颜色规则,保存·披露格断言不带状态值。这些断言证明声明与 DOM 事实,浏览器几何(色条宽度、圆点尺寸、对比度)不在本契约的测量范围内。会话能力的批量弹窗验证真实目标、窄屏边界与逐行写入;设置入口批量的「未确认不写、取消不写」由客户端用例覆盖。继承规则窗口验证独立小窗边界。统计参数与观察说明改由客户端用例覆盖:参数仍在面板内直接可达、观察说明的灰/换行/基线声明由 `test/client-runtime.spec.js` 的声明用例钉住,原本在浏览器里测量的渲染几何随旧目录一并移除,本契约不再声称它被测量。会话能力另包含 320×420 与 1920×1080 的主题、语言及 native/fallback 组合。
@@ -1,10 +1,10 @@
1
1
  # Installation
2
2
 
3
- PTC Plus requires Node.js `^22.19.0 || >=24.0.0` and targets the latest available DSH release with TypeScript PTC mode. Historical interface branches are retained through capability detection, without promising a fully verified earlier Host installation; when both generations expose competing presentation evidence, the current DSH contract wins. Compatibility follows those live extension surfaces rather than a version allowlist.
3
+ PTC Plus requires Node.js `^22.19.0 || >=24.0.0` and targets the latest available DSH release with TypeScript PTC mode. The runtime must also meet the selected Host's own Node.js requirement, which may be stricter than the plugin's range. Historical interface branches are retained through capability detection, without promising a fully verified earlier Host installation; when both generations expose competing presentation evidence, the current DSH contract wins. DSH checks the declared compatibility range before loading the plugin; runtime interface selection follows those live extension surfaces.
4
4
 
5
- The package declares `engines.dsh: "*"` for DSH's plugin compatibility preflight. This keeps release-number gating open while public capability checks and packed Host contracts establish compatibility; it does not claim that every historical or future Host has been tested. Host-owned service packages are peers of the plugin because the host supplies them; the PTC tool executor is an optional peer, because a host that keeps tool presentation in its registry does not publish that package at all.
5
+ The package declares `engines.dsh: ">=0.2.1-0 <0.2.3"` for DSH's plugin compatibility preflight. DSH evaluates that range, including prereleases, before loading the plugin. Public capability checks and packed Host contracts establish integration within the range; the declaration does not claim that every matching release has been tested. Host-owned service packages are peers of the plugin because the host supplies them; the PTC tool executor is an optional peer, because a host that keeps tool presentation in its registry does not publish that package at all.
6
6
 
7
- The worker uses the Host's Node executable. Startup verifies native REPL framing, imports, syntax failures, synchronous throws, awaited rejections, and original return values. The adapter combines public eval callbacks with domain error events before REPL formatting; a source-end witness distinguishes empty completion from falsy rejection. A failed or timed-out probe reports a runtime prerequisite failure before user code executes. The engine range follows DSH; CI exercises Node 22.19, 24, and 26, without claiming that untested future releases have already passed.
7
+ The worker uses the Host's Node executable. Startup verifies native REPL framing, imports, syntax failures, synchronous throws, awaited rejections, and original return values. The adapter combines public eval callbacks with domain error events before REPL formatting; a source-end witness distinguishes empty completion from falsy rejection. A failed or timed-out probe reports a runtime prerequisite failure before user code executes. The plugin engine range and the Host's engine range are separate requirements; CI exercises Node 22.19, 24, and 26, without claiming that untested future releases have already passed.
8
8
 
9
9
  Install the plugin into the profile that actually runs the target DSH surface. Do not assume a profile named `default` is active.
10
10
 
@@ -12,7 +12,7 @@ Install the plugin into the profile that actually runs the target DSH surface. D
12
12
 
13
13
  | Component | Current contract |
14
14
  | --- | --- |
15
- | DeepSeek Harness | Latest available release; validate the live public extension surfaces after every upstream release |
15
+ | DeepSeek Harness | `engines.dsh: ">=0.2.1-0 <0.2.3"`; DSH owns version preflight, while live public extension checks and packed Host contracts establish integration |
16
16
  | Runtime | DSH TypeScript PTC mode; cells currently accept modern JavaScript syntax |
17
17
  | Node.js | `^22.19.0 || >=24.0.0` |
18
18
  | Platforms | Windows CLI/Desktop and Linux CLI/Web verified locally; macOS package tests and import smoke run in CI, while live DSH integration and Desktop require release-time smoke testing |
@@ -32,7 +32,7 @@ The Client root requires `slots`, `locale`, `connection`, and `remote`; it adopt
32
32
 
33
33
  ### Compatibility Evidence
34
34
 
35
- Support is expressed as channels, not versions. `compat/channels.json` records, per channel, the host release each official dist-tag resolves to and the tarball integrity of every host package whose published surface the plugin probes. `latest` and `next` are the blocking channels; `alpha` is a pre-adaptation that reports without blocking. A probed package the release does not publish is recorded at the version and integrity its own declared dependency range resolves to, so a publish inside that range is a recorded drift; a probed package the release neither publishes nor depends on is recorded as absent, and the install proof rejects a graph that contains one. The recorded versions do not prove live registry availability or untested compatibility, and behaviour never branches on them: presentation, transport ownership and state retention are detected from the host's published shapes. `npm run host:channels:verify` checks the tracked manifest offline; `npm run host:channels:update` is the only command that resolves it from the registry.
35
+ The plugin declares a bounded `engines.dsh` range for manifest admission and leaves Host service peers unrestricted. This metadata does not prove a usable public extension surface; the selected Host must pass capability checks and packed contracts. Verification targets are expressed as channels, independently of the manifest range. `compat/channels.json` records, per channel, the host release each official dist-tag resolves to and the tarball integrity of every host package whose published surface the plugin probes. `latest` and `next` are the blocking channels; `alpha` carries the line this checkout develops against and reports without blocking a release. The development graph declares that channel rather than a release — every host `devDependencies` entry names it, and the lock resolves it — so a supported line is reached by moving the channel definition, not by editing the graph by hand. A probed package the release does not publish is recorded at the version and integrity its own declared dependency range resolves to, so a publish inside that range is a recorded drift; a probed package the release neither publishes nor depends on is recorded as absent, and the install proof rejects a graph that contains one. The recorded versions do not prove live registry availability or untested compatibility, and behaviour never branches on them: presentation, transport ownership and state retention are detected from the host's published shapes. `npm run host:channels:verify` checks the tracked manifest offline; `npm run host:channels:update` is the only command that resolves it from the registry.
36
36
 
37
37
  | Retained interface | Evidence and consequence of removal |
38
38
  | --- | --- |
@@ -54,7 +54,7 @@ Capabilities select behavior, never a release number. Historical fixture success
54
54
  Use this form after the selected version is available from the npm registry:
55
55
 
56
56
  ```sh
57
- dsh plugin --profile <profile> add dsh-ptc-plus@0.5.3
57
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.6
58
58
  dsh --profile <profile> --dump-config
59
59
  ```
60
60
 
@@ -159,7 +159,7 @@ dsh plugin add github:muyuanjin/dsh-ptc-plus#main
159
159
  dsh --dump-config
160
160
  ```
161
161
 
162
- After an npm release, the package spec may instead be `dsh-ptc-plus@0.5.3`. For a local package, use its absolute tarball path. Restart DSH Desktop after installation. Linux Desktop is not a current DSH Desktop release target; use DSH CLI/Web on Linux.
162
+ After an npm release, the package spec may instead be `dsh-ptc-plus@0.5.6`. For a local package, use its absolute tarball path. Restart DSH Desktop after installation. Linux Desktop is not a current DSH Desktop release target; use DSH CLI/Web on Linux.
163
163
 
164
164
  ## Upgrades
165
165
 
@@ -185,6 +185,13 @@ Start from the exact diagnostic: every message below names the surface that is m
185
185
  - `ptc-plus: Cordis companion tooling withdrew from an agent scope` — an exposed companion service, preset, Skill or child fiber failed its required contract. Repair the specific cause attached to the warning, or disable `cordisToolsEnabled` if that integration is unavailable. A scope missing optional companion surfaces instead waits silently and retries when its tool surface changes or its next prompt is assembled.
186
186
  - A commit is refused with a verification or proof error — follow [deterministic verification](verification.md): resolve any incomplete lanes shown by `npm run review:status`, run `npm run check` on the frozen tree, then `npm run review:finalize`. Stage that verified candidate and retry. Use `npm run hooks:install` if the hook is missing; never bypass it.
187
187
  - A historical PTC session cannot be resumed — follow the Session format upgrade below, keep the original log, and report the exact refusal message.
188
+ - A session cannot be exported or reopened, and the export reports `HTTP 500` — its log carries a session decision (a capability choice or a binding adoption) as a surface message appended before the Host had published its protected system head, and the released format refuses such a log on every read. The plugin now records both decisions as plugin records and adds no surface message. Stop the Host that owns the profile, then repair the artifact with the repair script from this repository's checkout (the installed package does not ship `scripts/`); the repair keeps every sequence number and turns only the offending statements into ignorable records, and each statement keeps the form that names its owner, so the capability panel and the binding group read back the decisions the session recorded:
189
+
190
+ ```sh
191
+ node scripts/repair-session-log.mjs --input /path/to/session.v4.jsonl.zstd --write --dsh-entry /path/to/dsh/lib/bin.js
192
+ ```
193
+
194
+ `--write` copies the original to `<input>.bak` first, and the command refuses to write a log the released format would still reject. Without `--write` it writes `session.repaired.jsonl.zstd` beside the input and leaves the original untouched, which is the way to inspect the result first.
188
195
 
189
196
  ## Session format upgrades
190
197
 
@@ -0,0 +1,171 @@
1
+ # 能力面板:施工契约(已被取代)
2
+
3
+ ## 0. 权威
4
+
5
+ **本文的页面形状已被 [能力面:概念契约](capability-surface.md) 取代。** 现行列集、取值、回执、入口与唯一渲染器由那份契约决定;本文继续生效的部分是 §1 的红线、§5 的写通道(行上的决定走的仍是同一条命令)与 §9 的落地位置,以及读路径的一致性要求。下文出现的七列、证据列、设置页清单投影都随该契约失效,保留在这里作为历史来源,不再是缺陷判据。
6
+
7
+
8
+ 非目标:不跨会话检索能力;不改冻结语义与 `/capabilities refresh` 的同步含义;不展示 prompt 原文、恢复快照或 worker 内部;不改 REPL 控制台与工作台的分工;**本面板不陈述物化**——方案由运行时在执行前构建,面板只陈述供给、记录与证据;不新增写入器、RPC 写操作或第二写通道。
9
+
10
+ ## 1. 红线:取值不得由面板之外的开关决定
11
+
12
+ 一个字段、一句文案、一个控件状态,若它的取值能被面板之外的任何来源改变——某个进程/服务/运行时/命令没有在运行,或任何全局开关没有启用——它就是缺陷。
13
+
14
+ 判定只有一句:**把那个来源摘掉,这个值会变吗?会变,它就不许存在。**
15
+
16
+ 这条覆盖两类来源,不是一类。「没有在跑」和「没有启用」是同一个错误的两种写法:都让面板去陈述一件它没有资格陈述的事。屏幕上的「未观察/尚未清点/暂不可用/未启用」之所以禁止,是因为它们都是同一个翻译动作的产物:把面板之外的缺失,翻译成面板之内的状态。
17
+
18
+ 推论:面板不需要知道有没有 PTC 运行时,也不需要知道某个开关是开是关;它一旦知道,就一定会在某处把这个知识画到屏幕上。行不存在,是唯一合法的「不能做这件事」的写法。
19
+
20
+ **这条分界线不落在运行时的有无上,落在「声明面」与「运行时」上。** 两者只差一句:
21
+
22
+ - **会话的声明面属于会话,必须读。** 这个会话作用域里的工具注册表视图、该作用域解析出的 Skill 层、prompt 装配在该作用域贡献的段,都是宿主对这个会话的供给。会话还有 agent 时,这三样都在它的 scope 上;`agent` 在这里只是取 scope 的句柄,不是「会话可用」的判断,也不是运行时。把它当成运行时来回避,就是把会话自己的声明面误记成 §1 禁止的来源。
23
+ - **PTC 运行时不属于声明面,一律不读。** worker、`canRefresh`、`run_code` 是否存在、方案投递(`prepare`/`refresh` 的重建与投递)、`session.append` 回答的是「这个会话现在能不能执行」,面板从不问这个问题。它们一旦被读,§1 的翻译动作就会以另一种拼写回来。
24
+ - **会话的 agent 已不在时,作用域随之消失**,面板读这个会话自己记录的冻结方案(§7)。冻结方案是会话的事实,不是运行时状态;拿宿主平面顶替它就是把这个缺陷换了方向——把「这个会话的声明面读不到」画成一张更小的表。记录里本来就没有面时(没有方案、方案损坏、或组合时就没有要求库存)这条读失败并点名缺的那条记录,而不是退回宿主平面、也不是画一张空表。
25
+
26
+ 分界只在读哪一处声明:有没有 agent 决定读 scope 还是读那份记录,不决定任何一格怎么写。
27
+
28
+ ## 2. 概念
29
+
30
+ | 概念 | 回答的问题 | 边界(属于 / 不属于) | 属于它的后果 | 不得混淆的邻居 |
31
+ | --- | --- | --- | --- | --- |
32
+ | **供给** | 宿主对这个会话声明存在什么 | 属于:该会话作用域里的工具注册表视图(含 preset 在 agent 作用域注册的工具)、该作用域解析出的 Skill 层、prompt 装配在该作用域贡献的 MCP/资源服务声明;这个会话的 agent 已不在时,属于它自己记录的冻结面。不属于:这个会话选了它没有、它有没有被证明用过 | 一条供给至少一行;供给没有,行就没有 | 记录:供给说「存在」,记录说「选了什么」 |
33
+ | **记录** | 这个会话写下过哪些决定 | 属于:绑定取用事件、能力选择事件。不属于:运行时构建出的方案、worker 装了什么 | 没有记录 ⇒ 该格取跟随保存的值;只有最后一条已投递方案带 `sessionOverrides` 的旧会话按那条方案折算出的同一条记录作答;绑定取用记录损坏 ⇒ 该行报记录损坏 | 供给:记录不能说某条目存在 |
34
+ | **证据** | 这个会话里有没有一条被接受的执行证明它被拿到过 | 属于:`tool/result` 的 `meta.dshPtcPlusCapabilities.used` 含该 id。不属于:方案、安装、模型是否知道 | 有 ⇒ 一个标记;没有 ⇒ 空格子,不是否定的词 | 记录:记录说「选了」,证据说「拿到过」 |
35
+ | **行** | 哪些对象各自构成一个可决定的单位 | 属于:宿主声明的能力、声明的 MCP 服务、全局绑定文档里 `enabled` 的条目。不属于:没有声明的、没有被供给的、统计聚合出来的 | 一行至少一个控件;对象不能被单独决定,它就不是行 | 组与批量:批量是「对已存在的行同时做同一个决定」,不产生行 |
36
+ | **控件** | 把一条新记录写进这个会话 | 属于:本会话的决定。不属于:全局配置(在设置页)、运行时动作 | 一行必有,永远可点,没有失败分支;写不进去说明该行不该存在 | 设置页的全局开关:它不决定这一行 |
37
+
38
+ 被删除的概念:清单可用性、就绪、处境、投递、`scope`、`plan`、`management`、`live`、`unreadableSupply`。它们不回答任何别的决定,只把面板之外的缺失翻译成界面。**没有这个概念,就没有它的词。**
39
+
40
+ ## 3. 行
41
+
42
+ - **能力行**:每个宿主声明的能力一条,恒在。声明没有的条目不会因为配置、记录或运行时有无而出现或消失。
43
+ - **服务行**:每个被声明的 MCP 服务一条,`mcpServers.<server>` 是它自己的决定。它是行,不是一批行:整台服务关掉是这个对象自己的决定,不是「筛选后批量」的替代品。
44
+ - **绑定行**:全局绑定文档里 `enabled` 的条目一条。未被供给的条目不进本面板——把它画成一行只会得到一个按不动的按钮。
45
+ - 行集只由供给决定;配置、记录、证据都不增减行。
46
+
47
+ 现行列集是 `对象 | 类型 | 来源 | 保存·启用 | 保存·披露 | 本会话·启用 | 本会话·披露` 加 `回执`(会话入口),由 [能力面:概念契约](capability-surface.md) §4 决定。下面这段是历史形状,不是缺陷判据:
48
+
49
+ - **保存**:当前配置里的值。能力行曾两维并写(`自动 · 自动`)——「自动」不是取值,这正是契约把它换掉的原因。
50
+ - **可用性/披露**:本会话记录的值,控件就在各自那一格,一格一个控件。
51
+ - **证据**:有执行报告时出现标记。这一列已随裁决四移出决定页,换成点名记录的回执列。
52
+
53
+ ## 4. 词表
54
+
55
+ 下面这张表是历史词表,不是缺陷判据:现行列名、取值与回执由 [能力面:概念契约](capability-surface.md) §4 与 §6 决定,本文的 `可用性`/`证据` 列名与 `开启`/`宿主`/`完整`/`按需`/`自适应`/`已证明` 已随该契约退场。
56
+
57
+ 没有否定词。每个词陈述一件存在的事实。
58
+
59
+ | 列 | 取值 |
60
+ | --- | --- |
61
+ | 来源 | `DSH 工具`|`MCP`|声明的 MCP 服务器名(全部列出,以 `、` 连接)|`多个服务器`|Skill 来源桶|`技能`|`全局绑定` |
62
+ | 保存·可用性 | `开启`|`关闭`|`自动` |
63
+ | 可用性 | `开启`|`关闭`|`自动`|`继承` |
64
+ | 保存·披露 | `宿主`|`完整`|`按需`|`自适应`|`自动` |
65
+ | 披露 | `宿主`|`完整`|`按需`|`自适应`|`自动`|`继承` |
66
+ | 可用性·取用 | `使用`|`不使用` |
67
+ | 证据 | `已证明` |
68
+
69
+ `自动` 是「这份记录没有为这个对象写下这一维」,`继承` 是「跟随保存列」,两者不互答。没有记录时可用性列与披露列写 `继承`,不写空、不写「未记录」。日志没有任何选择记录、而最后一条已投递方案带着 `sessionOverrides` 时,这两列陈述的是那条方案折算出的同一条记录(`decided`,标记 `legacy`);那条方案没有带任何选择时仍是 `继承`。方案的选择表读不出来时这条读是 `unreadable`:能力行没有表达它的词,这两列照常写 `继承`,`记录损坏` 只属于绑定组那条记录(见 §9 的未交付项)。
70
+
71
+ 唯一的例外,且必须同时满足三条:**只由 `classifyBindingAdoption` 返回 `unreadable` 触发**(记录存在但无法解析;记录不存在返回 `none`,不产生这个词);**陈述的是那条记录,不是面板的状态**;**同一行的控件仍然可点,写一条新记录即取代它**——`记录损坏`。它存在的理由只有一个:另一种做法是替会话报告一个它从未做过的决定。这个词只在面板的行上出现:模型可见的绑定目录没有位置表达「记录不可读」,它对同一条记录发布整份供给,所以 `记录损坏` 不能被读成模型目录的陈述(见 §9 的未交付项)。
72
+
73
+ 一个工具名同时被两个 server 命名空间命名时(`mcp__docs__deep__search` 同时以 `docs`、`docs__deep` 开头),来源列列出这两个 server;历史载荷只声明「有多个 server」而没有名单时写 `多个服务器`。两种写法都陈述存在的事实,来源列不写「未确认/未知/unknown」。
74
+
75
+ ## 5. 写通道
76
+
77
+ 一个意图:把一条新记录写进这个会话。写者只有一个,回执只有一种。
78
+
79
+ - 绑定 → 取用事件。能力/服务 → 选择事件(携带 id 与选择)。两者同形,都是这个会话的日志事件:`user/message` 携带 PTC 的 `source.form`,不新增事件类型(未知类型会让整份日志拒读)。
80
+ - 写者是**这个会话当前的写所有权**,不是「有没有 PTC 运行时」:
81
+ - 会话在 DSH 里活着(`sessions.get(id)` 有它,即使没有 PTC 运行时):用它的 `session.append`。
82
+ - 会话是冷的(不在 `sessions.get`):用持久化写句柄 `open(id, 'write')` → `append` → `flush` → **close**,并照运行时交还路径的做法先 `snapshotSessionEvent` 再 `foldSurface` 验证,再 append。
83
+ - 两个分支写的是同一条记录,回执由写者统一给出。**新会话不进入 PTC 模式时,它是活着的会话,走 append**——这正是今天会抛「select an active PTC session」的那一格。
84
+ - 命令事务(`/binding`、`/capabilities set`)与面板控件走同一个 owner、写同一条记录、给同一种回执。人类输入与面板不是两条路。
85
+ - 记录的物化在运行时:`preStep` 发现记录摘要与现有方案摘要不同时重建方案;`reconcilePendingChoice`、`pendingCommand`/`pendingPrevious` 失去依据,删除。
86
+ - **控件没有失败分支。** 没有禁用、没有预检、没有「先启用某开关」。凡是「这一行现在不能改」的情形,都说明该行不该存在。
87
+
88
+ 一个必然的推论:会话记录了选择,这个会话就是被管理的。全局开关决定这份记录**是否被应用**,不改变页面的任何一格:关掉时记录照旧保留、两列照常陈述,新的决定要到重新启用后才改变运行结果(`src/client-capabilities-view.js` 的格子不读这个开关;它决定的是方案的 `enabled`,以及只由管理开关决定的那种配置是否被发布)。要它成为 §1 禁止的那个来源,除非它开始改变某一格的值——那正是这条推论禁止的。
89
+
90
+ ## 6. 面板形状(出稿依据)
91
+
92
+ 一个 Modal(`管理会话能力`),五区,顺序固定:
93
+
94
+ 1. **头**:标题 + 当前会话标识 + 关闭。
95
+ 2. **工具栏**:搜索、类型筛选、来源筛选、批量(对已勾选的行做同一个决定)。
96
+ 3. **行区**:表格,§3 的列。
97
+ 4. **绑定组**:表格下方,同一套行与列语义;组永远在,行可以为零,零行就是空表,不配一句解释。
98
+ 5. **底部**:最近一次写入的回执。能力写入按当前界面语言陈述这次写了哪条记录、什么选择、写进哪个会话或全局设置;绑定组的写入回执是 `/binding` 命令返回的原文(英文),面板不改写它。回执不陈述证明程度,原始载荷留在命令自己的结果里。
99
+
100
+ 行不可展开:面板不陈述第六件事。七列已经分别陈述供给、记录与证据,行里没有可再展开的陈述。
101
+
102
+ 禁止出现在截图上:侧栏、产品名、版本号、服务状态、整块 `disabled` 的区域、空表头配一句解释的整块区域、任何否定词。
103
+
104
+ **图与词的分工**:稿决定版式、层级、控件形态与密度;**版式以本节文字为准,稿是它的实现目标**;文字一律按 §4 的词表写,图片模型生成的文字不作为契约。两者冲突时以本节与 §4 为准。
105
+
106
+ 本版设计稿:`artifacts/panel-mock/panel-0.5.5.png`(生成物,不入库)。
107
+
108
+ ## 7. 读契约
109
+
110
+ 一次读,三个来源,全成功或全失败:
111
+
112
+ 1. **会话头与事件**:同一次日志取用(`sessionLogOf`:`readSessionLog({id}, query)`;宿主没有 projection 服务时取该会话自己的 `snapshotEvents()`)同时给出 header(含工作目录)与事件。会话头与事件来自同一次日志取用;该次取用失败则整次读失败,不返回部分行集——没有 header 就没有目录,日志读不出时目录也没有。事件只用于取记录与证据。
113
+ 2. **供给**:读这个会话自己的声明面。两条分支,都不碰 PTC 运行时:
114
+ - **会话还有 agent**(任何 DSH agent;不看 `canRefresh`、不看 `run_code`、不看 worker):`assemble({ agent, scope: agent, ptcPlusCapabilityObservation: true })`、`toolSchemasForAgent(agent)`、`observeSkillsAt({ scope: agent, cwd })`。观察标志让这次公共装配保持被动:它贡献该作用域的段,不准备、不投递,也不重贴 model-facing 传输投影。`agent` 只作作用域句柄——用它判断会话是否可用、调用 `change`/`prepare`/`refresh` 的运行时分支、或 `session.append`,都是缺陷。
115
+ - **没有 agent 的冷会话**:从会话日志里最新一条方案消息的 `source.snapshot.capabilities` 取面(id/category/name/presentation),交给同一条行合成路径。这是这个会话记录的冻结面,不是宿主平面。这条记录能陈述面的前提是它真的冻结过一份库存:一份记录的 `settings` 经 `requiresCapabilityInventory` 判定为不要求库存时(能力与上下文总开关关闭,或能力管理关闭且记录的策略未启用统计与恢复——判据与组合时同一个 owner,`effectiveCapabilitySettings` 先按总开关压掉管理、统计与恢复)`capabilities` 是空数组,它陈述的是「这次组合没有把任何能力供给模型」,不是「宿主没有声明」。没有方案、方案损坏、或这种没有库存的记录,都让这条读失败并点名缺失的那条记录:不拿宿主平面顶替,也不返回空表——宿主平面只回答「宿主声明了什么」,不回答「这个会话被供给过什么」。
116
+ 配置:`capabilityConfiguration(currentConfig)`。
117
+ 3. **绑定文档**:`bindingRows` 读的全局绑定供给(`readUserBindings`),只为绑定组那几行,且只在全局绑定开关打开时读;它读不出时整次读同样失败,不返回部分行集。
118
+
119
+ 来源在实现里各自读,便于定位错误;但**任何一步失败就是整次读失败**:不做部分成功的响应。少了几行而屏幕不说,就是谎。
120
+
121
+ 这条读只有一个入口:`describeSessionCatalog`,两个入口都读它。请求指名会话时读该会话自己的日志与供给(同一个 scope,或同一份冻结方案);不指名会话时读 `hostSupply({})`,即宿主自己的进程级声明(不含 preset 在 agent 作用域注册的条目),不是任何会话的陈述,因此不充作会话的供给,且这样一次读不列出任何绑定行(绑定采纳没有保存地址)。读路径不得调用 `change`/`prepare`/`refresh` 的运行时分支、不得写(`session.append`)、不得 reconcile 待处理提案,也不得用 `canRefresh`/`run_code`/worker 判断这个会话能不能读:读不产生写,不改变进程态。
122
+
123
+ 读要么给出完整行集,要么整次失败。不存在部分成功的响应:少了几行而屏幕不说,就是谎。失败不是状态,是缺陷——面板给出原始错误、出错的文件或来源,以及重试;空表只表示「宿主真的没有声明」。
124
+
125
+ 响应(`ptc-capability-session-catalog/v2`):
126
+
127
+ ```
128
+ { schema: 'ptc-capability-session-catalog/v2', sessionId,
129
+ rows: [ { id, kind: 'capability'|'server'|'binding',
130
+ name, category, source,
131
+ saved, // 每行都有:能力/服务行取自己的规则,绑定行取绑定文档
132
+ session, // 本会话记录的值;绑定行另带 recorded 标明这条采纳是否被写下
133
+ record, // 能力/服务行:记录自己的字,layers 标明每一维由哪一层写下
134
+ evidence } ], // 能力行:boolean
135
+ config: { bindingsEnabled } }
136
+ ```
137
+
138
+ - 没有 `live`、没有 `scope`、没有 `plan`、没有 `management`、没有 `unreadableSupply`、没有 `capabilities: null`、没有 `defect` 字段。
139
+ - 失败走 RPC 错误通道,带原始错误;错误不分类来源枚举——来源枚举正是运行时重新溜回来的入口。
140
+
141
+ ## 8. 验收
142
+
143
+ 截图必须能判定:
144
+
145
+ 1. 五区齐备且顺序正确;没有 §6 的禁止项。
146
+ 2. 行区有真实的能力行与工具行(`tools.*`,含 `tools.mcp__<server>__*`)与 Skill 行(`skills.*`),条数可数;有被声明的 MCP 服务行。
147
+ 3. 每一行都有控件,形态是下拉或按钮,不是开关。
148
+ 4. 绑定组在表格下方,每行一个取用控件;组存在,即使零行。
149
+ 5. 全屏文字不含否定词族:`未观察`、`尚未清点`、`不可用`、`暂不可用`、`未记录`、`未证明`、`未启用`、`未确认`、`未知`、`unknown`、`unconfirmed`。
150
+ 6. 没有整块 `disabled` 区域。
151
+ 7. 新会话、不进入 PTC 模式打开面板:1–6 全部成立;进入 PTC 模式再打开:行集、行数与控件数不变。
152
+ 8. 点任一控件都能得到一种回执,底栏文字,与有无运行时无关。
153
+
154
+ **证伪方式**:把运行时摘掉重开面板,行集改为这个会话记录的冻结面:它与活读的差异只允许是方案冻结之后新注册的条目(集合差 ⊆ 新注册);该记录没有冻结过面时(没有方案、方案损坏、组合时没有要求库存)读失败并说明缺的是哪条记录,既不给一张更小的表,也不给一张空表。把任一全局开关关掉重开,行集必须只按供给变化(开关关掉的是供给,不是行里的值)。若变而本文没有授权,实现即缺陷。
155
+
156
+ ## 9. 实施落点
157
+
158
+ 本节只陈述已交付的落点;未交付的部分单列在末尾,读到它们不算读到授权。
159
+
160
+ - `internal/capability-selection.js`:`ptc-capability-selection/v1` 的正文与词表、`CAPABILITY_ENTRY_ID`(条目 id 的唯一词表)、`normalizeCapabilitySelection`;`capabilitySelectionText` 是一份记录的唯一正文字面;`capabilityRuleOfSelection` 是一个整选择与它陈述的维度规则相遇的唯一位置;`classifyCapabilitySelection` 与 `capabilitySelectionOf` 是启用与披露两列和组合入口共用的三态读(`none`/`decided`/`unreadable`);`capabilitySelectionOf` 在日志没有任何选择记录时把最新一条已投递方案的 `sessionOverrides` 折算成同一形态的 `decided`(带 `legacy` 标记):整选择词与维度规则写的同一个决定读成同一条记录,`prepare` 因此原地恢复那条方案而不是重建;有记录时以记录为准;该方案没有带任何选择时仍是 `none`(这两列照常写 `继承`),方案的选择表读不出来时是 `unreadable`,方案的 `source.sessionId` 不是本会话时不作为本会话的陈述。
161
+ - `internal/capability-environment.js`:`change()` 是唯一写者,按词表判断后写一条语句,不比较方案、不查运行时、不跑预检;`recordSelection` 通过宿主的 `appendPluginRecord` 把这条语句写成 `plugin:ptc-plus/capability-selection` 记录:决定做出的那一刻就落盘,不占 surface、不需要受保护 head、也不等待任何 step,因此新会话开始前的改动在下一次组合里就生效;记录不进入模型可见 surface,`capabilitySelectionOf` 直接读它(`user/message` 形态只作为 0.5.4 及更早会话的历史载体保留,`scripts/repair-session-log.mjs` 会把被旧版本写在 head 之前的语句转成同样的记录);写入后把这条事件并进本次观察的切面,紧接着的读不会回到被取代的那条;`prepare()` 在记录与已交付组合的 choices 不一致时重建(比较的是两者陈述的决定,不是拼写),重建沿用该组合的 `sourceSettings`(普通刷新仍以冻结来源为准,只有 `refresh` 读当前保存配置);`describeSessionCatalog` 按 §7 三源读:`sessionCatalogSupply` 决定读哪处声明(`liveAgentFor` 找到 agent 时由 `hostSupply` 以该 agent 为作用域取供给,否则读 `frozenSupply` 重放的冻结面),并在记录没有冻结过面时失败(没有方案、方案损坏、组合时没有要求库存——最后一种由记录自己的 `settings` 经 `requiresCapabilityInventory` 判定,与组合时的判据同一个 owner),`inventory` 接受 `access` 提供的注册表视图与 Skill 观察结果;server 行在 `capabilityRows` 合成且没有自己的披露;`bindingRows` 用 `bindingAdoptionOf` 的三态写绑定行的启用列(取用)。
162
+ - `internal/capability-command-receipt.js`:回执只校验它自己那句话需要的形式(无空白、有界长度)。条目 id 的词表由记录 owner 决定,回执不再保留第二个更窄的词表——更窄的那一个会拒掉会话已经写下的记录,于是写成功而回执成文为失败。
163
+ - `src/client-capabilities-view.js`:八列行模型、常驻绑定组、行内控件直接走命令通道、底栏与聊天卡片共用 `capabilityReceiptNotice`;`src/client-copy.js` 拥有页面自己的标签、区域标题与唯一一份取值词表(`capabilities.word.*`,两种语言各一份),词表的形状与退场词由 [能力面:概念契约](capability-surface.md) §4/§6 决定,接线与本地化由它自己的结构用例校对;`client.cjs` 是 `src/` 的构建产物,与 `scripts/client-fallback-smoke.mjs` 的断言在同一次改动里一起走。
164
+
165
+ 未交付,不得读成已交付:
166
+
167
+ - **模型可见的绑定目录没有「记录不可读」的表达。** 不可读的最新取用记录只在面板的行上读作 `记录损坏`;同一条记录交给模型目录时按「没有否决」处理,因此整份供给仍然发布给模型。要让模型也知道这条记录不可读,需要一个新增的模型可见陈述,本文没有授权它,也就没有它的词。
168
+ - **能力选择读不可读时面板没有词。** 一条无法解析的能力选择记录(或方案里读不出的选择表)让这条读成为 `unreadable`,而 §4 的例外只授权绑定组写 `记录损坏`:能力行的启用列与披露列没有词陈述它,仍按「没有记录」写 `继承`。要让能力行也陈述这条记录,需要一个本文没有授权的词,因此这里只把它记作未交付。
169
+ - **旧形态只覆盖以 `user/message` 投递的方案。** 一条只存在于命令回执提案里的方案由环境的恢复路径读(`recordedPlan`),不由这条陈述读覆盖:它不是会话的陈述,`prepare` 只把记录读到的选择与那条方案的选择逐项比较,相等时原地恢复那条方案,否则按该组合自己的 `sourceSettings` 与记录重算,那条提案自己的会话选择因此不被恢复(`docs/capability-planning-components.md` 记录了这一边界)。
170
+ - **冷会话的 Skill 来源桶没有记录。** 冻结方案里的 Skill 能力带 id、name、description 与调用资格,不带 provider/source 桶(它们不进入冻结能力快照),因此冷会话的 Skill 行来源列只写「技能」,不写活读能写出的桶名。要让冻结面也陈述桶,需要一个新增的冻结字段,本文没有授权它。这是两个面唯一按设计不同的列,`test/capability-environment.test.js` 的「the replayed Skill row states every column the live row states except the provider bucket」把这条边界钉成断言:重放行除来源桶外每一列都必须与活读相同。
171
+ - **绑定写所有权只有活会话这一条分支。** `internal/user-bindings-owner.js` 的 `recordAdoption` 要求活的 `session.append`;§5 的冷会话持久化写分支没有实现,冷会话写不了取用记录。
@@ -44,7 +44,7 @@ npm.cmd stage approve '<stage-id>' --registry=https://registry.npmjs.org/
44
44
 
45
45
  1. 提交前在稳定工作树上运行完整 `npm run check`,执行无覆盖插桩的完整普通后端测试并生成 review proof。覆盖率只在准备发布新版本时运行;Release workflow 在打包与 npm staging 前对 release tag 执行 `npm run coverage`,要求行与函数覆盖率 100%、分支覆盖率至少 95%。发布准备期间可在本地运行同一命令,并用 `npm run coverage:focus` 诊断覆盖率缺口;日常开发、审查与提交不运行覆盖率专用套件、采集探针或插桩分支;这些测试由 `test/coverage/` 和发布入口的显式标记拥有。仓库 CI 在 Linux Node `22.19.0`、24.x、26.x,以及 Windows 与 macOS Node 24.x 的干净安装上运行 `npm run verify:ci`,检查构建、Client 与跨平台关键运行契约;Ubuntu Node 24.x 另运行打包后的 `latest` / `next` Host contracts。普通 CI 不收集 coverage 或执行穷尽式后端套件。
46
46
  2. 运行 `npm audit --omit=dev`、`npx publint`、`git diff --check`、Markdown local-link check 和 `npm pack --silent --dry-run --json`。audit 检查随包安装的 production 依赖图;宿主 DSH 及其开发依赖不进入插件 tarball,由冻结宿主契约和 CI 单独验证。确认 tarball 只包含发布白名单内的运行时代码、文档和展示资产,不含凭据、本地路径、开发脚本或测试夹具,并执行 `npm run test:package:consumer -- <tarball>`:入口先校验当前安装的宿主与其 lock 一致,再将宿主实际提供的 peer 版本与 tarball 放在同一次 npm 安装事务中,在空目录执行 ESM import、内置编译器栈与内核 worker 加载 smoke。不能让 npm 对各宿主 peer 分别选用 dist-tag;插件继续声明不限制版本的 required peers,不私装宿主服务副本。机器读取 `npm pack --json` 时保持 `--silent`,避免 lifecycle 输出混入 JSON stream。
47
- 3. 更新到最新可用 DSH release 并记录 `dsh --version`。分别从 npm 包、固定 Git commit、源码 checkout 和 tarball 安装到临时 profile,再执行 `dsh --profile <profile> --dump-config`,确认与 `cordis.patch.yml` 一致:新增 `ptc-plus-execution`、`ptc-plus` 两项,并将原 `ptc-runtime` 的 `ptcRuntime` 服务隔离到 `ptc-plus-original`。每个上游 release 都重新验证公共扩展面、CLI/Web 集成和 profile 装配,不设置版本白名单。
47
+ 3. 更新到最新可用 DSH release 并记录 `dsh --version`。分别从 npm 包、固定 Git commit、源码 checkout 和 tarball 安装到临时 profile,再执行 `dsh --profile <profile> --dump-config`,确认与 `cordis.patch.yml` 一致:新增 `ptc-plus-execution`、`ptc-plus` 两项,并将原 `ptc-runtime` 的 `ptcRuntime` 服务隔离到 `ptc-plus-original`。每个上游 release 都重新验证公共扩展面、CLI/Web 集成和 profile 装配,并核对 `engines.dsh` 的上下界;范围内的宿主升级保留现有边界,运行时不按版本号选择接口。
48
48
  4. 在 Windows 与 Linux 运行无模型调用的 `npm run test:client:web -- --dsh-entry <latest-installed-dsh/lib/bin.js>`,验证 tarball 安装后的真实 Web Client、设置与对话 surface;浏览器前置条件见 [安装指南](installation.md)。`build:check`、Host ESM import 和 factory smoke 均不能替代浏览器激活验收。macOS 由原生 runner 验证 CLI/Web;Windows 与 macOS Desktop 从托盘打开当前 profile 的 DSH Terminal 安装,重启 Desktop 后做一次 PTC 模式 smoke。Desktop 当前发布平台不包括 Linux。界面有变化时用同一前置条件刷新 README 截图:`npm run readme:screenshots -- --dsh-entry <latest-installed-dsh/lib/bin.js>` 从当前打包候选各写回一帧中英文 REPL 工作台与设置窗口;先用 `--out <directory>` 落到别处检查,命令、前置条件与失败边界见 [安装指南](installation.md)。
49
49
  5. 只有在明确授权模型消耗后才运行 `npm run test:expensive` 与 `npm run test:ab`;发布候选还要用 `DSH_PTC_ACCEPTANCE_SCENARIOS=managed-adaptive-surface,managed-session-resume,managed-surface-change,subagent-continuity` 追加托管能力面、会话恢复、宿主表面变化与子代理场景(运行方式、预算与版本差异判别见[评估](evaluation.md#managed-session-continuity-cohort))。发布结论以结构化测试结果为准,不把一次模型样本推广为普遍保证。
50
50
  6. 确认 npm 包名可用、待发布版本高于 registry 版本、README 截图来自真实 DSH 会话,并核对 repository、homepage、bugs、license 与 `dsh-plugin` topic。
@@ -25,7 +25,7 @@
25
25
  4. **升级要求**:Node 版本、是否需要重启、是否有配置迁移。
26
26
  5. **内部交付**默认不出现;只有当它改变用户可见结果时,才用用户能理解的方式提及。
27
27
 
28
- 兼容性声明落在公共扩展面上——设置座位、slot、公共 `Menu` 区域、会话投影、能力探测。版本号只用于标明本次适配的目标发行,不构成版本白名单;能力与座位仍以宿主声明的公共扩展面为准([ADR 0017](adr/0017-track-the-latest-dsh-public-surface.md))。
28
+ 兼容性声明落在公共扩展面上——设置座位、slot、公共 `Menu` 区域、会话投影、能力探测。版本号可用于标明本次适配的目标发行及 `engines.dsh` 的安装准入范围;运行时能力与座位仍以宿主声明的公共扩展面为准([ADR 0017](adr/0017-track-the-latest-dsh-public-surface.md))。
29
29
 
30
30
  ## 风格
31
31
 
@@ -0,0 +1,79 @@
1
+ [中文](#cn-v054) | [English](#en-v054)
2
+
3
+ <h3 id="cn-v054">宿主适配</h3>
4
+
5
+ * 适配 DSH `0.2.2-alpha.3` 的公共扩展面,并保留上一代宿主调用方式;设置卡片、会话投影与公共 `Menu` 不要求宿主侧改动。兼容性按公共能力判定,不按版本号分支
6
+ * 会话的能力决定与绑定取用改为写进会话日志本身,不再占用对话消息:重载或重启后恢复会话时,面板读到的仍是当时那次决定,模型也不会因此多收到一条消息
7
+ * 支持哪些宿主仍由通道表达,而不是由版本号判定:`latest` 与 `next` 是阻塞通道,`alpha` 线只报告结果
8
+
9
+ <h3>新增</h3>
10
+
11
+ * 会话能力面板按「宿主提供了什么、这个会话记录了哪些决定、证据落在哪一层」重排:每行分列陈述对象、类型、来源、已保存的启用与披露、本会话的启用与披露,以及这一行的回执;点击列头可按该列排序
12
+ * 会话里直接列出全局绑定条目,并在面板里控制这个会话用不用它:每行按本会话的采纳记录读作「使用」「不使用」或「记录损坏」,点这一格就写下这个会话的取用;全局已停用的条目不出现在清单里。点击提交的就是人类输入的同一条 `/binding use|skip <id>` 命令,面板不新增写通道,结果按同一份会话能力目录回读
13
+ * 面板同时出现在会话入口与设置页:设置页编辑保存的规则,会话入口只写本会话的记录,两个入口各自固定自己的地址,不互相代替
14
+ * 支持一次选择多行、批量写下同一个决定,每行仍然各写一条记录,回执列逐行说明这次决定落在哪一层
15
+
16
+ <h3>修复</h3>
17
+
18
+ * 新版 DSH 中,`edit_run_code` 接受的修订继续属于原调用,保留本次运行可用的工具范围,并遵循宿主的策略与取消决定;后续单元格能继续使用修订后的状态
19
+ * 本会话关闭过的能力不再出现在任何模型可见处:`tools:sdk` 声明块、程序里真实的 `tools` 成员、`capabilities.*` 的探索结果,以及能力方案与说明段,都与这个会话真正可调的成员保持一致,关闭的能力不会只剩声明还在
20
+ * 已保存的开关单独成列陈述,不再与本会话的记录混读:一列只回答「保存了什么」,另一列只回答「这个会话记录了什么」
21
+ * 能力状态改用整块样式区分,而不是给控件里的文字染色:下拉控件保持正常文字颜色,只改它的填充与边框,行首的标记与那一格的词照旧陈述状态;只陈述文字的那一列改用同样底色的胶囊标签
22
+ * 能力变更的回执在会话里常驻:它不再因为会话里还没有人类消息而在发出第一句话时消失,连续几次写入合并成一张卡片、逐行列出这次改了哪些条目
23
+ * REPL 页签改排在宿主自己的页签之后,不再插在原生页签之间:对话、轨迹与实验性统计仍按宿主的顺序排列,REPL 尾随它们
24
+ * 设置页的能力表格恢复滚轮滚动:鼠标停在表格上时页面照常滚动;名称与来源单行省略,完整文字保留为悬浮提示,长名字不再把整行撑高
25
+ * 本版本写入的能力决定不会再让会话在重载时读不出来;旧版本留下的这类日志不再由新版写入
26
+ * 没有活动运行时的会话不再被读成「读不出来」:面板读它日志里最后一版方案,列出的行与有运行时时一致;真的读不出来时,错误与重试就写在行旁
27
+ * 绑定组永远在:读失败在行旁报出并可重试;可读但没有任何条目时它就是一张空表,不另配一句解释
28
+
29
+ <h3>升级</h3>
30
+
31
+ * Node.js 需同时满足插件的 `^22.19.0 || >=24.0.0` 与所选 DSH 的要求;DSH `0.2.2-alpha.3` 要求 Node.js `>=24.9.0`。升级插件后请重启 DSH
32
+ * 不需要迁移插件配置
33
+ * 若旧会话因能力决定或绑定取用被写到受保护的会话头之前而无法导出或重新打开,请先停止使用该 profile 的宿主,再用仓库 checkout 中的 `scripts/repair-session-log.mjs` 修复;该脚本不随 npm 包发布,插件升级不会自动改写历史日志。用法见[安装指南](../installation.md#troubleshooting)
34
+
35
+ ```sh
36
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.4
37
+ ```
38
+
39
+ ---
40
+
41
+ <h3 id="en-v054">Host Compatibility</h3>
42
+
43
+ * Adapts to the public extension surfaces of DSH `0.2.2-alpha.3` while retaining the previous Host invocation contract. Settings cards, session projections and the public `Menu` require no Host-side changes. Compatibility follows public capabilities rather than version branches
44
+ * A session's capability decisions and binding adoption are now written into the session log itself instead of taking up conversation messages: when a session is reloaded or resumed after a restart, the panel still reads the decision that was made, and the model receives no extra message for it
45
+ * Which hosts are supported is still expressed as channels rather than decided by a version number: `latest` and `next` are the blocking channels, and the `alpha` line is reported on without blocking a release
46
+
47
+ <h3>New Features</h3>
48
+
49
+ * The session capability panel is organised around what this host supplies, which decisions this session recorded, and which layer the evidence belongs to: each row states its object, type, source, the saved availability and disclosure, this session's availability and disclosure, and that row's receipt; a column header sorts by its own column
50
+ * The panel lists the global binding entries and controls, for this session, whether it uses one: every row reads as used in this session, not used in this session, or a damaged record, and its cell writes this session's adoption when it is clicked; an entry disabled globally is not listed at all. Clicking submits the same `/binding use|skip <id>` command a human types, the panel adds no write channel, and it reads the result back from the same session capability catalog
51
+ * The panel appears at both entrances: the settings page edits saved rules, the session entrance only writes this session's record, and each entrance fixes its own address instead of standing in for the other
52
+ * Several rows can be selected and given the same decision at once, each still writing its own record, and the receipt column says per row which layer the decision reached
53
+
54
+ <h3>Fixes</h3>
55
+
56
+ * On the new DSH, a revision accepted by `edit_run_code` stays within its original call, retains the tools admitted for that run, and follows Host policy and cancellation; later cells can continue using the revised state
57
+ * A capability this session closed no longer appears anywhere the model can see: the `tools:sdk` declaration block, the real `tools` members of a program, what `capabilities.*` can explore, and the capability plans and guidance sections all agree with the members this session can actually call, so a closed capability is never left declared on its own
58
+ * The saved switch is stated in its own column instead of being read together with this session's record: one column answers only "what is saved", the other only "what this session recorded"
59
+ * A capability state is told apart by the whole control instead of by tinting its words: a dropdown keeps the normal label colour and only its fill and border change, the row mark and the cell word still state the state, and a word-only cell states it as a chip of the same tone
60
+ * The receipt of a capability change now stays in the conversation: it no longer disappears when the first message gives the window a starting point, and several writes that arrive together are stated once, as one card listing what each one changed
61
+ * The REPL tab now trails the Host's own tabs instead of sorting between them: Conversation, Trajectory and the experimental statistics tab keep the Host's order, and REPL follows them
62
+ * The settings capability table scrolls with the wheel again: the page scrolls while the pointer is over the table, the name and source clip to one line with the full text kept as a tooltip, and a long name no longer makes its whole row taller
63
+ * A capability decision written by this version no longer makes a session unreadable when it is reloaded, and the logs older releases left behind are no longer written by this one
64
+ * A session with no live runtime is no longer read as unreadable: the panel reads the last plan its log carries and lists the same rows a live session lists, and a read that really fails states the error and its retry beside the rows
65
+ * The binding group is always present: a failed read is reported beside the rows with its retry, and a readable group with no entries is an empty table rather than a sentence explaining it
66
+
67
+ <h3>Upgrade</h3>
68
+
69
+ * Node.js must satisfy both the plugin's `^22.19.0 || >=24.0.0` range and the selected DSH requirements; DSH `0.2.2-alpha.3` requires Node.js `>=24.9.0`. Restart DSH after upgrading the plugin
70
+ * No plugin configuration migration is needed
71
+ * If an older session cannot be exported or reopened because capability decisions or binding adoption were written before its protected session head, stop the Host using that profile and repair the log with `scripts/repair-session-log.mjs` from the repository checkout. The script is not shipped in the npm package, and a plugin upgrade does not rewrite historical logs automatically. See the [installation guide](../installation.md#troubleshooting) for usage
72
+
73
+ ```sh
74
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.4
75
+ ```
76
+
77
+ ---
78
+
79
+ Full Changelog: https://github.com/muyuanjin/dsh-ptc-plus/compare/v0.5.3...v0.5.4
@@ -0,0 +1,41 @@
1
+ [中文](#cn-v055) | [English](#en-v055)
2
+
3
+ <h3 id="cn-v055">宿主适配</h3>
4
+
5
+ * 适配 DSH `0.2.2-rc.1` 的公共工具执行接口,保留上一代宿主的调用方式;兼容性按宿主提供的公共能力判定
6
+
7
+ <h3>修复</h3>
8
+
9
+ * 新版 DSH 中,`edit_run_code` 接受的修订保留原调用关系和本次运行可用的工具范围,继续遵循宿主策略与取消决定;后续单元格能继续使用修订后的状态
10
+
11
+ <h3>升级</h3>
12
+
13
+ * Node.js 需同时满足插件的 `^22.19.0 || >=24.0.0` 与所选 DSH 的要求;DSH `0.2.2-rc.1` 要求 Node.js `>=24.9.0`
14
+ * 无需迁移插件配置;升级后重启 DSH。插件升级不会自动改写历史会话日志
15
+
16
+ ```sh
17
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.5
18
+ ```
19
+
20
+ ---
21
+
22
+ <h3 id="en-v055">Host Compatibility</h3>
23
+
24
+ * Adapts to the public tool execution interface of DSH `0.2.2-rc.1` while retaining the previous Host invocation contract; compatibility follows the public capabilities the Host provides
25
+
26
+ <h3>Fixes</h3>
27
+
28
+ * On the new DSH, a revision accepted by `edit_run_code` retains its original call relationship and the tools admitted for that run, and continues to follow Host policy and cancellation; later cells can continue using the revised state
29
+
30
+ <h3>Upgrade</h3>
31
+
32
+ * Node.js must satisfy both the plugin's `^22.19.0 || >=24.0.0` range and the selected DSH requirements; DSH `0.2.2-rc.1` requires Node.js `>=24.9.0`
33
+ * No plugin configuration migration is needed; restart DSH after upgrading. A plugin upgrade does not rewrite historical session logs automatically
34
+
35
+ ```sh
36
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.5
37
+ ```
38
+
39
+ ---
40
+
41
+ Full Changelog: https://github.com/muyuanjin/dsh-ptc-plus/compare/v0.5.4...v0.5.5
@@ -0,0 +1,41 @@
1
+ [中文](#cn-v056) | [English](#en-v056)
2
+
3
+ <h3 id="cn-v056">宿主适配</h3>
4
+
5
+ * 声明 DSH 兼容范围 `>=0.2.1-0 <0.2.3`,由宿主按官方版本预检规则判断安装与启动资格;`0.2.2-rc.1` 在该范围内
6
+
7
+ <h3>修复</h3>
8
+
9
+ * 修复 0.5.5 将 DSH 兼容范围意外改成 `*` 的问题,恢复 0.5.4 的上下界;范围内的运行时接口仍按宿主公共能力选择
10
+
11
+ <h3>升级</h3>
12
+
13
+ * Node.js 需同时满足插件的 `^22.19.0 || >=24.0.0` 与所选 DSH 的要求;DSH `0.2.2-rc.1` 要求 Node.js `>=24.9.0`
14
+ * 无需迁移插件配置;升级后重启 DSH
15
+
16
+ ```sh
17
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.6
18
+ ```
19
+
20
+ ---
21
+
22
+ <h3 id="en-v056">Host Compatibility</h3>
23
+
24
+ * Declares the DSH compatibility range `>=0.2.1-0 <0.2.3`; the Host applies its official version preflight to installation and startup. This range includes `0.2.2-rc.1`
25
+
26
+ <h3>Fixes</h3>
27
+
28
+ * Fixes 0.5.5 unintentionally changing the DSH compatibility range to `*`, restoring the bounds from 0.5.4; runtime interfaces within that range continue to follow the Host's public capabilities
29
+
30
+ <h3>Upgrade</h3>
31
+
32
+ * Node.js must satisfy both the plugin's `^22.19.0 || >=24.0.0` range and the selected DSH requirements; DSH `0.2.2-rc.1` requires Node.js `>=24.9.0`
33
+ * No plugin configuration migration is needed; restart DSH after upgrading
34
+
35
+ ```sh
36
+ dsh plugin --profile <profile> add dsh-ptc-plus@0.5.6
37
+ ```
38
+
39
+ ---
40
+
41
+ Full Changelog: https://github.com/muyuanjin/dsh-ptc-plus/compare/v0.5.5...v0.5.6
@@ -49,6 +49,20 @@ The default SDK declares `capabilities.tree/find/inspect/search` directly. `sear
49
49
 
50
50
  The compatible `find` uses case-insensitive lexical matching, prioritizing exact `namespace.member` symbols, namespace names, and member names before complete identifier or description tokens. CamelCase and punctuation separate tokens; multiple query tokens must be contiguous. A miss means no lexical match, not proof that a capability is unavailable. `tree` and item-budgeted `inspect` keep their existing unbounded-byte interfaces. With capability management enabled, the SDK section is re-rendered from the frozen session plan: Host-declared members keep their Host schemas, complete and on-demand contracts arrive through session messages, and the always-callable `edit_run_code` transport keeps its Host signature in every render. Settings changes affect new sessions; `/capabilities refresh` synchronizes an existing session. See [public integration evidence](context-public-interface-coverage.md).
51
51
 
52
+ The declaration states the delivered capability set and nothing else. That set is the step's admission: the definitions the Host renders its own `tools:sdk` block from and builds a program's `tools` members from. A registered definition this step does not admit is therefore declared nowhere, and one session record that closes a capability removes it from the declaration, the program members and the explorable metadata at once instead of waiting for the next composition. A record is durable when it is made, so the surfaces that decide what can be called read it directly; the delivered plan catches up at the next accepted step and states the rest. The panel is a different read — it lists the rows a session can decide about, closed ones included.
53
+
54
+ A switch that is off delegates the Host surface, so the record is retained but not applied. A paused capability context and a disabled management switch both compose nothing and filter nothing: the declaration is the Host's own text, the program members are the Host's, and a closure the session recorded earlier applies again once management is on. Reading the record there would enforce a closure the same switch suspended, and enforce it only halfway — the switch also lets the Host execute that member. A session the Host still holds keeps the composition it froze, so its own snapshot decides whether this environment still applies; an agent with no composition yet answers from the configuration it would compose under.
55
+
56
+ A closure is one fact whichever layer of the record states it, so a projection never asks which document recorded the decision. A saved policy rule closes a capability, and so does the legacy overrides map of a plan composed before the policy generation that the session has not refreshed; one predicate reads both. A closure also reaches the rows whose contract names the closed member as their only model path: closing the `skill` loader keeps a Skill the user can still invoke with that remaining path stated and removes one that has no path left, and a resource server row states only the operations this session still has. A row may therefore never instruct a call the same session closed. A closure written for an MCP server states the server, not any one member of it, so it resolves through that one name to everything the server owns: the `mcp__<server>__*` tool rows, the derived `mcp.<server>` row, the `mcp:<server>` instructions that row depends on, and the `mcp-resource-servers` entry that names the server as the argument of the three resource operations. A registry view that still carries those members does not keep them on a surface, and the plan composed after the closure states the decision — its row is `closed` — rather than restating a calling contract.
57
+
58
+ Stating that path is a projection rule, not a composition rule. A composition states the path it was built under, and a decision recorded afterwards — `/capabilities` writes a record, never a plan — is already the session's newest statement, so an explorable row states the intersection of three statements: what the composition delivered, what the decision left, and what this step hands the program. The third is the same admission the declaration and the program members are made of: a composition is built once and reused while a step may deliver less, and a session that decided nothing does not recompose it, so a derived row's own contract is read against the members the cell really has. Absent that observation the composition's answer stands, because a caller that published no admission is not asking to state less than the session was composed from. A Skill row only ever loses the model path there, never gains one a composition did not state; a resource server row stays explorable only while an operation remains for its contract to name, and the guidance section and `mcp-resource-servers` directory entry it owns follow that same answer. One function states the resource sentence for both the composition and the read, so an unchanged session reads the same bytes.
59
+
60
+ The assembly observes that admission instead of inferring it. The Host resolves one admission per step and publishes it with the prompt context, and the registry read takes it as its limit, so the declaration, the plan and the program describe the step that is being assembled rather than every definition registered at that scope. The admission narrows this plugin's own contract view rather than replacing it: the definitions the Host publishes are model-facing and carry no output schema, so a capability recorded from them would promise an `unknown` result and a revision no live inventory agrees with. The same set bounds the repair of a top-level call into a program call: a model that names a member this step delivers is rewritten into `tools.<name>(...)`, and a name the registry merely carries is left as a top-level call for the Host to reject as unknown. A host that publishes no admission leaves the registry view as the only evidence, and that step's declaration is then as broad as its registry.
61
+
62
+ Guidance sections follow the same admission. A host that registers instructions for a tool states them as a `tool:<name>` section, and that text is a model-visible statement about a capability: a step that does not admit the definition delivers no member for it to instruct, so the section is withheld together with the declaration, the member and the metadata. The composition is not the admission — it is composed once and reused until the session decides something else — so a composition broader than the step (built from the registry or from an earlier step's admission) may not keep the section; a later step that delivers the definition states it again, which is why this is a statement about the step rather than a section deleted once. A projection that observed no admission keeps the registry view, as for the declaration. The two call transports are exempt: `run_code` and `edit_run_code` are the channel a program is called through, not capabilities.
63
+
64
+ The `mcp-resource-servers` directory follows the same rule, and it is the one Host section whose text *is* a list of capability names: its entries are the servers a program may pass as `server`, and the three resource operations are the only members that take one. A step that delivers none of them lists no server — the section leaves instead of naming a server no member of the program can name — and it returns on the step that delivers an operation again. The rows it is rewritten from are the resource server rows this step still states, so a server's own `mcp:<server>` instructions leave with the last row that named it and stay while a tool of that server is still delivered, because that text describes the server rather than one call's signature. A session with no composition states the directory from the admission alone, and a caller that observed no admission keeps the Host's own list.
65
+
52
66
  `tree()` returns namespace entries whose `members` are strings, not a flat symbol list. Form symbols with `tree.flatMap(entry => entry.members.map(member => `${entry.namespace}.${member}`))`. Reuse an observed tree within the current capability view and inspect only relevant symbols; do not infer completeness or effect guarantees from discovery. Exact symbols in examples are conditional on the live view. The advanced `repl.state` and `code.run` schemas remain behind inspection:
53
67
 
54
68
  ```ts
@@ -49,7 +49,7 @@ After the shared ledger, channel, semantic, build and syntax prerequisites pass,
49
49
 
50
50
  Both verification scopes produce a review-bound proof. Coverage runs only before a new version is released, as specified by [ADR 0035](adr/0035-run-coverage-only-before-a-new-release.md). CI starts from a clean lockfile install and runs `verify:ci` on every supported Node and operating-system entry: channel-manifest validation, semantic ownership, generated builds, Client tests, and focused runtime contracts covering compiler startup, helper-process lifecycle, plugin takeover, native-call transport, and durable argument diagnostics. A separate job per host channel packs the plugin and runs the host contracts against that channel's installed release. Normal CI therefore proves portable installation and runtime integration without running coverage-specific suites, collecting coverage, or running the exhaustive semantic suite on hosted runners.
51
51
 
52
- `host:channels:verify`, which is part of deterministic verification, is offline: it validates the tracked channel manifest — schema, per-channel dist-tag and blocking role, full coverage of the probed host packages, one release per pinned cohort, and a recorded integrity for each — without resolving a tag or installing a host. CI runs `test:host-contract` as one job per channel. Each job installs its channel on demand from the manifest into an ignored cache, proves the installed versions against the manifest, packs the plugin, and runs the host contracts through a repository-external consumer; the `alpha` job reports without failing the workflow. Registry resolution belongs only to `host:channels:update` and the scheduled channel-refresh workflow. That workflow publishes a changed manifest as a pull request and explicitly dispatches this CI workflow once because its `GITHUB_TOKEN`-authored events cannot start another run; ordinary gates never install a floating channel.
52
+ `host:channels:verify`, which is part of deterministic verification, is offline: it validates the tracked channel manifest — schema, per-channel dist-tag and blocking role, full coverage of the probed host packages, one release per pinned cohort, and a recorded integrity for each — without resolving a tag or installing a host. It also reports which channel the development graph declares and whether the lock materializes that record, so the checkout's own graph is read against the manifest the CI jobs install from. CI runs `test:host-contract` as one job per channel. Each job installs its channel on demand from the manifest into an ignored cache, proves the installed versions against the manifest, packs the plugin, and runs the host contracts through a repository-external consumer; the `alpha` job reports without failing the workflow. Registry resolution belongs only to `host:channels:update` and the scheduled channel-refresh workflow. That workflow publishes a changed manifest as a pull request and explicitly dispatches this CI workflow once because its `GITHUB_TOKEN`-authored events cannot start another run; ordinary gates never install a floating channel.
53
53
 
54
54
  ## Release coverage
55
55