dsh-ptc-plus 0.4.3 → 0.4.10

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 (66) hide show
  1. package/README.en.md +15 -3
  2. package/README.md +15 -3
  3. package/client.js +1157 -533
  4. package/cordis.patch.yml +12 -2
  5. package/docs/README.md +2 -0
  6. package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +60 -4
  7. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +5 -1
  8. package/docs/adr/0019-plugin-settings-and-kill-switch.md +14 -3
  9. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  10. package/docs/adr/0023-global-user-bindings.md +1 -1
  11. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +82 -18
  12. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +3 -3
  13. package/docs/adr/0032-own-session-log-facts-in-a-host-only-projection.md +27 -0
  14. package/docs/adr/0033-gate-client-visual-usability-in-a-browser.md +23 -0
  15. package/docs/architecture.md +6 -4
  16. package/docs/binding-review-placement-design.md +29 -21
  17. package/docs/client-ui.md +20 -8
  18. package/docs/client-visual-contract.md +48 -0
  19. package/docs/durability-design.md +12 -0
  20. package/docs/installation.md +48 -9
  21. package/docs/publishing.md +4 -4
  22. package/docs/release-notes.md +109 -0
  23. package/docs/runtime-reference.md +8 -2
  24. package/docs/user-bindings.en.md +2 -2
  25. package/docs/user-bindings.md +3 -3
  26. package/docs/verification-optimization-work.md +26 -0
  27. package/docs/verification.md +7 -1
  28. package/index.js +28 -7
  29. package/internal/compiler-platform.js +5 -3
  30. package/internal/compiler-service.js +2 -9
  31. package/internal/cordis-tools-owner.js +75 -16
  32. package/internal/direct-surface-owner.js +333 -7
  33. package/internal/edit-transport-owner.js +8 -5
  34. package/internal/execution-provider-owner.js +157 -0
  35. package/internal/execution-seam-compat.js +69 -113
  36. package/internal/isolated-worker.js +12 -8
  37. package/internal/recovery-tips.js +50 -21
  38. package/internal/rejected-cell-editor.js +11 -21
  39. package/internal/runtime-bridge-owner.js +88 -57
  40. package/internal/runtime-contexts.js +13 -13
  41. package/internal/session-events.js +40 -4
  42. package/internal/session-journal-recovery.js +678 -181
  43. package/internal/session-log-view.js +189 -43
  44. package/internal/session-runtime.js +58 -10
  45. package/internal/settings-compat.js +12 -2
  46. package/internal/user-bindings-owner.js +6 -5
  47. package/locale/en.json +6 -0
  48. package/locale/zh.json +6 -0
  49. package/package.json +18 -13
  50. package/src/client-authoring-view.js +222 -141
  51. package/src/client-binding-review.js +2 -0
  52. package/src/client-code-editor.js +6 -0
  53. package/src/client-copy.js +10 -0
  54. package/src/client-feature-gates.js +12 -5
  55. package/src/client-host-compat.js +23 -2
  56. package/src/client-primitives.js +249 -0
  57. package/src/client-repl-view.js +3 -3
  58. package/src/client-settings-view.js +2 -29
  59. package/src/client-styles.js +92 -33
  60. package/src/client-tool-view.js +8 -3
  61. package/src/client-workbench.js +9 -7
  62. package/src/client.js +72 -46
  63. package/assets/ptc-plus-bindings-en.png +0 -0
  64. package/assets/ptc-plus-bindings-zh.png +0 -0
  65. package/assets/ptc-plus-repair-en.png +0 -0
  66. package/assets/ptc-plus-repair-zh.png +0 -0
package/cordis.patch.yml CHANGED
@@ -1,5 +1,15 @@
1
- # Attach the session REPL after both the tools registry and Code Runtime exist.
2
- # The plugin adds a virtual rejected-cell edit transport beside DSH's run_code.
1
+ - id: ptc-runtime
2
+ isolate:
3
+ ptcRuntime: ptc-plus-original
4
+
3
5
  - insert:
6
+ - id: ptc-plus-execution
7
+ name: dsh-ptc-plus/execution-provider
8
+ intercept:
9
+ loader:
10
+ await: false
11
+ config:
12
+ originalEntryId: ptc-runtime
13
+ isolation: ptc-plus-original
4
14
  - id: ptc-plus
5
15
  name: dsh-ptc-plus
package/docs/README.md CHANGED
@@ -23,8 +23,10 @@
23
23
  ## Maintenance
24
24
 
25
25
  - [Deterministic Verification](verification.md): complete checks, backend test concurrency, coverage, and focused diagnostics.
26
+ - [Client Visual Contract](client-visual-contract.md): browser prerequisites, control and state coverage, fault counterexamples, and packed Host evidence boundaries.
26
27
  - [Incremental Review Verdict](adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md): predeclared parallel lanes, dependency-scoped invalidation, and the composite commit verdict.
27
28
  - [Focused Verification](verification-optimization-work.md): bounded coverage diagnostics and their relationship to the final verification gate.
28
29
  - [Semantic Validation](semantic-validation.md): pinned Test262 cases, dialect contracts, native differential matrices and their limits.
29
30
  - [Publishing](publishing.md): release checks, package contents, permissions, and platform validation.
31
+ - [GitHub Release Notes](release-notes.md): user-perspective priority order, required sections, bilingual style, and a worked example for release notes.
30
32
  - [Client UI](client-ui.md): current UI boundary and reevaluation criteria.
@@ -49,6 +49,25 @@ signal. A settled result retires the relation. The retained registration does no
49
49
  tool outside a code composition, and one shared session lifecycle revokes outstanding request and
50
50
  call records on session, agent, or plugin disposal.
51
51
 
52
+ The code composition deliberately retains a complete native registry and nested
53
+ SDK while the public assembly hook projects only the two direct transports.
54
+ This is an accepted exception to the Host recommendation that assembly hooks
55
+ should not change the visible tool list; registry and model-visible lists need
56
+ not be identical. Requiring stock `ptc` collapse would reject the editor, and
57
+ restricting the registry to the two transports would remove native program
58
+ bindings. Live-schema-proven native-call normalization is therefore retained
59
+ before persistence and Host dispatch, preserving call identity and native JSON
60
+ arguments through ordinary DSH validation, policy and approval. Stable
61
+ configuration still requires byte-stable plugin text and ordered schemas.
62
+
63
+ An unchanged native root call, including one left unchanged when canonicalization
64
+ is disabled, is rejected by the plugin's execution hook. Because Host
65
+ pre-execution approval precedes that hook, such a call can prompt for approval
66
+ before rejection; this ordering is an accepted limitation, not a registry-level
67
+ admission guarantee. Acceptance does not establish a new public direct-set API.
68
+ Revisit the projection if the official Host changes the assembly contract or
69
+ provides independent direct-tool admission without narrowing the nested SDK.
70
+
52
71
  `edit_run_code` targets the most recent editable cell in the current turn when its persisted
53
72
  `tool/call` event is recorded. Execution resolves that snapshot through the event sequence rather
54
73
  than reading the latest target when the handler begins. Intervening inspection tools do not erase
@@ -68,8 +87,10 @@ session-log projection captures the eligible target at the edit call event and a
68
87
  source only when its target sequence matches that snapshot and its journal is valid and non-noop,
69
88
  so live and recovered eligibility derive from the same persisted relation.
70
89
 
71
- The caller sends exactly one of `edits` or `regex_edits`, plus an optional non-negative
72
- `expected_target_call_seq` precondition. The precondition must equal the call sequence of the target
90
+ The public schema is one closed object with optional `edits`, `regex_edits`, and
91
+ `expected_target_call_seq` properties, avoiding duplicated object alternatives in the provider
92
+ prompt. Runtime validation still requires exactly one of `edits` or `regex_edits`, plus an optional
93
+ non-negative `expected_target_call_seq` precondition. The precondition must equal the call sequence of the target
73
94
  captured for the persisted edit event; a mismatch returns an unedited result before derived
74
95
  dispatch. Ordinary model-authored edits omit it and retain latest-target selection. Exact edits
75
96
  contain at most 16 items; each
@@ -95,11 +116,43 @@ tool/result: { edited: true, value?, error?, logs }
95
116
  The complete derived source, its journal, and its target call sequence are stored only in private tool-result metadata, including
96
117
  when the derived cell fails after entering the runtime. Cold
97
118
  recovery folds that explicitly marked derived run into the durable REPL history. The source is not
98
- copied into the model-visible edit result, and assistant stream chunks for the two declared
119
+ copied into the model-visible edit result. Valid assistant stream chunks for the two declared
99
120
  transports pass through unchanged.
100
121
  Consequently the UI and later model requests do not attribute a generated `run_code` call to the
101
122
  model.
102
123
 
124
+ The stream owner handles one bounded provider protocol failure before DSH assembles the assistant
125
+ message. It buffers tool-call material until the terminal event. If the response reports the exact
126
+ invalid-tool-JSON `MALFORMED_RESPONSE` as a terminal chunk or stream exception, it changes that
127
+ terminal reason to `tool-calls`.
128
+ DSH's existing Agent Loop
129
+ then preserves an unparseable argument as a string and routes it through ordinary tool validation,
130
+ execution, and result recording, after which the model receives another step. A malformed tool argument therefore
131
+ cannot become a turn-ending provider failure merely because this adapter parses it earlier than the
132
+ Agent Loop.
133
+
134
+ The stream owner preserves calls only when the buffered body consists entirely of
135
+ tool-call-specific framing plus at most one `usage` event. When that trusted body contains exactly
136
+ one complete, internally consistent declared `run_code` or `edit_run_code` block, the stream owner
137
+ first considers one correction: delete exactly one final `}`. The block index, call ID, name,
138
+ concatenated deltas, and final arguments must agree, and the candidate must parse as an object
139
+ accepted by that request's live direct-tool schema. A successful correction changes the final delta
140
+ and final block arguments before the same `tool-calls` settlement. Without that proof, trusted
141
+ internally consistent complete blocks retain their original identity and argument bytes for the
142
+ ordinary tool-error path. The owner re-emits those calls with canonical
143
+ `block-start`, full-argument delta, and `block-end` framing so provider variants tolerated by the
144
+ assembler also satisfy DSH's stream invariant. A final `block-end` is canonical even when the
145
+ provider emitted no deltas; when deltas exist, their supplied identity fields and accumulated
146
+ arguments must agree with it. An already visible open text or reasoning block is closed from its
147
+ accumulated content before the synthetic call. If any tool block is incomplete or inconsistent, or no tool block was
148
+ emitted, more than one usage event appears, or any other event occurs in the buffered body, the owner
149
+ removes unsafe block and unknown events, retains at most the first protocol-valid `usage`, and emits
150
+ one deterministic `run_code` call with an argument string that cannot parse as a JSON object. That
151
+ call can only fail DSH's ordinary schema
152
+ validation, so no untrusted partial call executes and the model still receives another step. Valid streams and every
153
+ other provider failure pass through unchanged. The rule does not insert missing delimiters, search
154
+ arbitrary edits, reinterpret native calls, or retry effects.
155
+
103
156
  No edit-specific runtime context is emitted. The truthful call/result pair already carries the
104
157
  operation and outcome; changing an aggregate runtime-context snapshot merely to restate that fact
105
158
  would repeat unrelated policy context. Rewrite feedback and unrelated recovery tips retain their
@@ -140,7 +193,10 @@ claim that the earlier execution was undone or idempotent.
140
193
  out-of-surface call are different protocol facts. Rewriting a real `edit_run_code` destroys a valid
141
194
  identity; normalizing a live-schema-proven native miscall to the declared `run_code` transport gives
142
195
  an otherwise invalid call its executable representation. Native-call canonicalization therefore
143
- remains available while the two declared transports pass through unchanged.
196
+ remains available. The bounded malformed-input correction likewise retains a declared call's identity.
197
+ Fallback settlement preserves arguments for trusted complete internally consistent blocks. Unsafe,
198
+ partial, or mixed buffered material is replaced by a validation-rejected `run_code` call only after
199
+ the provider itself reports the exact terminal protocol failure.
144
200
 
145
201
  ## Consequences
146
202
 
@@ -10,6 +10,10 @@ PTC Plus must remain independently installable on unmodified official DSH distri
10
10
 
11
11
  The compatibility target is the latest available DSH release. Production behavior, configuration, tests, installation guidance, and current compatibility claims depend on public extension contracts and observed live schemas, never on a DSH version allowlist or comparison. An upstream default projection is not an extension ceiling: when public scoped registration and presentation support a plugin-owned capability, PTC Plus preserves that capability and its model-visible identity instead of deleting or renaming it to match the default. Deterministic normalization remains valid for a call that is outside the declared direct surface when the live schema proves one native target and the lowering preserves arguments, call identity, authority, and result semantics. Deterministic tests exercise the consumed contracts; model-backed and packaging acceptance runners use the installed DSH and record `dsh --version` in generated reports so failures remain attributable without turning the observed value into policy. Concrete DSH release numbers may appear only in source comments that identify historical integration or evaluation evidence and cannot influence execution or acceptance.
12
12
 
13
+ Release discovery is separated from candidate verification. The root manifest declares the official `next` channel for the DSH packages used by development and freezes the resolved cohort in the root lockfile. `compat/latest` declares only the official DSH meta-package on `latest` and freezes that complete graph in its own lockfile. Resolved versions in these generated lock snapshots are reproducibility evidence selected by the channel declarations; they are not compatibility allowlists or runtime branches. Ordinary `verify` and `check` runs make no registry request and fail quickly when the installed root graph differs from the root lock.
14
+
15
+ The scheduled baseline refresh queries the official registry. When either channel moves, it updates both lock snapshots on an automation-owned branch, opens or updates one pull request, and dispatches the normal CI workflow once for that frozen candidate. GitHub suppresses workflow runs from branch and pull-request events produced by the workflow's `GITHUB_TOKEN`, so the explicit dispatch is the candidate's only CI run. If neither tag moved, it does not resolve or install the dependency graph. The Host contract suite tests the packed plugin against the root `next` graph and creates a repository-external consumer from the tracked `latest` lock. That consumer exposes the public packages from the selected Host graph to the plugin and runs the execution-seam, RPC-codec, and compressed Session persistence contracts. No compatibility run independently selects tags for DSH service packages, because their dist-tags need not move as one cohort.
16
+
13
17
  Preceding public contracts remain supported where capability detection is
14
18
  unambiguous. Tools presentation is selected by the installed public schema;
15
19
  Client contributions depend on their slots and supplied hooks rather than unused
@@ -69,4 +73,4 @@ capability, storage and observation rules independently of transport.
69
73
 
70
74
  Feature completion requires evidence from the actual packaged plugin running on the selected unmodified Host, including the affected user flow. Component fixtures and public-interface unit tests validate narrower properties; they do not prove that a required renderer exists or is loaded in that distribution. A clean code review and passing deterministic checks are separate from product acceptance. Both must cover the final change before a feature is described as delivered; commit and publish authorization remain separate user decisions.
71
75
 
72
- Each upstream DSH release becomes the immediate compatibility target and must pass the public-surface, packaging, and model-backed checks appropriate to the change. Users are not blocked by stale version metadata. Historical reports remain attributable through generated runtime metadata or source comments, while a passing older run never substitutes for validation against the latest release.
76
+ Each upstream DSH release becomes the immediate compatibility target and must pass the public-surface, packaging, and model-backed checks appropriate to the change. The automated pull request makes an upstream tag movement an explicit source candidate; the lockfile and CI result keep its proof reproducible after the registry moves again. Users are not blocked by stale version metadata. Historical reports remain attributable through generated runtime metadata or source comments, while a passing older run never substitutes for validation against the latest release.
@@ -8,17 +8,19 @@ Accepted
8
8
 
9
9
  ## Context
10
10
 
11
- PTC Plus 0.1.0 deliberately had no Client UI. The runtime surface was the DSH PTC mode `run_code`/`edit_run_code` transport, and adding a settings bundle was judged not to improve the core REPL path. The plugin also lacked a user-facing way to disable its runtime without removing the Cordis entry, and enabling/disabling state was invisible outside the session log. PTC Plus requires a plugin settings UI containing every Host Config field, a kill switch, and an explicit enabled marker. DSH's public settings service registers a namespace; the browser half contributes a card through the generation's settings seat, and the client reads the installed generation's settings transport (`configForms` on the current alpha, `settingsScope` on the preceding RC).
11
+ PTC Plus 0.1.0 deliberately had no Client UI. The runtime surface was the DSH PTC mode `run_code`/`edit_run_code` transport, and adding a settings bundle was judged not to improve the core REPL path. The plugin also lacked a user-facing way to disable its runtime without removing the Cordis entry, and enabling/disabling state was invisible outside the session log. PTC Plus requires a plugin settings UI containing every Host Config field, a kill switch, and an explicit enabled marker. DSH's public settings service registers a namespace; the browser half contributes a card through the generation's settings seat, and the client reads whichever public settings transport the installed Host exposes (`configForms` or `settingsScope`).
12
12
 
13
13
  ## Decision
14
14
 
15
15
  PTC Plus registers one DSH settings namespace `ptc-plus` with the same field list, defaults and validation as the Host Config schema. The field definitions live once in `internal/config-spec.js`; `index.js` builds the Cordis Config schema from it, and the esbuild client bundle imports the same module so the UI does not copy defaults or validation.
16
16
 
17
- The settings card belongs to plugin configuration. Current DSH renders a bundle's own configuration on the sidebar Plugins → Installed page through `plugins.row.config` (keyed, root) as `<bundle package name>#<row id>` and reserves `plugins.item` for the host-plane pages DSH itself ships. Preceding Hosts use `settings.plugin.item` (keyed, root) in the Settings panel, keyed by the served namespace. `src/client-host-compat.js` publishes to these plugin configuration seats through `ctx.slots.inject`, which waits until the owning page declares its slot. General settings may coexist with plugin configuration and is not a seat for this card. The composer shortcut opens an application-modal rendering of the same complete form, so direct access does not depend on a host page's component-local navigation state; its hover hint names the observed native plugin configuration seat. The package's top-level `icon` field points to a packaged SVG; DSH owns loading and displaying it on the installed bundle and row pages.
17
+ The settings card belongs to plugin configuration. Current DSH renders a bundle's own configuration on the sidebar Plugins → Installed page through `plugins.row.config` (keyed, root) as `<bundle package name>#<row id>` and reserves `plugins.item` for the host-plane pages DSH itself ships. Historical, unfrozen Hosts use `settings.plugin.item` (keyed, root) in the Settings panel, keyed by the served namespace. `src/client-host-compat.js` publishes to these plugin configuration seats through `ctx.slots.inject`, which waits until the owning page declares its slot. General settings may coexist with plugin configuration and is not a seat for this card. The composer shortcut opens an application-modal rendering of the same complete form, so direct access does not depend on a host page's component-local navigation state; its hover hint names the observed native plugin configuration seat. The package's top-level `icon` field points to a packaged SVG; DSH owns loading and displaying it on the installed bundle and row pages.
18
18
 
19
19
  The settings card places the plugin switch first, then groups controls by purpose: tool call tolerance, REPL syntax, state and recovery, tool extensions, interface display, and resource limits. Recovery tips and their thresholds stay together, and global binding management appears directly below its enable switch. `CONFIG_GROUPS` owns this presentation order independently of Host schema field order and defaults. `autoDescribeRunCode` defaults to true and controls only a request-bound local execution policy. When enabled, a call that omits the outer `description` uses derived arguments for local DSH validation, and the fallback summary enters presentation metadata only; when disabled, DSH validates the original arguments. Both states produce byte-stable model-visible tool schemas, order, and system sections with the required `description` declaration. Original call arguments, explicit summaries, cell source, and nested native-tool arguments remain unchanged.
20
20
 
21
- The configurable set is the Host runtime configuration plus `enabled: boolean` (default true). `enabled` is the kill switch: when false the Host keeps the settings namespace, client card, and passive message cleanup defined in [ADR 0010](0010-session-log-derived-recovery-tips.md). The next permitted accepted step may clear earlier PTC declarations. It does not install the runtime bridge, edit transport, direct-surface owner, system prompt section, tool registrations, or execution hooks, and does not read binding storage. When true the same runtime as pre-settings PTC Plus is installed. On the generations that expose a section installer, every field is live when its owner can reconcile it: the Host observes the settings scope and installs, uninstalls, or reconfigures owners without replacing existing session-bound bindings. The newest settings generation exposes no section installer and serves only fields marked volatile in the plugin's exported `Config`; the Host provides the form and commits volatile-only changes into the live references, notifying the owning fiber through the public `loader/volatile-update` event. The plugin subscribes and reconciles through its existing update path instead of running a per-field settings watch. Node fixes a worker's V8 `maxOldGenerationSizeMb` limit at construction, so changing that field while a session worker is active is rejected and the settings provider is restored to the previous value; other reconfiguration failures use the same compensation path. The TypeScript language check occurs at activation, allowing disabled settings to load on a host using another code runtime while rejecting and rolling back an enable attempt. If the settings service is absent, the Host falls back to composition config and enables the runtime.
21
+ The configurable set is the Host runtime configuration plus `enabled: boolean` (default true). `enabled` is the kill switch: when false the Host keeps the settings namespace, client card, and passive message cleanup defined in [ADR 0010](0010-session-log-derived-recovery-tips.md). The next permitted accepted step may clear earlier PTC declarations. It does not install the runtime bridge, edit transport, direct-surface owner, system prompt section, tool registrations, or execution hooks, and does not read binding storage. When true the same runtime as pre-settings PTC Plus is installed. On the generations that expose a section installer, every field is live when its owner can reconcile it: the Host observes the settings scope and installs, uninstalls, or reconfigures owners without replacing existing session-bound bindings. The volatile-only settings shape exposed by both frozen Host graphs has no section installer and serves only fields marked volatile in the plugin's exported `Config`; the Host provides the form and commits volatile-only changes into the live references, notifying the owning fiber through the public `loader/volatile-update` event. The plugin subscribes and reconciles through its existing update path instead of running a per-field settings watch. Node fixes a worker's V8 `maxOldGenerationSizeMb` limit at construction, so changing that field while a session worker is active or a submitted cell is preparing to execute is rejected and the settings provider is restored to the previous value; other reconfiguration failures use the same compensation path. The TypeScript language check occurs at activation, allowing disabled settings to load on a host using another code runtime while rejecting and rolling back an enable attempt. If the settings service is absent, the Host falls back to composition config and enables the runtime.
22
+
23
+ The host-only log-fact projection remains owned by the plugin/controller lifecycle when the runtime is disabled, as specified in [ADR 0032](0032-own-session-log-facts-in-a-host-only-projection.md). It supports passive message cleanup without retaining a worker, tool or default model-visible state projection.
22
24
 
23
25
  Every settings-card and PTC Plus tool-row string is registered into the DSH client locale namespace `settings.ptcPlus` and follows the active DSH client locale. Field copy exists in both locales from the single `internal/config-spec.js` source (`label`/`labelEn`, `description`/`descriptionEn`); display chrome copy is owned by the Client half. The stable REPL guidance remains plugin-owned protocol text without UI branding. The transport names remain `run_code`/`edit_run_code`; DSH owns their identity.
24
26
 
@@ -34,6 +36,15 @@ Feature notices name actual per-result events rather than configuration defaults
34
36
 
35
37
  Runtime activation is transactional. If a live enable cannot complete, every owner acquired before the failing setup step is disposed, the failure is logged, and the settings provider is asked to persist `enabled: false`; a failed compensating write remains an explicit activation diagnostic rather than an unreported state mismatch.
36
38
 
39
+ The settings compatibility owner binds the write identity when the provider
40
+ appears. A Host-owned `Config` document is addressed by its owning Loader
41
+ entry's profile ID; a historical section installer is addressed by its section
42
+ namespace. Enable-failure and live-reconfiguration compensation use that same
43
+ bound writer, not a fixed namespace substituted for the owning entry. The
44
+ writer and page policy are released with the settings provider.
45
+
46
+ Compatibility evidence and the consequences of removing historical branches are bounded by [Installation: Compatibility Evidence](../installation.md#compatibility-evidence). The two frozen graphs do not establish full Host coverage of the section-installer or settingsScope shapes.
47
+
37
48
  ## Alternatives Considered
38
49
 
39
50
  1. Keep no Client UI. Rejected: PTC Plus requires a settings surface and a kill switch. Away from settings, users cannot tell whether PTC Plus is actively installed because the only marker is application behavior.
@@ -14,7 +14,7 @@ Tool registration must finish before the prompt assembly returned to the agent;
14
14
 
15
15
  ## Decision
16
16
 
17
- Add `cordisToolsEnabled: boolean`, default `false`, as a live PTC Plus setting. When enabled, PTC Plus mounts the official `@deepseek-ai/dsh-tool-cordis` plugin and a maintained `@deepseek-ai/dsh-skill-filesystem` provider in each agent scope that exposes every surface the mount publishes through: `run_code`, the `skill` tool, and the public `agentPresets` and `skills` services; disabling it disposes both fibers immediately. The provider resolves the shipped `cordis` preset through the public `agentPresets` service and reads its sibling `skills` root without including default roots. At the public `skills.registerProvider` seam, PTC Plus transparently filters discovery and loading to exactly `cordis-plugin-development`; the maintained filesystem provider still owns parsing, resource bases, watch, invalidation, incomplete observations, and body loading. This prevents unrelated or obsolete sibling Skills from silently enlarging the PTC surface without copying the companion content or switching the current preset. A scope that omits one of those surfaces is not an error: the owner keeps the agent pending, publishes nothing there, and retries on the DSH tools-change signal or the next prompt assembly, because a later registration or provided service can supply the missing member ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
17
+ Add `cordisToolsEnabled: boolean`, default `false`, as a live PTC Plus setting. When enabled, PTC Plus mounts the official `@deepseek-ai/dsh-tool-cordis` plugin and a maintained `@deepseek-ai/dsh-skill-filesystem` provider in each agent scope that exposes every surface the mount publishes through: `run_code`, the `skill` tool, and the public `agentPresets` and `skills` services; disabling it disposes both fibers immediately. The provider resolves the shipped `cordis` preset through the public `agentPresets` service and reads its sibling `skills` root as an immutable bundled Host resource without including default roots or watching the packaged directory. At the public `skills.registerProvider` seam, PTC Plus transparently filters discovery and loading to exactly `cordis-plugin-development`; the maintained filesystem provider still owns parsing, resource bases, incomplete observations, and body loading. This prevents unrelated or obsolete sibling Skills from silently enlarging the PTC surface without copying the companion content or switching the current preset. A scope that omits one of those surfaces is not an error: the owner keeps the agent pending, publishes nothing there, and retries on the DSH tools-change signal or the next prompt assembly, because a later registration or provided service can supply the missing member ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
18
18
 
19
19
  The Skill provider and official Cordis child fiber form one reversible mount. Both must settle, and the scoped `skills` service must prove that `cordis-plugin-development` resolves from the added provider as model-invocable and loadable, before the first prompt assembly is returned. A prepended public `system-prompt/assemble` waterfall listener is the final race barrier: if collection began before the mount settled, it waits for readiness, discards that stale assembly, and invokes public assembly again so DSH recollects the official providers. It does not synthesize or mutate Cordis schemas or guidance. The Cordis fiber's resolved `inject` declaration is the authoritative required-service list, and its live registrations are the authoritative tool names, schemas, and guidance. A scope whose exposed preset, Skill service/tool, declared service, publication, or child fiber contradicts the DSH contract is a configuration error and rolls back every contribution; an absent surface only defers the mount. An unusable scope reached through the host's own calls — `agent/created` and the prepended waterfall — withdraws and reports one warning instead of failing the host operation that created the scope ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
20
20
 
@@ -24,7 +24,7 @@ Cordis tools remain native program bindings under `tools.*`. The PTC code-only d
24
24
 
25
25
  Cordis definitions and Runs are process-local, while PTC journals replay every settled program binding as a recorded value without redispatch. On the first prompt for an agent or a new Cordis enable generation, PTC Plus derives whether normalized journals contain a Cordis transcript. If they do, it emits the fixed `tools:ptc-plus-cordis-recovery` runtime context: recorded values remain journal data, but the model must perform a live read-only Cordis Inspect before relying on prior IDs, state, approvals, or capability observations. The context remains until a newly settled successful `cordis_inspect*` call appears in the session log. It neither asserts that live state was lost nor reruns a mutating call.
26
26
 
27
- Companion Skill resolution is capability-based. The generations that discover presets from their composition directories publish an absolute composition path for the shipped `cordis` preset, and PTC Plus reads the sibling `skills` root. A generation that declares presets without publishing any composition path publishes no companion Skill root through `agentPresets` at all: PTC Plus reports that missing publication as an unsupported surface, naming the surface and its consequence rather than a shape failure of a healthy host, and keeps the existing rollback or single-warning withdrawal instead of assuming a directory. An unusable preset (`broken`) is reported as unavailable before any path shape is considered.
27
+ Companion Skill resolution is capability-based. A generation that publishes an absolute composition path for the shipped `cordis` preset uses its sibling `skills` root. For a pathless generation, PTC Plus asks the Host's public `pluginPackages.packageOf` service for the active installation's `@deepseek-ai/dsh-agent-preset` or `@deepseek-ai/dsh-agent-presets` resource, then selects that generation's known Skill layout. Each resolution reads the current service after preset resolution; owner creation does not fix later mounts to an earlier service or its absence. Older generations that do not publish `pluginPackages` may resolve only the historical plural package from the Host's `ctx.baseUrl`; this compatibility path is disabled whenever the service exists, including when it returns no package. It never uses plugin-anchored ambient Node lookup, because a profile or Desktop installation may contain a stale package from another Host generation. PTC Plus accepts a root only when it contains the exact `cordis-plugin-development/SKILL.md`; it does not infer support from a package name or directory alone. An unusable preset (`broken`) is reported as unavailable before path or package resolution, while an invalid published path remains a host contradiction rather than falling through to a different generation.
28
28
 
29
29
  ## Alternatives Considered
30
30
 
@@ -69,7 +69,7 @@ An enabled agent whose effective public tool view contains `run_code` receives `
69
69
 
70
70
  Either command appends complete authoring instructions through `agent.steer` and completes admission once the normal Agent turn has been requested. Admission means authoring started, not that a candidate exists. Under enabled configuration, `code.submitBindingDraft({requestId, entry})` is a stable program SDK member, including its discovery schema. It uses the ordinary cell lease and program-call transcript. The Host captures the exact active request at cell creation and checks agent identity, request ID, generation, and single-submission eligibility before and after asynchronous validation. Acceptance, turn stop, error, cancellation, replacement, disablement, or disposal revokes submission eligibility without changing the declaration. No request-specific tool or Skill registration changes the system prefix. Cold replay returns a recorded receipt without submitting again or restoring writable access.
71
71
 
72
- The schema, SDK and authoring instructions include both `modelContext` fields. Authoring asks for a declaration-injection choice and a usage prompt containing only information missing from the interface; when types and API comments suffice, the prompt is empty. Edits preserve existing prompt preferences unless the requirement changes them. The workbench exposes both controls directly, without requiring source-edit mode; changes enter an unsaved draft with save and cancel actions. The input-dock review exposes accepted prompt metadata before a user saves it; the command card retains read-only history. Saving as disabled does not add configured API text to ordinary requests.
72
+ The schema, SDK and authoring instructions include both `modelContext` fields. Authoring asks for a declaration-injection choice and a usage prompt containing only information missing from the interface; when types and API comments suffice, the prompt is empty. Edits preserve existing prompt preferences unless the requirement changes them. The workbench exposes both controls directly, without requiring source-edit mode; changes enter an unsaved draft with save and cancel actions. The input-dock review exposes accepted prompt metadata before a user saves it; a zero-height plugin-owned anchor positions a portaled floating preview so disclosure does not resize the transcript or composer. An enlarged public Modal (or its plugin fallback) renders the same candidate and actions, with independently scrolling content and fixed header/footer. Returning to the preview changes only display; the portal yields when the composer entry is not reachable. The preview measures only its own anchor and visual viewport while visible, avoiding Host clipping/stacking without ancestor writes. In very limited space it shows the header and enlarge action. Neither presentation creates another review controller or write authority; the command card retains read-only history. Saving as disabled does not add configured API text to ordinary requests.
73
73
 
74
74
  Authoring uses ordinary `run_code` cells to develop and test pure logic with in-memory inputs, assertions and substitutes. Temporary session variables are permitted; the task prohibits test effects on external files and services. Imports and initializers with unknown effects are reviewed without execution. Tests can guide corrections and comparisons before the final source, exports, types and usage prompt are checked together. The answer reports verified behavior and untested integration, without requiring reasoning transcripts or a fixed number of calls. This is task guidance under DSH authority, not a sandbox or an additional permission mechanism. It does not expose the workbench's candidate runner to the Agent.
75
75
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  PTC Plus supplies the session-bound REPL by taking over the program-execution
6
6
  seam DSH uses for `run_code`. DSH registers that seam as a Cordis service and
7
- has renamed it between releases: the preceding generation published
7
+ has renamed it between releases: a historical request-only generation published
8
8
  `ctx.codeRuntime` (`@deepseek-ai/dsh-code-runtime`) and the current one publishes
9
9
  `ctx.ptcRuntime` (`@deepseek-ai/dsh-ptc-runtime`). A plugin that declares the
10
10
  removed name as a required injection never applies on the current host. Cordis
@@ -22,10 +22,41 @@ accepts a confinement request it cannot enforce silently weakens DSH's policy.
22
22
 
23
23
  ## Decision
24
24
 
25
- One owner attaches the plugin to the seam: `internal/execution-seam-compat.js`.
26
- It selects the seam from the registered service, not from a version string, and
27
- presents the same seam-neutral contract to the runtime bridge whatever the host
28
- generation is.
25
+ `internal/execution-provider-owner.js` owns public provider composition;
26
+ `internal/execution-seam-compat.js` owns live selection and the request/spec
27
+ boundary. Selection uses the registered capability, not a version string.
28
+
29
+ **Composition owns the routing relationship.** The shipped bundle preserves the
30
+ original `ptc-runtime` row's module and configuration and gives its `ptcRuntime`
31
+ service a named isolation. A separate execution-provider row observes that
32
+ original entry through public Loader resolution and injection, then registers a
33
+ plugin-owned global provider through Cordis. The main plugin installs its
34
+ execution callback only in that provider's private entry. The original service
35
+ is never modified and may be frozen or sealed. Custom compositions configure
36
+ the original entry ID and matching isolation explicitly. Entry IDs resolve in the
37
+ provider row’s owning Loader tree, including the profile’s Include subtree;
38
+ they are not assumed to be root-tree IDs.
39
+
40
+ The execution-provider row remains present when the main plugin is disabled;
41
+ without a callback it delegates native execution and capability getters to the
42
+ original. Its stable adapter follows original-generation replacement, but a
43
+ resolved spec remains bound to the generation that produced it and cannot run
44
+ after that generation retires. Before bundle removal changes the original isolation,
45
+ the public Loader lifecycle withdraws only the plugin's provider registration
46
+ synchronously, leaving the global service slot available for the original to
47
+ return. Cleanup cannot retire a newer registration. A plain, uncomposed provider
48
+ is a deployment error, not a reason to fall back to descriptor mutation.
49
+
50
+ Activation reads the current original generation's language through the live seam.
51
+ The adapter's stable identity does not make its first language a permanent fact;
52
+ an unsupported or unavailable current generation cannot authorize activation.
53
+ The original-generation observer also notifies the installed controller after source
54
+ replacement. An incompatible language retires the active PTC runtime without changing
55
+ the user's enabled setting; returning to TypeScript reconciles it again. Descriptor,
56
+ resolve/run and upstream delegation entries reject an installed-language mismatch
57
+ while that cleanup is pending, so SDK preparation cannot describe a different
58
+ language from the callback's execution. A TypeScript replacement retains the existing
59
+ session runtime. The subscription and its disposer belong to the injected controller.
29
60
 
30
61
  **Selection is a live capability.** The plugin's static injection names only the
31
62
  services both generations provide; the seam owner waits through `inject` for
@@ -48,14 +79,17 @@ failure naming the service; when a preceding-generation attachment exists, the
48
79
  report accompanies its restoration so `run_code` never silently returns to the
49
80
  host provider.
50
81
 
51
- **Execution is one neutral call shape.** The owner publishes `invokeUpstream`,
82
+ **New requests and resolved execution specs remain distinct.** The owner publishes `invokeUpstream`,
52
83
  which reproduces each generation's own call shape — directly for
53
84
  `run(request)`, and as `run(resolve(request))` for the two-step seam — and
54
- `takeOver(execute)`, which replaces the single execution entry and restores the
55
- exact descriptor it replaced. The plugin's entry receives exactly `program`,
56
- `bindings`, and `signal`: the fields PTC Plus has always consumed. A resolved
57
- spec's directory, deadline, and authority describe the provider whose execution
58
- was replaced; they are neither forwarded to the session kernel nor re-derived.
85
+ `installExecute(execute)`, which owns only the plugin provider's private callback
86
+ and returns its disposer. The plugin's entry receives the complete input.
87
+ `runUpstream(spec)` delegates an already resolved spec directly to the original
88
+ provider, retaining its object identity, cwd, deadline, sandbox policy and future
89
+ execution fields. Non-session callers use this path without resolving again.
90
+ Fresh isolated requests still use `invokeUpstream(request)`. Session cells consume
91
+ their program, bindings and signal under the session's own execution contract;
92
+ the boundary never drops fields before choosing which consumer owns execution.
59
93
 
60
94
  **The seam describes the execution the plugin performs.** While the plugin owns
61
95
  the seam it also answers the descriptors with its own behavior: no
@@ -69,10 +103,32 @@ DSH's authority decisions with DSH instead of accepting an input the plugin woul
69
103
  then ignore. Withdrawal is unconditional rather than generation-conditional,
70
104
  because the rule belongs to the plugin's execution rather than to a generation:
71
105
  the preceding generation's contract defines none of these members and nothing in
72
- its install closure reads them, so withdrawing there is inert, while a provider
73
- that did publish them cannot outlive the takeover. Every takeover and every
74
- withheld descriptor is released together, and a release leaves a descriptor that
75
- another owner replaced in the meantime.
106
+ its install closure reads them, so withdrawing there is inert. These values are
107
+ derived getters on the plugin provider, not replacement descriptors on the
108
+ original. Releasing the private callback restores native delegation and its
109
+ original capability values without any write to the original service.
110
+
111
+ **The tool-result bridge has a separate accepted compatibility boundary.**
112
+ `internal/runtime-bridge-owner.js` retains its wrappers on the registered
113
+ `run_code` definition's `execute` and `output.presentationMeta`. The latter
114
+ publishes execution-local journal, recovery, binding and presentation evidence;
115
+ the former supplies derived execution arguments when an omitted description is
116
+ generated, while the persisted model-authored arguments remain unchanged.
117
+ This bounded use of a shared tool definition is accepted even though public
118
+ lookup does not guarantee mutation support. It requires those properties to be
119
+ redefinable: frozen definitions or outputs reject execution and are not a
120
+ supported compatibility claim. Frozen original execution providers remain
121
+ supported through the independent composition described above.
122
+
123
+ The bridge retains call-local settlement isolation, native canonical values,
124
+ output limits, original callback receivers, and descriptor/ownership restoration
125
+ on rollback or disposal. DSH continues to own validation, policy, approval,
126
+ cancellation and final result projection. Acceptance retains this bridge rather
127
+ than claiming that a public per-execution metadata carrier or raw/derived input
128
+ protocol has been implemented. Replacing it becomes necessary if an official
129
+ Host changes this dependency or publishes an equivalent result/input contract.
130
+ The direct-tool projection has its own accepted boundary in
131
+ [ADR 0005](0005-temporary-rejected-cell-edit-transport.md).
76
132
 
77
133
  ## Alternatives considered
78
134
 
@@ -90,6 +146,10 @@ plugin would publish a service it does not implement, making this a provider
90
146
  rather than a consumer, and would have to model the wrapped provider's resolution
91
147
  semantics for callers that never reach its REPL.
92
148
 
149
+ **Replace descriptors on the registered original.** Public service lookup does
150
+ not grant mutation ownership. Such attachment fails on frozen providers and
151
+ cannot establish a durable extension contract; it is not a compatibility fallback.
152
+
93
153
  **Forward the resolved spec's directory, deadline, and policy to the session
94
154
  kernel.** The kernel has its own directory, budgets, and journal semantics; a
95
155
  per-call host deadline would have to be reconciled with the configured budget,
@@ -101,9 +161,13 @@ escalation it thinks it is offering.
101
161
 
102
162
  ## Consequences
103
163
 
104
- The plugin activates on both the current and the preceding host generation, and
105
- one test owner covers the selection rules, the neutral call shape, the descriptor
106
- takeover, and the release semantics for both. A host that registers neither
164
+ The frozen Host graphs exercise the `ptcRuntime` resolve/run shape. The
165
+ `codeRuntime` request-only shape is a historical compatibility branch with
166
+ fixture coverage, not a second frozen Host generation. The evidence boundary is
167
+ recorded in [Installation](../installation.md#compatibility-evidence).
168
+ Seam tests cover selection and input preservation for both shapes. Real public
169
+ Loader tests cover frozen originals, exact configuration and spec delegation,
170
+ main-plugin activation, source replacement and bundle removal. A host that registers neither
107
171
  execution service cannot be served, and its activation settles with a bounded
108
172
  diagnostic naming the missing seam — `no host execution seam (ptcRuntime or
109
173
  codeRuntime) is registered` — after the attachment window instead of staying
@@ -4,7 +4,7 @@ Date: 2026-09-18
4
4
 
5
5
  ## Problem
6
6
 
7
- PTC Plus publishes its Remote services through DSH's TYPERT registry, and that registry validates every strict codec it is handed before any endpoint exists. The codec carries the decoder for one wire member, and DSH changed where the host reads it: the preceding generation keeps the decoder on `codec.schema` and evaluates `codec.schema.parse(value)`, while the current generation keeps a `create()` factory, rejects a codec without it, and evaluates `codec.create().parse(value)`. The plugin published only the preceding shape, so a release that requires `create` fails registration inside the plugin's own activation: the Host entry never activates and the Client entry reports a failed fiber, although every import, load check, and type-level use still succeeds.
7
+ PTC Plus publishes its Remote services through DSH's TYPERT registry, and that registry validates every strict codec it is handed before any endpoint exists. The codec carries the decoder for one wire member, and DSH changed where the host reads it: a historical schema-based generation keeps the decoder on `codec.schema` and evaluates `codec.schema.parse(value)`, while the current generation keeps a `create()` factory, rejects a codec without it, and evaluates `codec.create().parse(value)`. The plugin published only the preceding shape, so a release that requires `create` fails registration inside the plugin's own activation: the Host entry never activates and the Client entry reports a failed fiber, although every import, load check, and type-level use still succeeds.
8
8
 
9
9
  ## Decision
10
10
 
@@ -12,7 +12,7 @@ PTC Plus publishes its Remote services through DSH's TYPERT registry, and that r
12
12
 
13
13
  Each generation validates only the member it owns and ignores the other, so one published contract serves whichever shape the installed host implements. Compatibility follows the live acceptance behavior of the registry rather than a release version, and the decoder is published once, so a host that reads both members cannot obtain two different decoders for one wire member.
14
14
 
15
- CI registers the packed contract with the installed host's own registry on both the stable and alpha channels (`scripts/dsh-rpc-contract-smoke.mjs`), so a generation that changes this validation fails the packaging check instead of reaching users.
15
+ CI registers the packed contract with the installed host's own registry from the frozen official `latest` and `next` graphs (`scripts/dsh-rpc-contract-smoke.mjs`). Both frozen graphs read `create()`; they do not exercise a schema-only Host. Unit fixtures cover `schema.parse`, not a complete historical Host installation. The evidence boundary is [Installation: Compatibility Evidence](../installation.md#compatibility-evidence); passing two graphs must not be reported as packaging verification of both codec shapes.
16
16
 
17
17
  ## Alternatives Considered
18
18
 
@@ -24,4 +24,4 @@ CI registers the packed contract with the installed host's own registry on both
24
24
 
25
25
  ## Consequences
26
26
 
27
- One plugin build serves the stable and alpha channels for this surface, and the compatibility rule lives in a single module with the decoder published once. A future generation that requires another member, or that rejects a codec carrying a member it does not know, needs this owner updated; the regression test is CI's registration against the installed registry, which fails on the channel that changed instead of on the user's machine. The decoder keeps the project's maintained schema runtime, so a host that validates payloads itself still evaluates the same semantics the plugin's own tests exercise through both members.
27
+ One plugin build carries both the historical schema-based and factory-based codec shapes, and the compatibility rule lives in a single module with the decoder published once. A future generation that requires another member, or that rejects a codec carrying a member it does not know, needs this owner updated; the regression test is CI's registration against the installed registry, which fails on the frozen Host graph that changed instead of on the user's machine. The decoder keeps the project's maintained schema runtime, so a host that validates payloads itself still evaluates the same semantics the plugin's own tests exercise through both members.
@@ -0,0 +1,27 @@
1
+ # Own session-log facts in a host-only projection
2
+
3
+ ## Problem
4
+
5
+ Synchronous prompt consumers repeatedly folded the complete session log and separately scanned historical runtime snapshots and tips. Recovery also read an obsolete Session snapshot API, so removing that API could turn unavailable history into an apparently empty session. Independent caches at each consumer would retain duplicate semantic rules and cannot prove a common observation cut.
6
+
7
+ ## Decision
8
+
9
+ `internal/session-journal-recovery.js` owns one synchronous event transition for the executable call/result timeline. Batch cold recovery and the host-only `ptcPlusSessionLog` projection use that same transition. The projection is registered through `sessionProjections` under its injected Cordis effect, has plain JSON state and an explicit state version, and publishes no Client wire view. Irrelevant log-only events return the previous reference.
10
+
11
+ The state preserves pending and ambiguous call identities, turn scope, edit-target claims, prune windows, normalized journals and transcript counts. It stores minimal call evidence and deterministic non-content result identity digests, not a second raw event log. Runtime presentation adds the ordered surface sequence vector and recognized runtime records. Replacement follows surface positions, not numeric sequence ranges: a newly appended replacement can occupy an earlier surface position. Historical notice identity, per-trigger ordinal, cooldown and unresolved escalation counts are updated at event entry; synchronous consumers read those facts without scanning the historical arrays.
12
+
13
+ Asynchronous consumers obtain an immutable cut from the public `sessionQuery.observeSession` reader, use `projectionMode: 'none'`, and release the observation lease. The captured cut is passed through recovery, call matching, no-op confirmation and derived edit execution. Its surface evidence is paired with that cut; a newer live surface cannot silently change an earlier observation. Historical array-backed sessions retain a read-only batch fallback over the shared transition. Missing current services or malformed historical arrays are diagnosed rather than represented as successful empty evidence. Cancellation and Host query failures remain authoritative errors.
14
+
15
+ The log-fact owner belongs to the plugin/controller lifecycle rather than an enabled worker activation. Disabling the runtime therefore leaves this host-only unit available to retract previously delivered PTC messages, while releasing tools, workers and enabled-generation UI projections. Unloading the plugin releases the unit. This does not keep hidden computation alive or inject a model-visible binding projection.
16
+
17
+ Result republication preserves the original settlement position and normalized evidence. A content-only prune clone, including a clone of another clone, is not a new execution, edit target, success or claim settlement. If the original result is absent, the original call position bounds the newly reconstructed chronology; later executions remain later. Tip identities retain their delivery positions so discovering an earlier success does not erase warnings delivered afterward.
18
+
19
+ Projection checkpoints are fold shortcuts only. State version 8 retains each settlement's independent publication index, first-observed index, ordinary/reconstructed classification and normalized run evidence, including ordinary runs without journals. Ordinary-result deduplication retains the first observation's call, event sequence and timeline position; admission requires matching ordinary settlement evidence or an identity-conflict clear, and every ordinary settlement requires its observation. It also retains the processed timeline position and ordered selection clears for turn resets and invalidations. The current frontier must agree with that retained lifecycle history and remain within the processed cut. Latest and editable runs are derived from the newest current-scope publication beyond that frontier; the success index is derived from retained successful publications. Edit targets and claim eligibility at dispatch are reconstructed from first-observed settlements and clears, using the same selection and target capture rules as the live transition. Their source must match the eligible ordinary or derived publication, and both current claim tables must match the reconstructed lifecycle. A late prune reconstruction cannot establish a target for an earlier dispatch. Selected fields and redundant target copies cannot certify their own provenance or chronology, and clones cannot revive a selection across an invalidation frontier. Normalized event facts retain call identity/source, result identity digests and formal source/replacement relations, public prune and turn inputs, journal presence, normalized settlement and recovery-boundary outcomes, and validated rewrites. They retain no result content. Checkpoint admission reconstructs the complete timeline with the same single-event transition used by live folding, then compares every materialized field. Journal/derived/binding facts, ordinary observations, settlements, selection, claims, transcript counters, unavailable evidence, pending/seen identities and the active prune window therefore share one lifecycle interpretation. Typed payload validation and the existing journal/derived/boundary owners validate the retained normalized inputs. The projection also retains presentation input facts: public append/replacement intents, context-step source categories and recognized runtime-message protocol inputs. Ordinary user and assistant content is omitted. These facts align with timeline event identity and drive the same projection transition at admission. The complete reconstructed projection must agree with the checkpoint, including ordered surface nodes, visible records/facts, message indexes, context steps and notice history. A historical catalog record therefore cannot certify its own visibility, and removing all visibility caches cannot suppress an actual append. Prompt consumers continue reading incremental state without raw-log scans. Missing settlements or valid-shaped journal divergences cannot be hidden by deleting their dependent caches. The timeline representation owner validates these relations together with typed table payloads, call/entry identities, normalized journals, derived runs and transcript counts before projection admission. Obsolete v1–v7 state requires refolding the complete log; a nonzero-start suffix alone is rejected with a seq-0 reread diagnostic. The Host owns watermark validation, suffix restore, fork inheritance and refolding. Raw journal ancestry and exact model-visible source relations still own recovery evidence. UI facts, cached state and matching recorded completions are not substitutes.
20
+
21
+ Submitting a cell reserves its memory configuration with the SessionRuntime owner before the first asynchronous observation on either the run or edit entry. The bridge and derived edit carry that same submission and its captured cut into execution rather than creating a second admission after reading. Runtime or session disposal invalidates that preparation, and an invalidated preparation cannot create a kernel or worker after the reader resumes. Reader failure releases the reservation; a genuinely new submission can use a fresh environment. Caller cancellation with an identified cut is settled by the existing cell owner as a no-op without starting a worker; it retains the caller's reason and does not create an unexplained recovery boundary.
22
+
23
+ ## Consequences
24
+
25
+ pre-step and assembly read current projected facts rather than materializing history. Recovery and authoring receipt operations are explicit asynchronous reader consumers. Honest checkpoint restore and fork must preserve the same timeline, edit and runtime-message decisions as batch replay. Tests cover serialized transition boundaries, duplicate identities, prune replacement, observation/surface races, real SessionStore/query/registry composition and long unrelated histories.
26
+
27
+ This migration does not change tool names, journal generations, Host policy authority, output governance or the selected PTC language contract. Public execution-provider composition is owned by [ADR 0028](0028-attach-to-the-host-ptc-execution-seam.md), not this projection. Successful-result metadata and two-tool collapse integration remain separate boundaries.
@@ -0,0 +1,23 @@
1
+ # Gate Client Visual Usability In A Browser
2
+
3
+ ## Problem
4
+
5
+ JSDOM can verify component classes and callbacks while the browser paints unusable controls. Optional smoke scripts and saved screenshots leave key style regressions outside normal verification and provide no automatic verdict for focus or disabled feedback.
6
+
7
+ ## Decision
8
+
9
+ The standard local and CI verification entries run one Client suite followed by deterministic browser layout and visual assertions against fresh actual-renderer fixtures. A shared bounded usability oracle owns contrast, action dimensions, reachability and state feedback. Fault counterexamples retain actual DOM classes and handlers and must be rejected. Browser prerequisites are explicit and absence fails verification. The coverage inventory and exceptions are owned by [the Client visual contract](../client-visual-contract.md).
10
+
11
+ Packed official-DSH acceptance remains a separate integration obligation under [ADR 0017](0017-track-the-latest-dsh-public-surface.md). It reuses the oracle on actual Host theme surfaces; fixture palettes do not establish Host compatibility. These checks do not change DSH authority, runtime state, program values or the model's tool surface.
12
+
13
+ ## Alternatives considered
14
+
15
+ **Keep browser checks opt-in.** This permits a standard green gate while CSS is absent or state feedback is lost, which does not satisfy the Client usability obligation.
16
+
17
+ **Freeze full-page screenshot baselines.** Such baselines couple plugin acceptance to upstream typography and rendering pixels. Bounded computed-style and hit assertions directly test the product obligation, while screenshots remain useful diagnostics.
18
+
19
+ **Run every browser script independently in the gate.** The layout script would rerun the complete Client suite. Sharing a single fresh fixture generation preserves current-source evidence without that duplication.
20
+
21
+ ## Consequences
22
+
23
+ Contributors need the locked Playwright Chromium installation before the full gate. Browser checks add work to verification and fail when their prerequisites are unavailable. Their guarantee is bounded by the declared controls and states; extending a UI responsibility requires extending its inventory and counterexamples rather than promising all future styles.
@@ -32,11 +32,11 @@ DSH 为一个 agent composition 固定选择 `native`、`ptc` 或 `both`。首
32
32
  `run_code`。无目标或参数不合法时不执行,返回 `{ edited: false, reason }` 并保留原目标。
33
33
  进程内 claim 区分 executing 与 settled:抛错、取消或缺少有效 PTC journal 的派生结果立即释放;已由 journal 证明进入 runtime 的派生执行继续占用旧 target,直到外层 result 的私有 metadata 通过最终 policy 并由 session log 投影为新 target。最终 result 丢失 metadata 时由 `tools/result` 释放。session log 投影在 edit call event 处记录 eligible target,只接受 target call sequence 匹配该快照且 journal 有效、非 noop 的派生源码,因此 live 与 cold recovery 从同一持久关系决定可编辑目标。
34
34
 
35
- `internal/session-log-view.js` 单次前向扫描 session events,分别投影最新执行、可编辑目标、rewrite metadata、规范 journal 中的 Cordis transcript 计数和恢复 tip
36
- 所需事实。`edit_run_code` 不产生专用 runtime context:真实 call/result 已完整表达操作身份和结果,额外 contribution
35
+ `internal/session-log-view.js` 通过公开 `sessionProjections` 注册 host-only 的 `ptcPlusSessionLog` 单元。同步单事件转移维护最新执行、可编辑目标、rewrite metadata、规范 journal 的 Cordis transcript 计数、已投递提示身份与 cooldown/escalation 事实,以及按公开 surface operation 排序的当前 runtime messages。pre-step 与 assembly 只读该单元,不重新读取或折叠历史;异步恢复通过 `sessionQuery.observeSession` 取得不可变观察切点,派生 edit 与其内层执行共享该切点。旧的 array-backed session 使用同一转移的批量折叠,不修改 Host 状态。详见 [ADR 0032](adr/0032-own-session-log-facts-in-a-host-only-projection.md)。
36
+ `edit_run_code` 不产生专用 runtime context:真实 call/result 已完整表达操作身份和结果,额外 contribution
37
37
  会重复已有事实;此类信息不进入独立 PTC 消息。只有缺少有效 journal、无法确认完成状态的 rewrite feedback 才保留独立生命周期;已结算失败的恢复指引由当前结果表达;成功的透明改写不产生 runtime context。
38
38
 
39
- 插件卸载时恢复仍由自己持有的执行缝 `run` 与 `presentationMeta` 属性;执行缝由 `internal/execution-seam-compat.js` 按宿主注册的服务选定,并同时收回该插件无法兑现的 provider 描述符(见 [ADR 0028](adr/0028-attach-to-the-host-ptc-execution-seam.md))。若外层插件仍持有旧 wrapper,已卸载 wrapper 会透明委托原 provider,不会恢复已释放的 session 状态。
39
+ 执行接入由 `internal/execution-provider-owner.js` 经公开 Loader/Cordis 组合:保留原 row 的模块与配置,将原服务置于 named isolation,另注册插件自有 global provider。`internal/execution-seam-compat.js` 选择该服务并拥有 request/spec 边界;主插件卸载只释放自有 provider 的私有 execution callback,恢复原生委托与能力 getter,不写原实例的 `run` 或描述符。移除完整 bundle 时,Loader 生命周期先同步撤销插件注册,再让原 provider 回到 global slot。`presentationMeta` 仍由 runtime bridge 单独还原;它不属于 provider composition(见 [ADR 0028](adr/0028-attach-to-the-host-ptc-execution-seam.md))。旧 provider generation 不能复活已释放的 session 状态。
40
40
  稳定 REPL 指引与执行共同从 `binding-update-policy.js` 取得语言代际。新代际说明 TypeScript、顶层 await/return、静态 import/export 与所选绑定更新策略;旧兼容态才按其独立开关说明支持的模块语法。显式结果使用 return,日志使用 console;原生表达式 completion 同样可以提供结果值。失败恢复先按状态分类:result 已证明解析或 preflight 未执行且提供符合任务意图的 validated repair 时,
41
41
  优先直接使用带目标保护的 `edit_run_code`,无需等待 recovery context;该验证只证明语法/preflight 接受。其他小型修正可用 edit 执行完整 cell;
42
42
  已执行或可能产生外部 effect 的目标,则必须依据操作 owner 的 retry/idempotence 契约和执行事实判断重跑。短 `run_code` 可以复用仍存活的 binding,但缩短源码不能证明幂等。能力和命令执行依赖当前 request
@@ -52,7 +52,7 @@ system sections、tool schema 或 tool order,也不假设 Windows、WSL、POSI
52
52
 
53
53
  ## 设置与启用开关
54
54
 
55
- Host half 通过 DSH 公共 settings 服务接入 `ptc-plus` 命名空间:提供 provider-owned `installSection()` 的代际直接注册,提供根模块 `installSettingsSection()` 的代际经兼容适配注册;两条路径共享同一 fallback、watch、rollback 与 disposal 语义。既不提供 section installer、又由宿主从插件导出的 `Config` 管理设置文档的代际(当前 alpha)被视为 host-owned surface:导出 schema 的全部字段带 volatile 标记,宿主据此提供表单并通过自身 config-editor 把 volatile-only 变更写入 retained handles;插件订阅宿主的 `loader/volatile-update` 事件,从同一 schema 重新解析 live 值并复用既有 reconcile、rollback 与 per-cell 配置代际语义。字段清单、默认值与校验来自 `internal/config-spec.js`。
55
+ Host half 通过 DSH 公共 settings 服务接入 `ptc-plus` 命名空间:提供 provider-owned `installSection()` 的代际直接注册,提供根模块 `installSettingsSection()` 的代际经兼容适配注册;两条路径共享同一 fallback、watch、rollback 与 disposal 语义。既不提供 section installer、又由宿主从插件导出的 `Config` 管理设置文档的代际被视为 host-owned surface:导出 schema 的全部字段带 volatile 标记,宿主据此提供表单并通过自身 config-editor 把 volatile-only 变更写入 retained handles;插件订阅宿主的 `loader/volatile-update` 事件,从同一 schema 重新解析 live 值并复用既有 reconcile、rollback 与 per-cell 配置代际语义。字段清单、默认值与校验来自 `internal/config-spec.js`。
56
56
  Client half 在侧栏 **插件 → 已安装 → dsh-ptc-plus** 的插件行配置页呈现全部设置,通过 `plugins.row.config`(keyed,键 `<包名>#<行 id>`)注册;旧宿主的插件设置使用 `settings.plugin.item`(keyed,按 namespace)。`src/client-host-compat.js` 等待对应页面声明槽位,并按 `summary`/`page` 分别渲染一句描述与完整表单,不向通用设置注册。星光菜单在应用内弹窗复用完整表单与写入 owner;包元数据的 `icon` 指向随包发布的 SVG,由宿主显示在插件列表与详情页([ADR 0019](adr/0019-plugin-settings-and-kill-switch.md))。`enabled` 是 kill switch:关闭时保留 settings 注册、设置卡片与撤销旧 PTC 声明所需的被动 presentation cleanup;`enhancedToolView` 是默认开启的正文展示开关,关闭时只交还 DSH 原生 `run_code`/`edit_run_code` generic row,
57
57
  总开关关闭时不注册 runtime、执行 hook、tool surface 或 system prompt section,也不读取 binding 存储;`ptc` 与兼容 `code` preset 会话在头部单独显示 `PTC Plus` 指示器。设置卡片显示“已启用/已停用”,稳定指引不包含 UI 品牌名。
58
58
  `Config` 的字段形态由 `internal/settings-compat.js` 按已安装代际的公共能力决定:仍提供 section installer 的代际保留普通描述字段,由自身文档路径提交校验后的具体默认值;只有自管设置文档的代际才加 volatile 标记,字段构建器不具备该能力的代际保持可加载。版本号不参与该判断。
@@ -63,6 +63,8 @@ Client half 在侧栏 **插件 → 已安装 → dsh-ptc-plus** 的插件行配
63
63
 
64
64
  `cordisToolsEnabled` 默认关闭且即时生效。Host 只在同时暴露 `run_code`、`skill` 工具与 `agentPresets`/`skills` service 的 agent scope 中挂载官方 `@deepseek-ai/dsh-tool-cordis`,并通过公共 `agentPresets` service 定位 shipped `cordis` preset,再用维护中的 Skill filesystem plugin 把其 companion Skill 目录发布到同一 scope。两个 child fiber、tool guidance 与 `cordis-plugin-development` Skill 是一个 mount;首轮 request 等待完整发布和 scoped Skill load 验证,关闭、agent/runtime 释放或任一激活失败时逆序卸载。缺少其中任一 surface 的 scope 不是错误:owner 保持 pending、不在该 scope 发布内容,并在工具 surface 变化或下一次 prompt assembly 时重试;由宿主自身调用触达的不可用 scope 只从该 scope 撤出并记一条 warning,不使 `agents.create()` 或 prompt assembly 失败([ADR 0029](adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md))。工具名、数量、schema 和 guidance 直接来自 official tool fiber,Skill 内容直接来自 shipped preset,Host 均不复制。官方插件同时向 process-global `cordisInspect` 注册 Host provider;owner 将 manifest 相同的 per-agent 注册合并为引用计数 lease,查询委托给当前仍存活的官方 registration,最后一份 lease 释放后才注销 provider。manifest 不一致时启用失败。该开关不切换 preset,也不改变 code-only direct-tool projection。
65
65
 
66
+ Skill 根在当前 generation 发布绝对 composition path 时取其 sibling;pathless generation 改由 active Host 的公共 `pluginPackages.packageOf` service 定位该安装的官方单数或复数 preset package resource。完全没有该 service 的旧 generation 仅可从 Host `ctx.baseUrl` 解析历史复数包;service 已存在但返回空或无效结果时不进入兼容路径,因此不会读取插件 profile 周围可能属于另一宿主的 ambient package。只有准确存在 `cordis-plugin-development/SKILL.md` 才进入 mount;已发布但无效的 path 不回退到另一 generation 的 package layout。
67
+
66
68
  ## Global User Bindings
67
69
 
68
70
  `internal/user-bindings.js` 是条目、文档、请求快照和有界声明的严格规范化 owner。它从命名 value export 的 TypeScript 源码派生 symbols、binding kind、body-free declaration、durability 与 fingerprint,并封闭校验所有衍生字段;调用方不能提交一份与源码不一致的声明或 snapshot。源码声明保留未被遮蔽的环境类型,并收集公开签名引用的本地 interface、type alias 与 class 闭包;各条目使用独立声明 namespace,公开 class shape 包含实例字段与 constructor parameter property。无法形成自足声明的 imported type 在持久化前拒绝,不能静默替换为 `unknown`。`namespace` scope 产生一个条目名对象,`top-level` scope 产生选定导出;保留名称和启用集合中的调用标识符冲突在持久化或请求激活前拒绝。