dsh-ptc-plus 0.3.1 → 0.4.1

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 (200) hide show
  1. package/README.en.md +66 -73
  2. package/README.md +66 -73
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30610 -722
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +554 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +6 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +6 -4
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +15 -3
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +9 -3
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +11 -5
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +8 -6
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +17 -3
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +82 -22
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +96 -20
  51. package/docs/durability-design.md +61 -24
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/program-data-plane.md +6 -0
  55. package/docs/publishing.md +5 -3
  56. package/docs/runtime-reference.md +79 -25
  57. package/docs/semantic-validation.md +29 -0
  58. package/docs/stateful-binding-updates-proposal.md +755 -0
  59. package/docs/user-bindings.en.md +64 -0
  60. package/docs/user-bindings.md +64 -0
  61. package/docs/value-wire.md +3 -3
  62. package/docs/verification.md +57 -0
  63. package/index.js +374 -92
  64. package/internal/ast-traversal.js +5 -2
  65. package/internal/binding-descriptors.js +1 -0
  66. package/internal/binding-pattern-traversal.js +25 -0
  67. package/internal/binding-pattern.js +26 -29
  68. package/internal/binding-source-analysis.js +391 -0
  69. package/internal/binding-update-policy.js +66 -0
  70. package/internal/bounded-worker-round.js +56 -0
  71. package/internal/callable-definition-environment.js +42 -0
  72. package/internal/callable-source-catalog.js +129 -0
  73. package/internal/callable-source-encoding.js +47 -0
  74. package/internal/callable-source-facts.js +459 -0
  75. package/internal/callable-source-format.js +2 -0
  76. package/internal/callable-source-lowering.js +123 -0
  77. package/internal/cell-analysis-contract.js +25 -0
  78. package/internal/cell-analysis.js +252 -242
  79. package/internal/cell-completion.js +15 -0
  80. package/internal/cell-error.js +7 -0
  81. package/internal/cell-parser.js +66 -0
  82. package/internal/cell-rewriter.js +3 -553
  83. package/internal/commonjs-export-evidence.js +63 -0
  84. package/internal/commonjs-source-evidence.js +72 -0
  85. package/internal/compiler-amaro.cjs +2 -0
  86. package/internal/compiler-compression.js +12 -0
  87. package/internal/compiler-data.js +58 -0
  88. package/internal/compiler-descriptors.js +54 -0
  89. package/internal/compiler-dynamic-cache.js +48 -0
  90. package/internal/compiler-entry.js +35 -0
  91. package/internal/compiler-generated-names.js +17 -0
  92. package/internal/compiler-intrinsics.js +84 -0
  93. package/internal/compiler-module-links.js +34 -0
  94. package/internal/compiler-operations.js +61 -0
  95. package/internal/compiler-platform-factory.js +84 -0
  96. package/internal/compiler-platform.js +136 -0
  97. package/internal/compiler-record-roles.js +53 -0
  98. package/internal/compiler-region-output.js +259 -0
  99. package/internal/compiler-resource-lowering.js +103 -0
  100. package/internal/compiler-scope-facts.js +115 -0
  101. package/internal/compiler-service.js +109 -0
  102. package/internal/compiler-source-cache.js +32 -0
  103. package/internal/compiler-source-pieces.js +93 -0
  104. package/internal/compiler-source-regions.js +132 -0
  105. package/internal/compiler-storage-source.js +54 -0
  106. package/internal/compiler-text.js +15 -0
  107. package/internal/compiler-typescript.cjs +2 -0
  108. package/internal/config-spec.js +91 -25
  109. package/internal/cordis-tools-owner.js +130 -21
  110. package/internal/diagnostic.js +27 -1
  111. package/internal/direct-surface-owner.js +76 -23
  112. package/internal/dynamic-binding-evidence.js +16 -0
  113. package/internal/dynamic-environment-compiler.js +779 -0
  114. package/internal/dynamic-environment-integration.js +87 -0
  115. package/internal/dynamic-environment-runtime.js +362 -0
  116. package/internal/dynamic-native-calls.js +150 -0
  117. package/internal/dynamic-native-runtime.js +248 -0
  118. package/internal/dynamic-scope-analysis.js +90 -0
  119. package/internal/edit-transport-owner.js +28 -3
  120. package/internal/execution-seam-compat.js +193 -0
  121. package/internal/failure-reporting.js +118 -18
  122. package/internal/host-rpc.js +66 -0
  123. package/internal/isolated-worker.js +548 -0
  124. package/internal/kernel-child.js +139 -0
  125. package/internal/kernel-worker.js +911 -116
  126. package/internal/language-semantics.js +14 -0
  127. package/internal/legacy-binding-catalog.js +48 -0
  128. package/internal/legacy-cell-analysis.js +600 -0
  129. package/internal/legacy-cell-parser.js +50 -0
  130. package/internal/legacy-cell-rewriter.js +631 -0
  131. package/internal/legacy-repl-convenience.js +291 -0
  132. package/internal/managed-module-operations.js +170 -0
  133. package/internal/module-compilation.js +321 -0
  134. package/internal/module-runtime-platform.js +19 -0
  135. package/internal/module-transform-contract.js +12 -0
  136. package/internal/native-await-declarations.js +68 -0
  137. package/internal/native-root-compilation.js +54 -0
  138. package/internal/native-root-dynamic.js +67 -0
  139. package/internal/recovery-tips.js +27 -15
  140. package/internal/rejected-cell-editor.js +13 -8
  141. package/internal/repl-convenience.js +2 -201
  142. package/internal/repl-memory-projection.js +81 -12
  143. package/internal/repl-observation-interest.js +70 -0
  144. package/internal/repl-rewrite-contract.js +21 -0
  145. package/internal/repl-scope-normalizer.js +2091 -0
  146. package/internal/repl-value-observer.js +114 -0
  147. package/internal/rpc-contract.js +52 -0
  148. package/internal/runtime-bridge-owner.js +172 -28
  149. package/internal/runtime-config.js +48 -51
  150. package/internal/runtime-contexts.js +82 -10
  151. package/internal/runtime-messages.js +111 -0
  152. package/internal/session-cell-executor.js +455 -91
  153. package/internal/session-journal-recovery.js +684 -0
  154. package/internal/session-journal-schema.js +106 -0
  155. package/internal/session-journal.js +237 -440
  156. package/internal/session-log-view.js +42 -9
  157. package/internal/session-runtime.js +325 -80
  158. package/internal/session-state.js +249 -40
  159. package/internal/source-position-map.js +211 -71
  160. package/internal/stateful-module-compiler.js +154 -0
  161. package/internal/stateful-module-runtime.js +303 -0
  162. package/internal/stateful-root-compiler.js +598 -0
  163. package/internal/stateful-root-runtime.js +340 -0
  164. package/internal/typert-codec-compat.js +28 -0
  165. package/internal/typescript-transform.js +29 -0
  166. package/internal/user-binding-authoring.js +70 -0
  167. package/internal/user-binding-console-worker.js +184 -0
  168. package/internal/user-binding-console.js +148 -0
  169. package/internal/user-binding-draft-projection.js +335 -0
  170. package/internal/user-binding-model-context.js +31 -0
  171. package/internal/user-binding-runner.js +56 -0
  172. package/internal/user-bindings-owner.js +1065 -0
  173. package/internal/user-bindings-store.js +293 -0
  174. package/internal/user-bindings.js +353 -0
  175. package/internal/value-wire-schema.js +28 -0
  176. package/internal/value-wire.js +29 -20
  177. package/internal/worker-client.js +57 -67
  178. package/internal/worker-environment.js +45 -0
  179. package/internal/worker-output-relay.js +29 -0
  180. package/internal/worker-shutdown.js +14 -0
  181. package/package.json +81 -11
  182. package/src/client-activity.js +109 -45
  183. package/src/client-authoring-view.js +580 -0
  184. package/src/client-binding-review.js +230 -0
  185. package/src/client-bindings-data.js +29 -0
  186. package/src/client-catalog.js +127 -0
  187. package/src/client-code-editor.js +84 -0
  188. package/src/client-console.js +112 -0
  189. package/src/client-copy.js +370 -0
  190. package/src/client-feature-gates.js +62 -0
  191. package/src/client-host-compat.js +150 -0
  192. package/src/client-indicator-view.js +267 -0
  193. package/src/client-repl-view.js +292 -0
  194. package/src/client-rpc.js +20 -0
  195. package/src/client-settings-view.js +221 -0
  196. package/src/client-styles.js +106 -0
  197. package/src/client-tool-view.js +108 -0
  198. package/src/client-transport.js +159 -0
  199. package/src/client-workbench.js +521 -0
  200. package/src/client.js +233 -615
package/docs/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  ## Getting Started
4
4
 
5
5
  - [Installation](installation.md): npm, Git, source, tarball, development snapshot, and Desktop installation.
6
+ - [Global binding guide](user-bindings.en.md) ([中文](user-bindings.md)): author, review, save, configure, and test reusable helpers.
6
7
  - [Runtime Reference](runtime-reference.md): cell behavior, capability discovery, configuration, diagnostics, and limits.
7
8
  - [Evaluation](evaluation.md): paired ordinary-task protocol, metrics, configuration, and limitations.
8
9
 
@@ -13,9 +14,14 @@
13
14
  - [Program Data Plane](program-data-plane.md): canonical values and result completeness.
14
15
  - [Durable / Volatile Recovery](durability-design.md): replay model and external-input boundaries.
15
16
  - [PTC Value Graph V1](value-wire.md): supported JavaScript value encoding.
17
+ - [Global User Bindings](adr/0023-global-user-bindings.md): persistent helper ownership, model projection, runtime activation, recovery, and Agent-assisted authoring.
18
+ - [Binding Review Placement](binding-review-placement-design.md): the implemented full draft panel above the current composer, using the published input dock and one review controller.
19
+ - [Logical Binding Identities](adr/0025-use-versioned-logical-binding-identities.md): stateful declarations, scope, candidate publication and language generations.
16
20
  - [Architecture Decisions](adr/): stable design constraints and their consequences.
17
21
 
18
22
  ## Maintenance
19
23
 
24
+ - [Deterministic Verification](verification.md): complete checks, backend test concurrency, coverage, and focused diagnostics.
25
+ - [Semantic Validation](semantic-validation.md): pinned Test262 cases, dialect contracts, native differential matrices and their limits.
20
26
  - [Publishing](publishing.md): release checks, package contents, permissions, and platform validation.
21
27
  - [Client UI](client-ui.md): current UI boundary and reevaluation criteria.
@@ -1,5 +1,5 @@
1
1
  # Declare Program Bindings At The Owner
2
2
 
3
- PTC Plus does not create a private cross-plugin registry or reflective invocation bus. The current public CodeRuntime request surface has no registry for discovering non-tool program bindings.
3
+ PTC Plus does not create a private cross-plugin registry or reflective invocation bus. The public execution-seam request surface ([ADR 0028](0028-attach-to-the-host-ptc-execution-seam.md)) has no registry for discovering non-tool program bindings.
4
4
 
5
5
  If DSH later provides one, capability owners should publish explicit typed contracts, semantic metadata, source references, and binding factories. DSH should own discovery, scope, authority, leasing, dispatch, and settlement. Explicit registration, generated manifests, decorators, or scanning are assembly choices; none replaces those contracts. PTC Plus would consume only bindings already present in the live request.
@@ -1,16 +1,18 @@
1
1
  # Rewrite Module Syntax With An AST
2
2
 
3
+ The AST and native module-resolution decision remains in force. The alias storage, readonly writes and collision rules below describe the frozen `legacy-v1` compiler; [ADR 0025](0025-use-versioned-logical-binding-identities.md) supersedes those rules for new cells and unifies plugin-owned module compilation. `internal/legacy-cell-rewriter.js`, `internal/legacy-cell-parser.js` and `internal/legacy-cell-analysis.js` preserve that historical contract.
4
+
3
5
  ## Problem
4
6
 
5
7
  PTC Plus evaluates each cell as an async function body, where static `import` and `export` declarations are syntactically invalid. The adapter must accept TypeScript type syntax, preserve cell-relative source positions and line counts, classify the rewritten program for replay durability, record every automatic rewrite, and reject malformed or unrecognized module syntax without partially deleting or transforming it. Token-by-token text scanning duplicated parser responsibilities and could accept a recognized prefix while leaving an invalid suffix or erase malformed type-only declarations.
6
8
 
7
9
  ## Decision
8
10
 
9
- [`internal/cell-rewriter.js`](../../internal/cell-rewriter.js) owns module-syntax adaptation. `@babel/parser` parses the original cell with its TypeScript plugin under script semantics while explicitly allowing top-level module declarations, `return`, and `await`; recognizing a module declaration therefore does not impose module strict mode on the surrounding async-function body. Before any edit or module preload record is produced, `@babel/traverse` builds the original Program scope. Its declaration and hoisting rules reject same-scope collisions between value imports and lexical, `var`, function, or other import bindings while retaining block shadowing and the separate TypeScript type namespace. The same scope validates local exports and drives imported-reference rewriting, supplemented by top-level TypeScript declaration names because Babel intentionally excludes the type namespace from runtime scope. The rewriter derives every accepted import, export, type-only declaration, specifier, source value, and edit range from that AST. One batch edit assembler validates non-overlapping ranges, produces generated source, and composes source mappings without rebuilding either artifact per edit. [`internal/cell-analysis.js`](../../internal/cell-analysis.js) then wraps the rewritten cell as an async function body and first parses it with Acorn. Already-valid JavaScript proceeds unchanged; only a cell that Acorn cannot parse is passed through Node's `stripTypeScriptTypes` and parsed again for binding and durability analysis.
11
+ [`internal/legacy-cell-rewriter.js`](../../internal/legacy-cell-rewriter.js) owns historical module-syntax adaptation. `@babel/parser` parses the original cell with its TypeScript plugin under script semantics while explicitly allowing top-level module declarations, `return`, and `await`; recognizing a module declaration therefore does not impose module strict mode on the surrounding async-function body. Before any edit or module preload record is produced, `@babel/traverse` builds the original Program scope. Its declaration and hoisting rules reject same-scope collisions between value imports and lexical, `var`, function, or other import bindings while retaining block shadowing and the separate TypeScript type namespace. The same scope validates local exports and drives imported-reference rewriting, supplemented by top-level TypeScript declaration names because Babel intentionally excludes the type namespace from runtime scope. The rewriter derives every accepted import, export, type-only declaration, specifier, source value, and edit range from that AST. One batch edit assembler validates non-overlapping ranges, produces generated source, and composes source mappings without rebuilding either artifact per edit. [`internal/legacy-cell-parser.js`](../../internal/legacy-cell-parser.js) owns executable parsing of the prepared cell: it wraps the rewritten cell as an async function body, parses it with Acorn, and relocates every returned AST range to original-cell coordinates. Already-valid JavaScript proceeds unchanged; only a cell that Acorn cannot parse is passed through Node's `stripTypeScriptTypes` and parsed again. [`internal/legacy-cell-analysis.js`](../../internal/legacy-cell-analysis.js) consumes that single parse for binding and durability analysis.
10
12
 
11
- Each static import or remote re-export creates an ordered module preload record. A value-bearing record carries its source, import attributes, original position, generated temporary-global identifier, and the default or named exports required by its AST specifiers. The dedicated worker uses Node's synchronous module resolve hook to give REPL imports and static-link adapters one parent at the session cwd, falling back to the worker process cwd when the session has no recorded cwd. Node's ESM resolver therefore owns relative URLs, bare packages, conditional `exports`, URL schemes, import conditions, and platform path conversion; plugin and target-module dependency imports retain their natural parents. Each ephemeral data-URL adapter expresses the required members as static re-exports, so Node completes export linkage before evaluating the target module, then returns the namespace for a value-bearing preload. The worker resolves records before compiling the cell and exposes each namespace under its temporary identifier. One generated lexical prologue after the original directive prologue and before every executable cell statement captures each temporary identifier into a distinct persistent namespace identifier in source order; import declarations are erased at their original ranges, and the temporary globals are removed when the cell settles. Both identities are allocated outside current source identifiers, persistent REPL bindings, reserved program bindings, and every live private namespace. The prologue references the generated host identifier directly, so a lexical `globalThis` binding has ordinary JavaScript semantics and cannot redirect capture. A binding catalog stores only the persistent namespace identity and maps public import aliases to it and the export name; scope-aware rewriting routes unshadowed reads through the namespace, keeps bare, optional, and tagged calls detached from the namespace receiver with the language's comma-reference form, and lowers writes to a deterministic `TypeError`. Private namespace names remain reserved after a public alias is redeclared, so closures from earlier cells cannot be redirected by a later import. The catalog is rebuilt during journal replay. In loose REPL mode an explicit later declaration replaces the alias for future cells, while closures compiled before that declaration retain their namespace read. Destructuring, loop, nested, and delete writes that cannot preserve native evaluation semantics are rejected before execution. Direct `eval` and `WithStatement` are rejected on the original Program while value import aliases are active because generated namespace reads cannot reproduce their dynamic lexical resolution; this validation precedes module preload. Indirect or locally shadowed eval, non-strict `with` without value aliases, and cells containing only type imports retain ordinary JavaScript semantics. Side-effect, default, namespace, named, default-plus-named, and default-plus-namespace forms remain supported. Export modifiers are removed while declarations remain; default exports bind the fixed public name `__default`; anonymous default function and class lowering emits an explicit statement terminator, while default expressions retain their parsed continuation; remote re-exports become preload-only side-effect modules; local export lists are removed; and declaration-level or specifier-level type-only syntax is erased.
13
+ Each static import or remote re-export creates an ordered module preload record. A value-bearing record carries its source, import attributes, original position, generated temporary-global identifier, and the default or named exports required by its AST specifiers. The dedicated worker uses Node's synchronous module resolve hook to give REPL imports and static-link adapters one parent at the session cwd, falling back to the worker process cwd when the session has no recorded cwd. Node's ESM resolver therefore owns relative URLs, bare packages, conditional `exports`, URL schemes, import conditions, and platform path conversion; plugin and target-module dependency imports retain their natural parents. Each ephemeral data-URL adapter expresses the required members as static re-exports, so Node completes export linkage before evaluating the target module, then returns the namespace for a value-bearing preload. The worker resolves records before compiling the cell and exposes each namespace under its temporary identifier. One generated lexical prologue after the original directive prologue and before every executable cell statement captures each temporary identifier into a distinct persistent namespace identifier in source order; import declarations are erased at their original ranges, and the temporary globals are removed when the cell settles. Both identities are allocated outside current source identifiers, persistent REPL bindings, reserved program bindings, and every live private namespace. The prologue references the generated host identifier directly, so a lexical `globalThis` binding has ordinary JavaScript semantics and cannot redirect capture. A binding catalog stores only the persistent namespace identity and maps public import aliases to it and the export name; scope-aware rewriting routes unshadowed reads through the namespace, keeps bare, optional, and tagged calls detached from the namespace receiver with the language's comma-reference form, and lowers writes to a deterministic `TypeError`. Private namespace names remain reserved after a public alias is redeclared, so closures from earlier cells cannot be redirected by a later import. The catalog is rebuilt during journal replay. In loose REPL mode an explicit later declaration replaces the alias for future cells, while closures compiled before that declaration retain their namespace read. Destructuring, loop, nested, and delete writes that cannot preserve native evaluation semantics are rejected before execution. Direct `eval` and `WithStatement` are rejected on the original Program while value import aliases are active because generated namespace reads cannot reproduce their dynamic lexical resolution; this validation precedes module preload. Indirect or locally shadowed eval, non-strict `with` without active aliases, and cells containing only type imports retain ordinary JavaScript semantics. Side-effect, default, namespace, named, default-plus-named, and default-plus-namespace forms remain supported. Export modifiers are removed while declarations remain; default exports map the fixed public name `__default` through the same alias lowering to a generated persistent private slot. Later default exports update that slot at their source position independently of variable-redeclaration policy, and the binding catalog adopts the alias definition only after the worker reports the generated post-update commit signal. This keeps `__default` live and read-only while preventing an early return or failed class evaluation from publishing an update that did not execute. Anonymous default function and class lowering emits an explicit statement terminator, while default expressions retain their parsed continuation; remote re-exports become preload-only side-effect modules; local export lists are removed; and declaration-level or specifier-level type-only syntax is erased.
12
14
 
13
- The rewriter normalizes Babel syntax and local-export validation failures as original-cell positions before they cross the module boundary. Executable wrapper parsing retains Acorn's wrapper-relative positions, and only those positions receive the one-line wrapper subtraction during `PTC-C001` rendering. [`internal/cell-analysis.js`](../../internal/cell-analysis.js) then applies return, redeclaration, collision, and durability analysis to the successfully rewritten program. Return control-flow lowering addresses its per-cell worker-global signal through the top-level `this` receiver, which bypasses both lexical `globalThis` shadowing and `with` object-environment resolution; worker startup validates that this receiver is the evaluator's global context, and settlement removes the signal property. Lowered returns emit an explicit statement terminator so a return in a `switch` clause remains valid after replacement. Rewrite provenance remains parallel to the closed journal schema under `meta.dshPtcPlusRewrites` and does not alter replay equality. A successful rewrite remains private audit metadata; only a failed rewrite or missing valid journal may project its description as a bounded recovery context.
15
+ The rewriter normalizes Babel syntax and local-export validation failures as original-cell positions before they cross the module boundary. Executable parsing normalizes AST ranges and parse failures to original-cell coordinates inside that parse owner, so `PTC-C001` renders `ModuleRewriteError.cellPosition` without applying any wrapper offset; a failure raised while parsing the module-rewrite output is mapped back through that rewrite's source map before preparation returns. [`internal/legacy-cell-analysis.js`](../../internal/legacy-cell-analysis.js) then applies return, redeclaration, collision, and durability analysis to the successfully rewritten program. Return control-flow lowering addresses its per-cell worker-global signal through the top-level `this` receiver, which bypasses both lexical `globalThis` shadowing and `with` object-environment resolution; worker startup validates that this receiver is the evaluator's global context, and settlement removes the signal property. Lowered returns emit an explicit statement terminator so a return in a `switch` clause remains valid after replacement. Rewrite provenance remains parallel to the closed journal schema under `meta.dshPtcPlusRewrites` and does not alter replay equality. A successful rewrite remains private audit metadata; only a failed rewrite or missing valid journal may project its description as a bounded recovery context.
14
16
 
15
17
  ## Alternatives considered
16
18
 
@@ -42,4 +44,4 @@ The rewriter normalizes Babel syntax and local-export validation failures as ori
42
44
 
43
45
  ## Consequences
44
46
 
45
- Each accepted transformation corresponds to a complete TypeScript AST node, and every automatic type erasure produces provenance without recovering module names from source text. Static modules resolve from the session project in source order before cell compilation; their aliases are initialized before body execution regardless of textual declaration position or an earlier return. A resolution, linkage, or evaluation failure leaves REPL declarations and aliases uncommitted, although a successfully completed earlier preload may already have produced effects. A preload with a missing requested export does not evaluate its target module. Imported reads add one namespace property access; bare, optional, and tagged calls use an indirect reference so the namespace cannot become `this` and nullish optional calls still short-circuit. Malformed module or type syntax and unsupported imported writes fail before execution. The production dependency set includes `@babel/parser` and `@babel/traverse`; Acorn remains the executable-JavaScript and scope-analysis authority downstream. Module resolution uses Node's `registerHooks` primitive available at the engine floor. Node's `stripTypeScriptTypes` is invoked only when the rewritten cell is not already valid JavaScript and remains experimental at the current engine floor, so the compatibility suite must be rerun when the supported Node version changes.
47
+ Each accepted transformation corresponds to a complete TypeScript AST node, and every automatic type erasure produces provenance without recovering module names from source text. Static modules resolve from the session project in source order before cell compilation; their aliases are initialized before body execution regardless of textual declaration position or an earlier return. A resolution, linkage, or evaluation failure leaves REPL declarations and aliases uncommitted, although a successfully completed earlier preload may already have produced effects. A preload with a missing requested export does not evaluate its target module. Imported reads add one namespace property access; bare, optional, and tagged calls use an indirect reference so the namespace cannot become `this` and nullish optional calls still short-circuit. Malformed module or type syntax and unsupported imported writes fail before execution. The production dependency set includes `@babel/parser`, `@babel/traverse`, and `acorn`; Acorn remains the executable-JavaScript and scope-analysis authority downstream. TypeScript lowering of global binding modules is a separate mechanism with its own owner, [`internal/typescript-transform.js`](../../internal/typescript-transform.js), which pins its transform generation and does not parse or rewrite cells ([ADR 0023](0023-global-user-bindings.md)). Module resolution uses Node's `registerHooks` primitive available at the engine floor. Node's `stripTypeScriptTypes` is invoked only when the rewritten cell is not already valid JavaScript and remains experimental at the current engine floor, so the compatibility suite must be rerun when the supported Node version changes.
@@ -8,7 +8,11 @@ The session runtime coordinates two different lifecycles: transport ownership fo
8
8
 
9
9
  [`internal/worker-client.js`](../../internal/worker-client.js) exclusively owns worker creation, the readiness handshake, the private port, bounded stderr capture, reset, concurrent termination tracking, scratch allocation, and scratch cleanup. It reports private-channel messages and terminal failures through callbacks. [`internal/session-runtime.js`](../../internal/session-runtime.js) owns the active cell and decides how a reported message or failure settles the journal, durability state, replay transaction, or binding call. Messages reach the kernel only from the client's current worker, while each active semantic transaction retains its worker identity for lease and replay checks.
10
10
 
11
- Cross-process policy that must agree on both sides has one source. [`internal/module-policy.js`](../../internal/module-policy.js) defines durable imports, forbidden kernel-control imports, and ambient globals for both static analysis and the worker runtime. [`internal/failure-reporting.js`](../../internal/failure-reporting.js) defines hostile-error normalization, active-cell stack extraction, bounded diagnostic logs, and repeat-failure tracking for the host and worker. Session-log recovery belongs to [`internal/session-journal.js`](../../internal/session-journal.js), which owns journal shape, event association, and branch folding. Live durable nodes, current-call exclusion, no-op confirmations, recovery boundaries, and cold nodes all use persisted `tool/call.seq` identity. During live dispatch, the journal owner uses `callId` only to resolve the unique unpaired top-level call, then passes its sequence into semantic state. Sessionless direct runtime calls do not fabricate a persisted identity. Journal v3 stores confirmed no-ops as sequences; v2 journals with empty confirmations migrate without ambiguity, while a v2 call-id confirmation forms an unknown suffix. A failed durable replay records one log-only recovery boundary in the current settled `tool/result` metadata under `meta.dshPtcPlusRecoveryBoundaries`; its payload identifies the failed call event and its parent frontier without inventing a DSH event type. Every boundary is normalized as it enters recovery, before its event sequence participates in ordering; malformed boundary data therefore rejects reconstruction instead of disappearing from the fold. A completed record enters branch folding at its `tool/result` event position because that event confirms durability. Folding leaves immutable call/result events intact, removes the failed node and dependent descendants, and recomputes checkpoints from the remaining records. [`internal/session-runtime.js`](../../internal/session-runtime.js) resets the worker and retries the contracted frontier, recursively reaching the empty REPL only if every earlier candidate also fails. The exported migration helper converts old custom boundary events into this metadata before DSH restores a session and never mutates its input.
11
+ Cross-process policy that must agree on both sides has one source. [`internal/module-policy.js`](../../internal/module-policy.js) defines durable imports, forbidden kernel-control imports, and ambient globals for both static analysis and the worker runtime. [`internal/failure-reporting.js`](../../internal/failure-reporting.js) defines hostile-error normalization, active-cell stack extraction, bounded diagnostic logs, and repeat-failure tracking for the host and worker. Session-log recovery belongs to [`internal/session-journal-recovery.js`](../../internal/session-journal-recovery.js), which owns event association and branch folding; the closed field sets and generation constants belong to [`internal/session-journal-schema.js`](../../internal/session-journal-schema.js), and journal validation, migration, and creation belong to [`internal/session-journal.js`](../../internal/session-journal.js). Live durable nodes, current-call exclusion, no-op confirmations, recovery boundaries, and cold nodes all use persisted `tool/call.seq` identity. During live dispatch, the journal owner uses `callId` only to resolve the unique unpaired top-level call, then passes its sequence into semantic state. Sessionless direct runtime calls do not fabricate a persisted identity. Journal v3 stores confirmed no-ops as sequences; v2 journals with empty confirmations migrate without ambiguity, while a v2 call-id confirmation forms an unknown boundary. A failed durable replay records one log-only recovery boundary in the current settled `tool/result` metadata under `meta.dshPtcPlusRecoveryBoundaries`; its payload identifies the failed call event and its parent frontier without inventing a DSH event type. Every boundary is normalized as it enters recovery before its event sequence participates in ordering. Malformed boundary or association data is rejected as evidence for old state, but it does not turn historical plugin metadata into an availability gate for the current valid call. A completed record enters branch folding at its `tool/result` event position because that event confirms durability. Folding leaves immutable call/result events intact, removes unproved nodes and dependent descendants, and recomputes checkpoints from the remaining records. [`internal/session-runtime.js`](../../internal/session-runtime.js) resets the worker and retries the greatest verified frontier, recursively reaching the empty REPL if every non-empty candidate fails, then executes the current cell against that actual state. The contraction is recorded on the current settled result and reported once so later recovery does not repeatedly encounter the same boundary. The exported migration helper converts old custom boundary events into this metadata before DSH restores a session and never mutates its input.
12
+
13
+ Recovery is conservative about state and best-effort about availability. A post-boundary cell or binding may be retained only when owned evidence mechanically proves that its ancestry or independence does not cross the unknown boundary. The current journal does not contain a complete per-binding dependency graph, so recovery treats a cell as atomic and discards its affected suffix when it cannot prove a finer partition. This can lose bindings, including all bindings in the empty-frontier case, but never claims that an unverified heap or historical effect was restored. DSH policy and failures of the current request remain outside this fallback.
14
+
15
+ The selected frontier must also agree with the state the model can know when it produces the current call. DSH's append-only session log owns durable evidence, while its ordered surface and derived request history own model visibility; raw events shadowed from that surface do not become model knowledge merely because replay can still read them. UI-only `dshPtcPlusBindings` metadata also does not qualify. A cell remains eligible when a result-only replacement leaves the assistant tool call carrying its exact source on the model-visible surface. When compaction shadows that provenance, the live or cold runtime contracts the affected cell and descendants unless an explicitly selected bounded model-visible structure publishes the exact surviving state. Such a projection is not injected by default merely to retain hidden bindings. Recovery never parses a natural-language summary into binding proof. Surface replacement generation is checked before a later cell uses an already-live worker, so this rule is not cold-start-only.
12
16
 
13
17
  ## Alternatives considered
14
18
 
@@ -32,8 +36,16 @@ Cross-process policy that must agree on both sides has one source. [`internal/mo
32
36
 
33
37
  **Always recover from an empty REPL.** This guarantees a clean worker but discards verified bindings and checkpoints unnecessarily. Parent-by-parent contraction retains the largest frontier whose replay actually succeeds.
34
38
 
35
- **Compare raw boundary sequences before decoding boundary events.** This appears to avoid work for boundaries after the current record, but an absent or nonnumeric sequence is not orderable and can evade the decoder entirely. Normalizing at session-log ingestion gives the fold one trusted boundary shape and makes damaged history fail closed.
39
+ **Reject every future cell until malformed history is repaired.** This preserves a simple reconstruction invariant but lets plugin-owned optimization metadata permanently disable `run_code` in an otherwise usable DSH conversation. Rejecting an unproved binding is required; refusing the current valid call is not. The runtime instead contracts to verified state or an empty REPL and lets the current cell establish a new branch.
40
+
41
+ **Recover arbitrary bindings after an unknown boundary.** This retains more names in favorable cases, but source text and completion equality do not prove the values, mutations, closures, or transitive reads that produced those bindings. Fine-grained retention requires explicit owned dependency evidence; absent that evidence, the whole affected cell or suffix is discarded.
42
+
43
+ **Treat every raw-log durable node as model-knowable.** This maximizes continuity after compaction, but can expose names and values whose declaration is absent from the request history that produced the current call. Durability proves reconstruction, not awareness. The runtime uses the intersection of durable and model-visible provenance instead.
44
+
45
+ **Parse the compaction summary for binding names.** A natural-language summary can omit, rename, or ambiguously describe bindings and does not carry an owner-proven relation to journal nodes. Only an explicit structured model-visible projection can preserve state after exact source provenance leaves the surface.
46
+
47
+ **Compare raw boundary sequences before decoding boundary events.** This appears to avoid work for boundaries after the current record, but an absent or nonnumeric sequence is not orderable and can evade the decoder entirely. Normalizing at session-log ingestion lets the fold reject the damaged record as state evidence and place a conservative contraction boundary without silently accepting it.
36
48
 
37
49
  ## Consequences
38
50
 
39
- Worker resource cleanup and startup failures are independently testable, while the kernel retains one owner for journal and replay meaning. The client callback is deliberately narrow: it carries transport facts, not journal decisions. Recovery metadata stays private to the settled `tool/result`; it does not change tool schemas, model messages, truthful top-level tool identity, `edit_run_code`, or recorded-value replay. Adding a private protocol message still requires a kernel handler and contract tests because the client does not interpret semantic payloads. Shared policy modules become load-bearing single sources and must remain usable in both the main thread and worker without importing session state.
51
+ Worker resource cleanup and startup failures are independently testable, while the kernel retains one owner for journal and replay meaning. The client callback is deliberately narrow: it carries transport facts, not journal decisions. Recovery metadata stays private to the settled `tool/result`; it does not change tool schemas, truthful top-level tool identity, `edit_run_code`, or recorded-value replay. The runtime consumes DSH's public surface contract without copying its projection algorithm or adding a DSH version whitelist. A contraction caused by damaged or no-longer-model-visible history can remove previously available bindings, so the first continued cell receives one bounded diagnostic and may need to redeclare them; historical program-binding effects are neither replayed nor described as undone. Adding a private protocol message still requires a kernel handler and contract tests because the client does not interpret semantic payloads. Shared policy modules become load-bearing single sources and must remain usable in both the main thread and worker without importing session state.
@@ -16,6 +16,8 @@ The edit canary covers both a completed cell whose result needs adjustment and a
16
16
 
17
17
  Both model-backed runners complete keyless verification and resolved-config validation before model invocation. They then run one complete representative canary sequentially and audit its process result, session log, tool transport, runtime contexts, budgets, and task oracle before scheduling broader scenarios, replicates, or concurrency. A canary failure stops the run without starting the remaining paid work. Deterministic tests remain the authority for AST rewrite variants and the acceptance contract itself. The ordinary-task A/B canary is the stable fixture's fixed, cheap, machine-checkable transport task rather than a full repository test run; see ADR 0018.
18
18
 
19
+ Resolved tools settings are independently validated by DSH's public configuration schema, in addition to the runner's policy comparison. Workload-specific inspection symbols and operation limits belong to the scenario's `programWork` expectations. These limits use canonical argument evidence and include failed calls; identical arguments never authorize runtime deduplication or prove observation freshness. The fixed typed fixture permits one native read and reuse of that observation. Guarded edits reuse the canonical editor and dispatch-time target projection; explicitly expected guard mismatches require a non-executing result without derived metadata. Deterministic coverage of these contracts does not enlarge the default paid cohort.
20
+
19
21
  Machine acceptance and stochastic comparison are separate from blind semantic review. A/B output reports machine pass or failure independently and keeps overall approval pending until the blind packets have been evaluated; producing packets is not evidence that their review is complete.
20
22
 
21
23
  ## Alternatives considered
@@ -2,21 +2,75 @@
2
2
 
3
3
  ## Problem
4
4
 
5
- The persistent REPL contract must stay short enough for every request, while some failures need a model-visible recovery affordance. Repeated binding failures and platform-specific command errors benefit from a precise next action. A real `edit_run_code` call already carries its identity, arguments, and result; restating those facts in a runtime context wastes tokens and causes DSH to append a new aggregate snapshot containing unrelated contributions. Long failed cells are a separate trigger: after the failure is persisted, a bounded context may distinguish a journal-proven no-execution edit candidate from a possibly effectful failure.
5
+ The persistent REPL contract must stay short enough for every request, while some failures need a model-visible recovery affordance. Repeated binding failures and platform-specific command errors benefit from a precise next action. A real `edit_run_code` call already carries its identity, arguments, and result; restating those facts wastes tokens. The former aggregate runtime-context path also repeated unrelated owner contributions whenever any PTC contribution changed. Long-cell failure guidance belongs in the current diagnostic, where pre-execution rejection and possibly effectful failure can be distinguished.
6
6
 
7
7
  ## Decision
8
8
 
9
- PTC Plus keeps the stable REPL guidance limited to invariants, discovery entry points, and environment-neutral boundaries. `internal/session-log-view.js` scans the event sequence once, pairs settled calls within each open turn, validates execution journals and rewrite records once, and returns immutable facts for edit targeting, successful-run reset, context distance, normalized Cordis call/inspection counts, and canonical DSH system-prompt snapshots. Each snapshot preserves its named sections. `internal/runtime-contexts.js` renders rewrite feedback only when the rewritten cell failed or lacks a valid journal, the fixed `tools:ptc-plus-cordis-recovery` context when a new agent or Cordis enable generation contains historical Cordis transcript without a newer successful live Inspect, plus at most one context from the reserved `tools:ptc-plus-tip/<trigger>/<ordinal>` name family. Successful transparent rewrites remain result metadata and do not create aggregate snapshot churn. It never emits edit provenance or target-lifecycle context: those facts belong to the registered tool call/result and its private derived-execution metadata. These contexts never change the tool list, tool schemas, or system sections.
9
+ PTC-owned dynamic information uses independently sourced, accepted DSH messages.
10
+ Unproved rewrite completion and Cordis recovery form a bounded `ptc-plus`
11
+ `snapshot` with named sections. Configured Global User Binding documentation uses
12
+ DSH's existing `catalog` form, independently of transient recovery state. A recovery tip is a `ptc-plus` `notice` whose
13
+ structured summary is its trigger/ordinal name. A snapshot supersedes only prior
14
+ PTC state snapshots, including PTC sections in historical DSH aggregate snapshots;
15
+ it never supersedes a binding catalog, authoring task, Skill instructions, a tool result, or
16
+ another producer. An empty snapshot explicitly invalidates earlier PTC state.
10
17
 
11
- The default triggers are a repeated binding failure and a failure whose diagnostic or structured cause identifies an executable, shell, or path problem. The first tip is concise. A matching trigger may produce another tip only after `tipCooldownMessages` model-context steps; unresolved matching tips reach the detailed form after `tipEscalationFailures` occurrences. A successful cell resets the unresolved escalation count. Every emitted tip name carries its stable trigger identity and next per-trigger ordinal. Reconstruction accepts only canonical snapshots from DSH's system-prompt owner, treats a named section as one effective-state transition even when another owner's aggregate update repeats it, and ignores legacy or malformed plugin prose. Visible wording does not determine cooldown or escalation identity.
18
+ The binding catalog contains one bounded literal configuration document with a
19
+ fixed owner prefix; its reader recognizes that prefix only within a `ptc-plus`
20
+ `catalog` source. Only a later binding catalog replaces it; an explicit empty
21
+ catalog withdraws it. Host runtime-context clearances and PTC recovery snapshots
22
+ do not withdraw catalogs. Suppression prevents new delivery without changing the
23
+ meaning of a retained catalog. This is API documentation, not proof of successful
24
+ initialization, current values, or recoverable session-local state. The historical
25
+ snapshot reader remains intact: an accepted recovery snapshot retires old binding
26
+ sections once, while a catalog supplies the current configuration. No history or
27
+ journal is rewritten. Catalog and recovery changes never resend each other's text.
12
28
 
13
- Platform wording names execution-world differences without assuming Windows, WSL, POSIX, a shell, or package-runner availability. `edit_run_code` remains independently available as a fixed real tool and does not depend on a recovery-tip trigger.
29
+ The binding catalog wrapper names `run_code` as the invocation location and
30
+ limits replacement to the previous global binding API reference. Its body contains
31
+ only entry labels, optional user prompts and selected declarations; checkpoint
32
+ instructions belong to `repl.state` discovery, and authoring instructions belong
33
+ to the `/binding` task. Initialization failures are reported by execution results.
34
+ Readers accept the exact bounded historical wrappers and empty marker as
35
+ well as the emitted form. A wording change does not reinterpret old records or
36
+ require journal migration. Catalog bodies are compared literally, so revised
37
+ documentation can cause one replacement on upgrade and is then deduplicated.
38
+
39
+ The public `systemPrompt.context` registry contains one empty PTC delivery witness.
40
+ DSH omits this contribution when `includeRuntimeContext` is false or a scoped
41
+ runtime-context suppressor applies; the empty text never enters its rendered
42
+ aggregate. The assembly listener captures that witness and the exact request's
43
+ PTC facts, leaving unrelated aggregate content unchanged. `agent/pre-step`
44
+ delegates its waterfall first and adds messages only to an accepted, non-cancelled
45
+ step matching that assembly. It neither calls `inject` after inbox claim nor wakes
46
+ the agent with `steer`, and it cannot override admission or runtime suppression.
47
+
48
+ Delivery is reconstructed from committed messages, never from a proposed step.
49
+ The public ordered Session surface identifies retained current-state snapshots;
50
+ historical aggregate state includes DSH's exact owner-sourced clearance marker.
51
+ An accepted step's pending aggregate replacement can withdraw an old PTC section,
52
+ requiring an independent current declaration in that same step.
53
+ Raw committed history identifies delivered tip ordinals and cooldown distance,
54
+ but cannot make hidden bindings model-visible. Compaction or removal of a state
55
+ snapshot requires a fresh eligible state or an explicit clear. Suppressed steps
56
+ send nothing; the next permitted step reconciles claims. Disabled PTC mode retains
57
+ only the settings surface and a passive presentation cleanup listener, which can
58
+ clear previously delivered claims without mounting runtime tools, reading binding
59
+ storage, or publishing new declarations. Plugin/agent disposal releases pending
60
+ assembly ownership. Resume reconstructs from the same durable source records.
61
+
62
+ PTC Plus keeps the stable REPL guidance limited to invariants, discovery entry points, and environment-neutral boundaries. `internal/session-log-view.js` projects immutable facts for edit targeting, successful-run reset, context distance, normalized Cordis call/inspection counts, canonical historical DSH snapshots, and formed PTC messages. `internal/runtime-contexts.js` renders rewrite feedback only when the rewritten cell lacks a valid journal, Cordis recovery while historical transcript lacks a newer successful live Inspect, and at most one recovery tip. Known failures already carry partial-execution and retry guidance in their result, so they do not generate duplicate rewrite feedback. `internal/runtime-messages.js` owns bounded message forms: snapshot sections total at most 65536 UTF-16 code units and recognize the two historical binding sections for retirement; a catalog body is at most 65536 code units, with the tighter configured-declaration budget still enforced by the binding owner; a notice is at most 8192 code units with a valid trigger/ordinal identity. Malformed records are not delivery evidence. Transparent rewrites remain result metadata. Edit provenance and target lifecycle remain in real call/results and private derived-execution metadata. These messages never change the tool list, tool schemas, or system sections.
63
+
64
+ The default triggers are a repeated binding failure and a failure whose diagnostic or structured cause identifies an executable, shell, or path problem. The first tip is concise. A matching trigger may produce another tip only after `tipCooldownMessages` model-context steps; unresolved matching tips reach the detailed form after `tipEscalationFailures` occurrences. A successful cell resets the unresolved escalation count. Every emitted tip name carries its stable trigger identity and next per-trigger ordinal. Reconstruction merges valid PTC notices and canonical historical sections from DSH's system-prompt owner, counting each delivered identity once across both sources. Unformed tasks and malformed plugin prose are not tip evidence. Visible wording does not determine cooldown or escalation identity; an exhausted safe-integer ordinal yields no further tip.
65
+
66
+ Platform wording names execution-world differences without assuming Windows, WSL, POSIX, a shell, or package-runner availability. Bounded multiline message/stderr facts may supply a missing cause, but generic exit failure alone does not prove an environment problem. Repeated lexical failures point to visible source, scope and initialization; discovery is reserved for worker-owned capability failures. Warning state describes the failed cell conservatively, not the act of emitting a warning. `edit_run_code` remains independently available as a fixed real tool and does not depend on a recovery-tip trigger; a validated result repair only proves syntax/preflight acceptance and retains the target guard and complete-cell execution contract.
14
67
 
15
68
  The Cordis recovery context is not a failure tip and is not controlled by fatigue settings. It narrows the meaning of recorded values after a lifecycle boundary: they remain historical program data but cannot prove current process-local state. It clears only after a newly settled successful `cordis_inspect*` transcript, does not infer whether the original process survived, and never redispatches a historical effect.
16
69
 
17
70
  ## Alternatives considered
18
71
 
19
72
  - **Keep all recovery instructions in the stable system prompt.** This makes every request pay for rare failures and makes platform-specific text look universally applicable.
73
+ - **Keep configured APIs inside recovery snapshots.** A short-lived recovery fact would resend unchanged interfaces on both entry and withdrawal. Catalogs already express the required public Host semantics; a new delta protocol or producer registry is unnecessary.
20
74
  - **Emit a tip after every matching failure.** This repeats stale advice, consumes context, and can encourage blind retry loops.
21
75
  - **Store mutable tip counters only in the kernel.** A worker restart or replay would then change model-visible behavior without a session-log source.
22
76
  - **Infer tip identity from rendered prose or one fixed section name.** Wording changes would reset history, unrelated plugin text could create false matches, and an unchanged aggregate context would not persist repeated occurrences.
@@ -26,4 +80,4 @@ The Cordis recovery context is not a failure tip and is not controlled by fatigu
26
80
 
27
81
  ## Consequences
28
82
 
29
- Normal requests receive only the persistent REPL invariants in stable system text. Prompt assembly performs one linear event projection regardless of how many PTC runtime contexts consume it; renderers receive facts rather than raw history or search callbacks. Failure recovery becomes an append-only, bounded context contribution with explicit cooldown and escalation semantics. Changing a tip's name records a new effective context even when compact wording repeats, while aggregate snapshots that repeat the same named section do not advance fatigue state. Tip wording and thresholds are configurable, but their defaults remain conservative; disabling tips removes only the runtime context and does not remove `edit_run_code` or any native capability.
83
+ Normal requests receive only the persistent REPL invariants in stable system text. Renderers consume projected facts; accepted-step delivery rechecks committed history and the public surface before proposing bounded messages. A PTC transition appends no unrelated owner text, and another owner's aggregate transition does not resend unchanged PTC state. A new tip ordinal records a separate notice even when compact wording repeats, while repeated historical copies do not advance fatigue state. Tip thresholds are configurable; disabling tips stops future notices without removing `edit_run_code` or any native capability. Historical records require no migration.
@@ -6,7 +6,7 @@ Recovery tips are a presentation policy, while PTC Plus owns the REPL, diagnosti
6
6
 
7
7
  ## Decision
8
8
 
9
- Keep the current deterministic recovery policy in `internal/recovery-tips.js` as a replaceable local provider. The provider consumes the immutable facts produced by `internal/session-log-view.js`; it does not traverse raw events, pair calls, parse journals, or query the core through callbacks. The core calls it only for a bounded named runtime context, and the provider does not change execution, journal semantics, tool schemas, or stable system text. Defer an external adapter until a public facts and decision contract exists; the adapter must be optional, fail closed, and leave the local provider or disabled mode available when absent.
9
+ Keep the current deterministic recovery policy in `internal/recovery-tips.js` as a replaceable local provider. The provider consumes the immutable facts produced by `internal/session-log-view.js`; it does not traverse raw events, pair calls, parse journals, or query the core through callbacks. The core calls it for one bounded named tip, delivered as an independent PTC notice under [ADR 0010](0010-session-log-derived-recovery-tips.md). The provider does not change execution, journal semantics, tool schemas, or stable system text. Defer an external adapter until a public facts and decision contract exists; the adapter must be optional, fail closed, and leave the local provider or disabled mode available when absent.
10
10
 
11
11
  ## Alternatives considered
12
12
 
@@ -1,12 +1,14 @@
1
1
  # Preserve Mixed Destructuring Initialization
2
2
 
3
+ The historical behavior below is retained by the frozen `legacy-v1` compiler. New cells use the logical identities and complete declarator publication in [ADR 0025](0025-use-versioned-logical-binding-identities.md).
4
+
3
5
  ## Problem
4
6
 
5
7
  Loose cross-cell redeclarations must assign names that already exist while introducing fresh names from one top-level destructuring declarator. A text-level whole-pattern assignment can preserve simple values, but it changes JavaScript binding initialization when a default expression refers to an earlier fresh binding, and a generated helper can also change top-level `await` or initializer ordering.
6
8
 
7
9
  ## Decision
8
10
 
9
- `internal/repl-convenience.js` evaluates the initializer as a helper argument, then runs the original destructuring pattern unchanged inside the helper. This leaves initializer references outside the new pattern scope while the JavaScript engine owns binding order, TDZ, computed keys, defaults, iterator handling, lexical shadowing, and abrupt completion inside the pattern. After the complete pattern succeeds, the helper passes every bound value positionally to a commit callback: existing names are assigned to their session bindings and fresh values are returned to one outer declaration. Arrays carry the positional values so names such as `__proto__` have no property-key semantics. A pattern containing direct `await` uses an async helper; a synchronous pattern stays synchronous. Declarator replacements remain in source order, and both lexical and `var` mixed declarations use the same native-pattern model with their corresponding outer declaration kind.
11
+ `internal/legacy-repl-convenience.js` evaluates the initializer as a helper argument, then runs the original destructuring pattern unchanged inside the helper. This leaves initializer references outside the new pattern scope while the JavaScript engine owns binding order, TDZ, computed keys, defaults, iterator handling, lexical shadowing, and abrupt completion inside the pattern. After the complete pattern succeeds, the helper passes every bound value positionally to a commit callback: existing names are assigned to their session bindings and fresh values are returned to one outer declaration. Arrays carry the positional values so names such as `__proto__` have no property-key semantics. A pattern containing direct `await` uses an async helper; a synchronous pattern stays synchronous. Declarator replacements remain in source order, and both lexical and `var` mixed declarations use the same native-pattern model with their corresponding outer declaration kind.
10
12
 
11
13
  ## Alternatives considered
12
14
 
@@ -1,12 +1,18 @@
1
1
  # Isolate REPL Redeclaration Convenience
2
2
 
3
+ The historical behavior below is retained by the frozen `legacy-v1` compiler. New cells use the logical identities and complete declarator publication in [ADR 0025](0025-use-versioned-logical-binding-identities.md).
4
+
3
5
  ## Problem
4
6
 
5
- The persistent REPL uses one worker lexical environment so later cells can refer to earlier top-level bindings. That convenience is not JavaScript's module or function semantics, and mixed old/new destructuring requires a policy for combining declaration and assignment. Keeping that policy inside `internal/cell-analysis.js` makes core parsing and durability analysis depend on one replaceable persistence strategy.
7
+ The persistent REPL uses one worker lexical environment so later cells can refer to earlier top-level bindings. That convenience is not JavaScript's module or function semantics. Mixed old/new destructuring needs a policy for combining declaration and assignment, while ordinary iterative work also needs an explicit policy for replacing an earlier function or class declaration. Keeping either policy inside `internal/cell-analysis.js` makes core parsing and durability analysis depend on one replaceable persistence strategy.
6
8
 
7
9
  ## Decision
8
10
 
9
- `internal/cell-analysis.js` owns cell parsing, binding inventory, durability classification, return rewriting, and execution preparation. Shared binding-pattern traversal lives in `internal/binding-pattern.js`. `internal/repl-convenience.js` owns the optional loose-redeclaration policy, including all-existing replacement and mixed destructuring lowering; it returns executable source, collisions, redeclaration metadata, and rewrite provenance through one narrow function. The current persistent REPL continues to enable this policy, so the user-facing convenience and journal behavior remain unchanged. A future state/frame persistence implementation can replace this policy without changing the cell language analyzer.
11
+ `internal/legacy-cell-analysis.js` owns legacy cell parsing, binding inventory, durability classification, return rewriting, and execution preparation. Shared binding-pattern traversal lives in `internal/binding-pattern.js`. `internal/legacy-repl-convenience.js` owns two independent, optional cross-cell policies: variable replacement (including mixed destructuring lowering) and named function/class replacement. It returns executable source, collisions, redeclaration metadata, and rewrite provenance through one narrow function. Both policies are enabled by default for the REPL workflow; function/class replacement can still be explicitly disabled with `looseTopLevelFunctionClassRedeclarations`.
12
+
13
+ Only a top-level named `FunctionDeclaration` or `ClassDeclaration` whose name existed before preparation is eligible. Its catalog provenance must prove that the existing binding is writable: `let`, `var`, function, and class are writable; a source `const` is writable only when that cell's variable policy lowered it to `let`; imports and reserved/private bindings are not writable. Unknown provenance fails closed. A function is lowered at its declaration position to assignment of an anonymous function expression, so recursive reads resolve through the replaceable outer binding. A class is lowered to assignment of a named class expression, preserving its inner self-reference and ensuring a throw during class evaluation leaves the old outer value unchanged. Both forms deliberately take effect at the declaration position rather than acquiring native declaration hoisting. A terminated `void 0` statement prevents the assignment value from becoming the cell completion.
14
+
15
+ The original Program is validated before lowering. Same-cell duplicates, nested or block declarations, parsing, TypeScript scope rules, and source positions therefore remain owned by the language pipeline. A future state/frame persistence implementation can replace these policies without changing the cell language analyzer.
10
16
 
11
17
  ## Alternatives considered
12
18
 
@@ -18,4 +24,4 @@ The persistent REPL uses one worker lexical environment so later cells can refer
18
24
 
19
25
  ## Consequences
20
26
 
21
- The core analyzer has no mixed-redeclaration lowering helpers and can be tested independently of the REPL convenience policy. The compatibility module remains responsible for its custom hybrid semantics and its focused tests; it must not be described as native JavaScript semantics. Future persistence work can introduce fresh cell lexical frames while retaining or replacing the convenience adapter at one explicit boundary.
27
+ The core analyzer has no redeclaration lowering helpers and can be tested independently of the REPL convenience policy. The compatibility module remains responsible for its custom replacement semantics and focused tests; neither policy is native JavaScript semantics. Binding assignability is reconstructed from prepared source and each cell's persisted policy rather than runtime-value inspection. Future persistence work can introduce fresh cell lexical frames while retaining or replacing the convenience adapter at one explicit boundary.
@@ -2,13 +2,17 @@
2
2
 
3
3
  ## Problem
4
4
 
5
- Durable replay prepares the original cell source again. AST module and REPL convenience rewrites are configuration-controlled, so using the current profile during replay can reject a cell that was durable when it was recorded. Replay would then discard recoverable bindings even though the journal still proves the cell's calls and completion.
5
+ Durable replay prepares the original cell source again. AST module rewrites and both REPL redeclaration conveniences are configuration-controlled, so using the current profile during replay can reject a cell that was durable when it was recorded or infer the wrong binding assignability. Replay would then discard recoverable bindings even though the journal still proves the cell's calls and completion.
6
6
 
7
7
  ## Decision
8
8
 
9
- Journal version 3 records `rewritePolicy` beside `bindingMode` with the three boolean rewrite settings used to prepare the cell. Live journals capture the active profile; replay passes each node's recorded policy to `prepareProgram`. The policy is part of journal normalization and equality, is frozen with the journal, and is required by the closed schema. A profile change therefore affects only new cells; existing durable nodes retain the language policy under which they were evaluated.
9
+ The module-lowering fields below retain the `legacy-v1` contract. Journal v9 additionally selects the complete language through `languageSemantics`; its `stateful-v1` and `protected-v1` contracts are owned by [ADR 0025](0025-use-versioned-logical-binding-identities.md). A historical `live-readonly` field does not independently make a stateful binding read-only.
10
10
 
11
- The journal decoder also owns the predecessor adapters. Version 1 has its original closed field set and migrates with all three later rewrite switches disabled, matching the language pipeline that emitted it; `bindingMode` continues to preserve its top-level redeclaration policy. Its string call-ID confirmations become version 3 event sequences only when the enclosing session log contains exactly one earlier unjournaled `run_code` call with that identity. Missing or repeated candidates are ambiguous and fail closed. Version 2 already contains `rewritePolicy` and normalizes to version 3 only when its confirmed no-op list is absent or empty; version 2 call-ID confirmations remain unsupported.
11
+ Journal version 4 replaces `bindingMode` with the closed `bindingPolicy` object containing the exact `variableRedeclarations` and `functionClassRedeclarations` booleans used to prepare the cell. It retains `rewritePolicy` with the three module and mixed-declaration rewrite booleans, and adds the closed `moduleSemantics.defaultExportBinding` value. Current cells record `live-readonly`; this is a source-lowering generation, not a user setting. Live journals capture both active policies and the fixed module semantics; replay passes every recorded value to `prepareProgram`. These objects participate in normalization and semantic equality, are frozen with the journal, and are required by the closed schema. A profile change therefore affects only new cells; existing durable nodes retain the language policy, module lowering, and writable-binding provenance under which they were evaluated.
12
+
13
+ Journal version 7 adds the closed `moduleSemantics.importExpressionBoundary` value, which is orthogonal to the default-export binding model and fixes how a module-reference write is lowered relative to its preceding statement. Current cells record `statement-safe`: the lowered write keeps its own statement boundary, so automatic semicolon insertion cannot merge it into a preceding semicolonless expression and change which value receives the write or whether the write runs at all. Versions 1 through 6 normalize to `legacy` so historical cells replay the lowering generation that evaluated them instead of the current one. The value participates in normalization, freezing, and semantic equality like the other closed semantics fields.
14
+
15
+ The journal decoder also owns the predecessor adapters. Versions 1 through 3 retain their original closed field sets as inputs and normalize forward through the closed generations. Their `bindingMode` maps exactly to `variableRedeclarations`; `functionClassRedeclarations` is always `false` because those language pipelines did not implement the feature. They receive `legacy-variable` default-export semantics so loose journals preserve the historically writable generated binding and strict journals preserve its const behavior. Version 1 receives all three later rewrite switches as disabled and its string call-ID confirmations become event sequences only when the enclosing session log contains exactly one earlier unjournaled `run_code` call with that identity. Missing or repeated candidates are ambiguous, so they cannot prove old state and form an unknown recovery boundary. Versions 2 and 3 retain their recorded `rewritePolicy`; unsupported non-numeric predecessor confirmations receive the same conservative contraction. Each later generation extends the same chain: version 4 records no Global User Binding relation, version 5 adds the snapshot fingerprint, version 6 adds `userBindingsReusePolicy`, version 7 adds `importExpressionBoundary`, and version 8 adds the per-name shadow policy with its name evidence, owned by [ADR 0023](0023-global-user-bindings.md). Version 9 adds the required complete language generation, with versions 1 through 8 fixed to the frozen legacy compiler rather than reinterpreted by current lowering ([ADR 0025](0025-use-versioned-logical-binding-identities.md)). Per [ADR 0007](0007-separate-worker-transport-from-session-semantics.md), rejecting predecessor state evidence does not make historical metadata an availability gate for the current valid call.
12
16
 
13
17
  ## Alternatives considered
14
18
 
@@ -18,8 +22,10 @@ The journal decoder also owns the predecessor adapters. Version 1 has its origin
18
22
 
19
23
  **Read the current profile during replay.** This keeps the journal small, but makes durable recovery depend on mutable deployment configuration and causes valid historical cells to become unrecoverable after a configuration change.
20
24
 
21
- **Accept every version 2 confirmation by call ID.** Preserving those values would require replay to guess which event a reused provider call ID denotes. Only the empty-confirmation subset has an identity-independent meaning, so broader migration would weaken the version 3 event-sequence contract owned by [ADR 0007](0007-separate-worker-transport-from-session-semantics.md).
25
+ **Infer the default-export lowering from source or journal version during replay.** Source does not identify which implementation generation evaluated it, while version-derived behavior becomes implicit protocol state. Persisting the closed semantic value makes migration explicit and keeps replay deterministic.
26
+
27
+ **Accept every predecessor confirmation by call ID.** Preserving those values would require replay to guess which event a reused provider call ID denotes. Only the version 1 adapter with a unique enclosing session event has sufficient evidence, so broader migration would weaken the event-sequence contract owned by [ADR 0007](0007-separate-worker-transport-from-session-semantics.md).
22
28
 
23
29
  ## Consequences
24
30
 
25
- The current journal schema is version 3. Replay remains source-based and deterministic while configuration changes no longer invalidate durable cells. Version 1 histories retain the predecessor language behavior and migrate only uniquely identified confirmations; version 2 histories without call-ID confirmations retain their recorded rewrite policy. Ambiguous identity remains unsupported recovery input rather than receiving guessed defaults. New profile settings apply at the next live cell boundary.
31
+ The journal schema introduced by this decision is version 4; the closed field sets, generation constants, and migration rules are owned by [`internal/session-journal-schema.js`](../../internal/session-journal-schema.js), with validation, migration, and creation in [`internal/session-journal.js`](../../internal/session-journal.js) and event association and fold/recovery in [`internal/session-journal-recovery.js`](../../internal/session-journal-recovery.js). Replay remains source-based and deterministic across configuration changes without invalidating durable cells or altering reconstructed binding assignability. Version 1 histories retain the predecessor rewrite behavior and migrate only uniquely identified confirmations; versions 2 and 3 retain their recorded rewrite policy. Versions 1 through 3 fix function/class replacement to disabled and default-export lowering to `legacy-variable`; versions 1 through 6 fix the import-expression boundary to `legacy`. Later records preserve their independently recorded values instead of guessing from current behavior. Ambiguous identity remains unsupported recovery input rather than receiving guessed defaults. New profile settings apply at the next live cell boundary.
@@ -6,7 +6,7 @@ PTC cells are prepared by several source-to-source passes before they reach the
6
6
 
7
7
  ## Decision
8
8
 
9
- Each source edit carries a compact segment map from generated text back to the original cell. Unchanged text retains exact offsets; generated module bindings and source literals carry token-level anchors to their originating AST nodes, while other introduced text maps to the replaced source span. [`internal/source-position-map.js`](../../internal/source-position-map.js) validates and sorts one pass of non-overlapping edits, then assembles source and composed segments in one traversal. Binary segment lookup handles repeated or non-monotonic explicit token anchors without rescanning the complete map. Maps compose through every preparation pass. Mixed-destructuring generation emits copied pattern, initializer, and binding ranges through the same mapped representation instead of one opaque replacement string. [`internal/cell-analysis.js`](../../internal/cell-analysis.js) converts rewrite-time preflight and collision spans to original-cell coordinates before returning a prepared program; runtime exception positions use the same map after worker execution.
9
+ Each source edit carries a compact segment map from generated text back to the original cell. Unchanged text retains exact offsets; generated module bindings and source literals carry token-level anchors to their originating AST nodes, while other introduced text maps to the replaced source span. [`internal/source-position-map.js`](../../internal/source-position-map.js) validates and sorts one pass of non-overlapping edits, then assembles source and composed segments in one traversal. Binary segment lookup handles repeated or non-monotonic explicit token anchors without rescanning the complete map. Maps compose through every preparation pass. Mixed-destructuring generation emits copied pattern, initializer, and binding ranges through the same mapped representation instead of one opaque replacement string. [`internal/cell-parser.js`](../../internal/cell-parser.js) is the single executable-parse entry: it relocates AST ranges to original-cell coordinates and reports parse failures in those coordinates, so no downstream pass applies a wrapper offset. [`internal/cell-analysis.js`](../../internal/cell-analysis.js) maps parse failures raised against the module-rewrite output, preflight spans, and collision spans back to original-cell coordinates before returning a prepared program; runtime exception positions use the same map after worker execution, except a module-load failure that already carries an original-cell position.
10
10
 
11
11
  ## Alternatives considered
12
12
 
@@ -10,7 +10,7 @@ An ignored root `REVIEW_FINDINGS.md` prevents unresolved review findings from be
10
10
 
11
11
  Review output and ledger mutation follow task authority. A read-only review reports records in the ledger's semantic fields without writing checkout state. Every implementation preserves an active ledger, but an ordinary change with no finding does not create one. `npm run review:new` creates the ignored root ledger only when a task authorizes capture or resolution of at least one finding; implementation imports those findings before editing their fixes. Archives move under Git's local `review-findings/archive` metadata path, so they cannot enter a commit and remain associated with the checkout.
12
12
 
13
- Ledger validation, readiness, deterministic verification, archive, and commit proof are distinct states with one implementation. `npm run review:validate` checks schema and tracked-file safety while accepting a valid open ledger. `npm run review:gate` is read-only: it blocks an open ledger, validates durable owners for accepted findings, and never archives. `npm run verify` performs schema validation before syntax and coverage checks, so open-ledger work can collect evidence. `npm run check` applies the readiness gate first, then materializes the current tracked and non-ignored checkout through Git's clean and index semantics in a temporary Git administrative directory. Git selects that directory's default index through `--git-dir` and reads the target checkout through `--work-tree`; it never receives an alternate-index environment path that could fall back to the real repository index. The temporary object database reads the repository's objects through a relative alternates entry and stores new fingerprint objects locally. The resulting tree object ID includes canonical blobs, symlink identity, and file modes while remaining independent of staged content. Sparse checkouts retain skip-worktree paths from the `HEAD` baseline and apply clean conversion only to materialized paths, so an absent out-of-cone file is neither lost nor mistaken for a deletion. Every path discovered by Git is reapplied through NUL-delimited literal input. The command separately snapshots the ignored ledger, runs `verify`, rejects changed source or ledger state, and refreshes the proof before archiving a resolved ledger. Repository scripts that launch npm as a child use one command resolver: an invoking npm process supplies its CLI path and Node executable, while direct script invocation falls back to the platform npm executable. A successful later check without an active ledger also refreshes an older proof. The pre-commit hook rejects open and unverified resolved ledgers, then asks Git for the prospective index tree object ID and requires it to equal the verified source tree. Staging the complete verified tree permits repeated commit attempts; partial staging, additional staged content, mode-only changes, or later checkout changes require reconciliation or another checked workflow. An advanced HEAD proves that the checked commit completed and retires the old proof.
13
+ Ledger validation, readiness, deterministic verification, archive, and commit proof are distinct states with one implementation. `npm run review:validate` checks schema and tracked-file safety while accepting a valid open ledger. `npm run review:gate` is read-only: it blocks an open ledger, validates durable owners for accepted findings, and never archives. `npm run verify` performs schema validation before syntax and coverage checks, so open-ledger work can collect evidence. `npm run check` applies the readiness gate first, then materializes the current tracked and non-ignored checkout through Git's clean and index semantics in a temporary Git administrative directory. Git selects that directory's default index through `--git-dir` and reads the target checkout through `--work-tree`; it never receives an alternate-index environment path that could fall back to the real repository index. The temporary object database reads the repository's objects through a relative alternates entry and stores new fingerprint objects locally. The resulting tree object ID includes canonical blobs, symlink identity, and file modes while remaining independent of staged content. Sparse checkouts retain skip-worktree paths from the `HEAD` baseline and apply clean conversion only to materialized paths, so an absent out-of-cone file is neither lost nor mistaken for a deletion. Every path discovered by Git is reapplied through NUL-delimited literal input. The command separately snapshots the ignored ledger, runs `verify`, rejects changed source or ledger state, and refreshes the proof before archiving a resolved ledger. Repository scripts that launch npm as a child use one command resolver: an invoking npm process supplies its CLI path and Node executable, while direct script invocation falls back to the platform npm executable. A successful later check without an active ledger also refreshes an older proof. The pre-commit hook rejects open and unverified resolved ledgers, requires a verification proof for the current `HEAD`, requires equal source and index tree fingerprints, and requires a clean independent-review verdict bound to the same `HEAD`, fingerprint and scope (ADR 0026). Staging the complete verified tree permits repeated commit attempts; partial staging, additional staged content, mode-only changes, or later checkout changes require reconciliation or another checked workflow. An advanced HEAD, a missing proof, or a verdict that does not match the verified candidate retires the stale evidence and blocks the commit.
14
14
 
15
15
  Hook installation is explicit. `npm run hooks:install` selects the tracked hook path only when the effective `core.hooksPath` is unset or already `.githooks`. Before the first switch from Git's default hooks directory, installation rejects any non-sample hook file there; it also rejects an incompatible configured path instead of disabling another hook owner. Dependency installation has no Git-configuration side effect.
16
16
 
@@ -6,8 +6,55 @@ PTC Plus integrates with DSH services, request bindings, prompt assembly, sessio
6
6
 
7
7
  ## Decision
8
8
 
9
+ PTC Plus must remain independently installable on unmodified official DSH distributions. Host source is read-only research evidence, not an implementation workspace for plugin features. Plugin changes must not patch host source or installed packages, introduce install-time host patches, or require a custom host build. Plugin-owned components, panels, styling, portals and public renderer replacements are valid UI choices within the consumed contracts; integration does not require every visual element or layout to be native. A locally invented extension declaration is not a published public capability. Choose among published surfaces according to the required user experience rather than assuming that a UI feature must become a historical message node. If none can satisfy the required behavior, record the actual limitation; do not substitute a custom distribution or present a compatibility fallback as delivery.
10
+
9
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.
10
12
 
13
+ Preceding public contracts remain supported where capability detection is
14
+ unambiguous. Tools presentation is selected by the installed public schema;
15
+ Client contributions depend on their slots and supplied hooks rather than unused
16
+ package gates. Preset projection evidence takes precedence over the preceding
17
+ public session-summary field, and the current composer currency takes precedence
18
+ over the earlier session/interactions currency. This compatibility does not
19
+ extend to private stores or inferred binding state.
20
+
21
+ Compatibility decisions have one owner per public contract and execution
22
+ environment. `src/client-host-compat.js` owns Client preset reads and subscriptions
23
+ and composer compatibility. UI consumers own feature eligibility and slot
24
+ registration. `scripts/dsh-host-contract.mjs` owns selected-installation package
25
+ resolution, tools presentation and persona field adaptation for development and
26
+ acceptance commands. Host runtime contracts remain in their existing focused
27
+ owners, including `internal/session-events.js`, `internal/settings-compat.js`, and
28
+ `internal/execution-seam-compat.js`, which owns which program-execution service the
29
+ plugin attaches to and the call shape and provider descriptors it presents for it
30
+ ([ADR 0028](0028-attach-to-the-host-ptc-execution-seam.md)).
31
+ `internal/host-rpc.js` owns UI Remote service registration and withdrawal;
32
+ `src/client-rpc.js` owns Client mounting and result unwrapping. Both consume the
33
+ executable wire definitions in `internal/rpc-contract.js`. Binding and observation
34
+ owners supply operation handlers and retain their domain validation. Consumers
35
+ use these operations instead of repeating transport or field-generation checks.
36
+ Adapters preserve unknown evidence and public subscription disposal; they do not
37
+ cache session capabilities globally. Test-only persistence fixtures and explicit
38
+ offline journal migration retain their own lifecycles and validation contracts.
39
+
40
+ ## UI communication
41
+
42
+ Plugin UI calls use DSH's public Typert Remote and Gateway over the existing
43
+ `/api` carrier. The shared contract defines `ptcPlusBindings.invoke` and
44
+ `ptcPlusRepl.invoke`, each with an operation string, JSON payload, optional
45
+ cancellation signal and the domain result envelope. The Client unwraps only the
46
+ Gateway result layer. The Host owns authentication, origin checks, transport
47
+ cancellation and dispatch; a connection identity does not confer a draft locator.
48
+
49
+ The communication owner contributes one package definition containing the active
50
+ services. Disabling Global User Bindings withdraws its service and invocation;
51
+ REPL observation has its own eligibility checks. Service removal aborts pending
52
+ calls and invalidates retained references. Provider replacement cancels the old
53
+ requests and republishes active definitions through Cordis injection. Client
54
+ Remote mounting belongs to its calling fiber and is released with that fiber.
55
+ Writes are never retried by the adapter. Business owners preserve revision,
56
+ capability, storage and observation rules independently of transport.
57
+
11
58
  ## Alternatives considered
12
59
 
13
60
  **Pin one verified DSH release.** A pin makes one historical environment reproducible but turns normal upstream progress into an artificial incompatibility and allows the implementation to drift from the release users actually install.
@@ -20,4 +67,6 @@ The compatibility target is the latest available DSH release. Production behavio
20
67
 
21
68
  ## Consequences
22
69
 
70
+ 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
+
23
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.
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## Problem
4
4
 
5
- The ordinary-task A/B benchmark previously copied the active PTC Plus checkout into each arm. The workload therefore changed whenever the plugin repository grew, making absolute machine budgets and longitudinal comparisons unstable. The same source tree was also serving as the host, the treatment-under-test workspace, and the measurement workload, which mixes unrelated variables into one measurement.
5
+ Using the active PTC Plus checkout as each ordinary-task A/B arm's workload would make the workload change whenever the plugin repository grows, destabilizing absolute machine budgets and longitudinal comparisons. It would also make one source tree serve as the host, treatment-under-test workspace, and measurement workload, mixing unrelated variables into one measurement.
6
6
 
7
7
  ## Decision
8
8
 
9
- The primary ordinary-task A/B workload is now a purpose-built, versioned, zero-dependency Node.js fixture in `fixtures/ab-node-project-v1`. The fixture manifest is the single owner of the fixture name, version, content SHA-256, deterministic Git identity/commit, and deterministic dirty state. The runner materializes the fixture independently into each arm workspace, initializes the same deterministic Git history, applies the same uncommitted changes, and never copies the active PTC Plus checkout as the model workload.
9
+ The primary ordinary-task A/B workload is a purpose-built, versioned, zero-dependency Node.js fixture in `fixtures/ab-node-project-v1`. The fixture manifest is the single owner of the fixture name, version, content SHA-256, deterministic Git identity/commit, and deterministic dirty state. The runner materializes the fixture independently into each arm workspace, initializes the same deterministic Git history, applies the same uncommitted changes, and never copies the active PTC Plus checkout as the model workload.
10
10
 
11
11
  The A/B task set contains a fixed, cheap, machine-checkable canary that exercises `run_code` before the full paired matrix starts. Reports record the fixture path, version, and content hash so future runs are grouped by benchmark version. The current PTC Plus checkout is kept as a separate self-hosting acceptance surface; it is not the stable README headline benchmark.
12
12
 
@@ -22,4 +22,4 @@ The A/B task set contains a fixed, cheap, machine-checkable canary that exercise
22
22
 
23
23
  ## Consequences
24
24
 
25
- The benchmark workload is stable under unrelated PTC Plus source changes and has its own result series tied to `fixtureVersion` and content hash. Existing README totals from the checkout-based series are explicitly non-comparable to the new fixture series. Maintaining a benchmark now requires updating the fixture manifest together with the fixture content, and a materially different task set or fixture change starts a new series rather than reusing old totals.
25
+ The benchmark workload is stable under unrelated PTC Plus source changes and has its own result series tied to `fixtureVersion` and content hash. Results produced from an active-checkout workload are not comparable to the versioned-fixture series. Maintaining the benchmark requires updating the fixture manifest together with the fixture content, and a materially different task set or fixture change starts a new series rather than reusing old totals.