dsh-ptc-plus 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.en.md +164 -78
  2. package/README.md +165 -79
  3. package/assets/dsh-ptc-plus-banner-en.webp +0 -0
  4. package/assets/dsh-ptc-plus-banner-zh.webp +0 -0
  5. package/assets/ptc-plus-icon.svg +5 -0
  6. package/client.js +854 -336
  7. package/compiler-core.cjs +161 -157
  8. package/compiler-core.cjs.map +3 -3
  9. package/docs/README.md +4 -1
  10. package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +8 -7
  11. package/docs/adr/0008-define-agent-operating-contract.md +2 -2
  12. package/docs/adr/0010-session-log-derived-recovery-tips.md +7 -0
  13. package/docs/adr/0016-archive-resolved-review-findings.md +3 -3
  14. package/docs/adr/0019-plugin-settings-and-kill-switch.md +3 -3
  15. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -0
  16. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +14 -3
  17. package/docs/adr/0023-global-user-bindings.md +7 -7
  18. package/docs/adr/0025-use-versioned-logical-binding-identities.md +3 -3
  19. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +23 -7
  20. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +9 -5
  21. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +26 -6
  22. package/docs/adr/0031-close-semantic-obligations-by-owner.md +29 -0
  23. package/docs/adr/README.md +4 -4
  24. package/docs/architecture.md +15 -10
  25. package/docs/binding-review-placement-design.md +1 -1
  26. package/docs/client-ui.md +9 -5
  27. package/docs/durability-design.md +12 -9
  28. package/docs/installation.md +27 -9
  29. package/docs/runtime-reference.md +23 -12
  30. package/docs/semantic-validation.md +7 -3
  31. package/docs/stateful-binding-updates-proposal.md +8 -4
  32. package/docs/user-bindings.en.md +10 -7
  33. package/docs/user-bindings.md +9 -6
  34. package/docs/value-wire.md +1 -1
  35. package/docs/verification-optimization-work.md +41 -0
  36. package/docs/verification.md +53 -2
  37. package/index.js +39 -34
  38. package/internal/async-local-storage-intrinsics.js +43 -0
  39. package/internal/binding-declaration-contract.js +8 -0
  40. package/internal/binding-source-analysis.js +381 -64
  41. package/internal/binding-update-policy.js +7 -1
  42. package/internal/callable-source-facts.js +37 -1
  43. package/internal/cell-analysis.js +85 -17
  44. package/internal/compiler-intrinsics.js +9 -43
  45. package/internal/compiler-module-links.js +7 -4
  46. package/internal/config-spec.js +1 -1
  47. package/internal/cordis-tools-owner.js +20 -10
  48. package/internal/dynamic-environment-integration.js +8 -4
  49. package/internal/dynamic-environment-runtime.js +24 -3
  50. package/internal/dynamic-native-calls.js +4 -1
  51. package/internal/dynamic-native-runtime.js +15 -1
  52. package/internal/edit-transport-owner.js +80 -20
  53. package/internal/execution-seam-compat.js +192 -30
  54. package/internal/failure-reporting.js +38 -30
  55. package/internal/isolated-worker.js +17 -10
  56. package/internal/kernel-worker.js +645 -393
  57. package/internal/message-sources.js +14 -0
  58. package/internal/module-compilation.js +7 -5
  59. package/internal/module-transform-contract.js +32 -2
  60. package/internal/record-utils.js +24 -15
  61. package/internal/repl-memory-projection.js +10 -0
  62. package/internal/repl-scope-normalizer.js +72 -35
  63. package/internal/repl-value-observer.js +145 -46
  64. package/internal/runtime-config.js +62 -2
  65. package/internal/runtime-intrinsics.js +104 -0
  66. package/internal/runtime-messages.js +6 -4
  67. package/internal/session-cell-executor.js +26 -2
  68. package/internal/session-journal-recovery.js +267 -67
  69. package/internal/session-journal-schema.js +30 -13
  70. package/internal/session-journal.js +485 -44
  71. package/internal/session-log-view.js +5 -4
  72. package/internal/session-runtime.js +46 -21
  73. package/internal/session-state.js +7 -29
  74. package/internal/settings-compat.js +66 -1
  75. package/internal/source-position-map.js +38 -0
  76. package/internal/stateful-root-compiler.js +3 -1
  77. package/internal/typescript-transform.js +4 -2
  78. package/internal/user-binding-console-worker.js +115 -41
  79. package/internal/user-binding-draft-projection.js +3 -2
  80. package/internal/user-bindings-owner.js +2 -1
  81. package/internal/user-bindings.js +16 -3
  82. package/internal/validated-parse-repair.js +6 -2
  83. package/internal/value-wire.js +189 -94
  84. package/internal/worker-client.js +99 -8
  85. package/internal/worker-cwd-virtualization.js +82 -54
  86. package/internal/worker-environment.js +20 -0
  87. package/internal/worker-output-capture.js +187 -0
  88. package/internal/worker-output-fence.js +26 -0
  89. package/internal/worker-realm-surfaces.js +197 -0
  90. package/internal/worker-repl-realm.js +140 -0
  91. package/package.json +37 -4
  92. package/src/client-activity.js +12 -2
  93. package/src/client-authoring-view.js +121 -62
  94. package/src/client-console.js +4 -2
  95. package/src/client-copy.js +4 -2
  96. package/src/client-feature-gates.js +7 -9
  97. package/src/client-host-compat.js +104 -27
  98. package/src/client-repl-view.js +3 -1
  99. package/src/client-styles.js +12 -1
  100. package/src/client-tool-view.js +3 -1
  101. package/src/client-transport.js +2 -2
  102. package/src/client-workbench.js +4 -3
  103. package/src/client.js +56 -17
package/docs/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Getting Started
4
4
 
5
- - [Installation](installation.md): npm, Git, source, tarball, development snapshot, and Desktop installation.
5
+ - [Installation](installation.md): npm, Git, source, tarball, development snapshot, and Desktop installation, plus upgrades, troubleshooting, and Session format migration.
6
6
  - [Global binding guide](user-bindings.en.md) ([中文](user-bindings.md)): author, review, save, configure, and test reusable helpers.
7
7
  - [Runtime Reference](runtime-reference.md): cell behavior, capability discovery, configuration, diagnostics, and limits.
8
8
  - [Evaluation](evaluation.md): paired ordinary-task protocol, metrics, configuration, and limitations.
@@ -17,11 +17,14 @@
17
17
  - [Global User Bindings](adr/0023-global-user-bindings.md): persistent helper ownership, model projection, runtime activation, recovery, and Agent-assisted authoring.
18
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
19
  - [Logical Binding Identities](adr/0025-use-versioned-logical-binding-identities.md): stateful declarations, scope, candidate publication and language generations.
20
+ - [Stateful Binding Updates](stateful-binding-updates-proposal.md): target stateful-computation semantics and their acceptance boundaries.
20
21
  - [Architecture Decisions](adr/): stable design constraints and their consequences.
21
22
 
22
23
  ## Maintenance
23
24
 
24
25
  - [Deterministic Verification](verification.md): complete checks, backend test concurrency, coverage, and focused diagnostics.
26
+ - [Incremental Review Verdict](adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md): predeclared parallel lanes, dependency-scoped invalidation, and the composite commit verdict.
27
+ - [Focused Verification](verification-optimization-work.md): bounded coverage diagnostics and their relationship to the final verification gate.
25
28
  - [Semantic Validation](semantic-validation.md): pinned Test262 cases, dialect contracts, native differential matrices and their limits.
26
29
  - [Publishing](publishing.md): release checks, package contents, permissions, and platform validation.
27
30
  - [Client UI](client-ui.md): current UI boundary and reevaluation criteria.
@@ -23,9 +23,10 @@ edit_run_code({
23
23
 
24
24
  PTC mode requests using the code-only direct-tool projection expose `[run_code, edit_run_code]` in
25
25
  that order. The first conclusive prompt assembly creates one per-agent composition owner before any
26
- plugin-owned presentation effect changes the nearest DSH scope. A non-empty `tools:code-only`
27
- section proves `code`, an empty section proves `both`, and only a missing owner signal permits a
28
- tool-shape inference. For a code composition, the same owner
26
+ plugin-owned presentation effect changes the nearest DSH scope. A non-empty `tools:ptc-only`
27
+ section proves `ptc`, an empty section proves `both`, and the preceding generation's
28
+ `tools:code-only` alias proves the same composition; the current section wins when both appear, and
29
+ only a missing owner signal permits a tool-shape inference. For a code composition, the same owner
29
30
  registers `edit_run_code` through `agent.ctx.tools.register()` and uses the same scope's
30
31
  `tools.presentAs('both')` to admit both direct calls. It retains both exact disposers and releases
31
32
  registration and presentation together with the owning session, agent, or plugin. Native-mode and unrelated agent
@@ -105,10 +106,10 @@ would repeat unrelated policy context. Rewrite feedback and unrelated recovery t
105
106
  own independently justified lifecycles.
106
107
 
107
108
  A live `PTC-C001` at the exact source EOF may carry a validated one-call repair. The analyzer tries
108
- only the three single-token suffixes `}`, `)`, and `]` against the same binding catalog, reserved
109
- bindings, redeclaration mode, rewrite policy, and import state as the rejected cell. Exactly one
110
- candidate must complete preparation without a binding collision, and the existing exact editor
111
- must be able to express it from a bounded unique source suffix. The rejected call must also have a
109
+ only the 12 suffixes of one or two closing tokens drawn from `}`, `)`, and `]` against the same
110
+ binding catalog, reserved bindings, redeclaration mode, rewrite policy, and import state as the
111
+ rejected cell. Exactly one candidate across both lengths must complete preparation without a binding
112
+ collision, and the existing exact editor must be able to express it from a bounded unique source suffix. The rejected call must also have a
112
113
  persistent event sequence. The diagnostic then renders those already-validated
113
114
  `edit_run_code({ edits: [...], expected_target_call_seq })` arguments on one help line. At dispatch,
114
115
  the precondition binds the proof to that rejected cell even if another matching source has become
@@ -6,11 +6,11 @@ PTC Plus needs a tracked instruction surface for product boundaries, source owne
6
6
 
7
7
  ## Decision
8
8
 
9
- `AGENTS.md` contains only obligations whose subject is PTC Plus: DSH authority, runtime and journal invariants, public source ownership, the checkout-local review ledger, deterministic verification, documentation parity, generated-material exclusions, and delivery safety. It links the canonical product and architecture documents rather than duplicating their detailed behavior.
9
+ `AGENTS.md` contains only obligations whose subject is PTC Plus: DSH authority, runtime and journal invariants, public source ownership, checkout-local review state, deterministic verification, documentation parity, generated-material exclusions, and delivery safety. It links the canonical product and architecture documents rather than duplicating their detailed behavior.
10
10
 
11
11
  Reusable maintenance methods remain outside tracked project sources. Local editor state and branch topology also remain checkout-owned. They may guide an individual maintainer, but project code, tests, hooks, and acceptance do not require their names, installation, or presence.
12
12
 
13
- The tracked ledger template and lifecycle script remain because they enforce a repository-specific commit invariant: unresolved findings cannot be committed, and a verified source tree must match the prospective Git tree. The tracked hook is limited to that invariant and is installed explicitly.
13
+ The tracked findings-ledger and review-plan templates and their lifecycle script remain because they enforce repository-specific commit invariants: unresolved findings cannot be committed, changed paths need declared semantic coverage, lane evidence follows dependency-scoped invalidation, and a verified source tree must match the prospective Git tree. The tracked hook is limited to those invariants and is installed explicitly.
14
14
 
15
15
  ## Alternatives considered
16
16
 
@@ -7,6 +7,13 @@ The persistent REPL contract must stay short enough for every request, while som
7
7
  ## Decision
8
8
 
9
9
  PTC-owned dynamic information uses independently sourced, accepted DSH messages.
10
+ All newly emitted PTC messages, including authoring instructions and binding-action
11
+ receipts, use `source.kind: 'plugin:ptc-plus'`, the producer identity assigned by
12
+ DSH's official source migration. They never emit the retired `kind: 'plugin'`
13
+ wrapper. Readers retain that historical wrapper and recognize current Host
14
+ `runtime-context` sources as well as historical system-prompt sources. Source
15
+ admission is tested through the official persistence codec; an in-memory Session
16
+ alone does not establish that a message can be saved or resumed.
10
17
  Unproved rewrite completion and Cordis recovery form a bounded `ptc-plus`
11
18
  `snapshot` with named sections. Configured Global User Binding documentation uses
12
19
  DSH's existing `catalog` form, independently of transient recovery state. A recovery tip is a `ptc-plus` `notice` whose
@@ -6,11 +6,11 @@ An ignored root `REVIEW_FINDINGS.md` prevents unresolved review findings from be
6
6
 
7
7
  ## Decision
8
8
 
9
- `.agents/templates/REVIEW_FINDINGS.md` is the tracked schema owner for local review ledgers. Schema `dsh-review-findings/v3` separates each finding's stable required outcome, current implementation plan, accumulated resolution evidence, and optional accepted-disposition owner. A finding can be captured before diagnosis produces a plan; once a concrete correction is selected, the plan is recorded before implementation and kept synchronized when evidence changes the diagnosis, ownership, affected artifacts, or verification path. `resolutionEvidence` records completed facts rather than a chronological work transcript. A finding marked `resolved` retains its implemented plan. A finding marked `accepted` names a tracked document or HTTPS issue in `dispositionRef`; the local ledger cannot be the only copy of an intentionally retained limitation.
9
+ `.agents/templates/REVIEW_FINDINGS.md` is the tracked schema owner for local review ledgers. Schema `dsh-review-findings/v3` separates each finding's stable required outcome, current implementation plan, accumulated resolution evidence, and optional accepted-disposition owner. A finding can be captured before diagnosis produces a plan; once a concrete correction is selected, the plan is recorded before implementation and kept synchronized when evidence changes the diagnosis, ownership, affected artifacts, or verification path. `resolutionEvidence` records completed facts rather than a chronological work transcript. A finding marked `resolved` retains its implemented plan. A finding marked `accepted` names a tracked document or HTTPS issue in `dispositionRef`; a local reference must be one exact tracked file that remains present in the source candidate, not a directory, pathspec match, or index entry deleted from the checkout. The local ledger cannot be the only copy of an intentionally retained limitation. The separate `.agents/templates/REVIEW_PLAN.json` owns the independent-review partition described by ADR 0026; a review plan routes verification work and invalidation, while the findings ledger owns discovered defects and their resolution.
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, 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.
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 the composite independent-review plan, lane verdicts, and final verdict defined by ADR 0026. Staging the complete verified tree permits repeated commit attempts; partial staging, additional staged content, mode-only changes, later checkout changes, uncovered paths, or invalidated lane dependencies require reconciliation before 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
 
@@ -40,4 +40,4 @@ Hook installation is explicit. `npm run hooks:install` selects the tracked hook
40
40
 
41
41
  ## Consequences
42
42
 
43
- Review findings have an explicit `reported -> authorized capture -> planned -> implemented and verified -> proof and archive -> matching commit -> proof retirement` lifecycle while retaining `open` and `resolved` as file-level states. An open ledger uses `verify` for deterministic evidence collection and fails `check` before its full gate runs; it also blocks commits. A resolved ledger remains active until verification succeeds against an unchanged source fingerprint, and commit readiness additionally requires the prospective index to match that fingerprint. The archive is intentionally local, while accepted limitations and durable architecture remain in tracked owners. Hook installation is an explicit checkout setup decision rather than a dependency-install side effect.
43
+ Review findings have an explicit `reported -> authorized capture -> planned -> implemented and verified -> proof and archive -> matching commit -> proof retirement` lifecycle while retaining `open` and `resolved` as file-level states. An open ledger uses `verify` for deterministic evidence collection and fails `check` before its full gate runs; it also blocks commits. A resolved ledger remains active until verification succeeds against an unchanged source fingerprint, and commit readiness additionally requires the prospective index to match that fingerprint. Independent review lanes have their own `plan -> parallel review -> dependency-scoped retry -> deterministic proof -> composite verdict` lifecycle and do not replace finding disposition. Both local records stay outside source history; accepted limitations and durable architecture remain in tracked owners. Hook installation is an explicit checkout setup decision rather than a dependency-install side effect.
@@ -8,17 +8,17 @@ Accepted
8
8
 
9
9
  ## Context
10
10
 
11
- PTC Plus 0.1.0 deliberately had no Client UI. The runtime surface was the DSH PTC mode `run_code`/`edit_run_code` transport, and adding a settings bundle was judged not to improve the core REPL path. The plugin also lacked a user-facing way to disable its runtime without removing the Cordis entry, and enabling/disabling state was invisible outside the session log. PTC Plus requires a plugin settings UI containing every Host Config field, a kill switch, and an explicit enabled marker. DSH's public settings service registers a namespace, the browser half contributes a card through `settings.plugin.item`, and the client receives the scoped settings service through `settingsScope`.
11
+ PTC Plus 0.1.0 deliberately had no Client UI. The runtime surface was the DSH PTC mode `run_code`/`edit_run_code` transport, and adding a settings bundle was judged not to improve the core REPL path. The plugin also lacked a user-facing way to disable its runtime without removing the Cordis entry, and enabling/disabling state was invisible outside the session log. PTC Plus requires a plugin settings UI containing every Host Config field, a kill switch, and an explicit enabled marker. DSH's public settings service registers a namespace; the browser half contributes a card through the generation's settings seat, and the client reads the installed generation's settings transport (`configForms` on the current alpha, `settingsScope` on the preceding RC).
12
12
 
13
13
  ## Decision
14
14
 
15
15
  PTC Plus registers one DSH settings namespace `ptc-plus` with the same field list, defaults and validation as the Host Config schema. The field definitions live once in `internal/config-spec.js`; `index.js` builds the Cordis Config schema from it, and the esbuild client bundle imports the same module so the UI does not copy defaults or validation.
16
16
 
17
- The settings card's seat is generation-owned. The preceding DSH declares `settings.plugin.item` (keyed, root) in its Settings panel and renders one card per served namespace; the current one renders a bundle's own configuration on its side-bar Plugins page through `plugins.row.config` (keyed, root) as `<bundle package name>#<row id>` and reserves `plugins.item` for the host-plane pages DSH itself ships. `src/client-host-compat.js` owns both seats and publishes the card to both, because `ctx.slots.inject` waits while a key is undeclared and neither generation declares the other's key; the declaring generation therefore decides which single seat renders the card. The composer shortcut opens an application-modal rendering of the same complete form, so direct access does not depend on a host page's component-local navigation state; its hover hint still names the native seat available on that generation.
17
+ The settings card belongs to plugin configuration. Current DSH renders a bundle's own configuration on the sidebar Plugins → Installed page through `plugins.row.config` (keyed, root) as `<bundle package name>#<row id>` and reserves `plugins.item` for the host-plane pages DSH itself ships. Preceding Hosts use `settings.plugin.item` (keyed, root) in the Settings panel, keyed by the served namespace. `src/client-host-compat.js` publishes to these plugin configuration seats through `ctx.slots.inject`, which waits until the owning page declares its slot. General settings may coexist with plugin configuration and is not a seat for this card. The composer shortcut opens an application-modal rendering of the same complete form, so direct access does not depend on a host page's component-local navigation state; its hover hint names the observed native plugin configuration seat. The package's top-level `icon` field points to a packaged SVG; DSH owns loading and displaying it on the installed bundle and row pages.
18
18
 
19
19
  The settings card places the plugin switch first, then groups controls by purpose: tool call tolerance, REPL syntax, state and recovery, tool extensions, interface display, and resource limits. Recovery tips and their thresholds stay together, and global binding management appears directly below its enable switch. `CONFIG_GROUPS` owns this presentation order independently of Host schema field order and defaults. `autoDescribeRunCode` defaults to true and controls only a request-bound local execution policy. When enabled, a call that omits the outer `description` uses derived arguments for local DSH validation, and the fallback summary enters presentation metadata only; when disabled, DSH validates the original arguments. Both states produce byte-stable model-visible tool schemas, order, and system sections with the required `description` declaration. Original call arguments, explicit summaries, cell source, and nested native-tool arguments remain unchanged.
20
20
 
21
- The configurable set is the Host runtime configuration plus `enabled: boolean` (default true). `enabled` is the kill switch: when false the Host keeps the settings namespace, client card, and passive message cleanup defined in [ADR 0010](0010-session-log-derived-recovery-tips.md). The next permitted accepted step may clear earlier PTC declarations. It does not install the runtime bridge, edit transport, direct-surface owner, system prompt section, tool registrations, or execution hooks, and does not read binding storage. When true the same runtime as pre-settings PTC Plus is installed. Every field is live when its owner can reconcile it: the Host observes the settings scope and installs, uninstalls, or reconfigures owners without replacing existing session-bound bindings. Node fixes a worker's V8 `maxOldGenerationSizeMb` limit at construction, so changing that field while a session worker is active is rejected and the settings provider is restored to the previous value; other reconfiguration failures use the same compensation path. The TypeScript language check occurs at activation, allowing disabled settings to load on a host using another code runtime while rejecting and rolling back an enable attempt. If the settings service is absent, the Host falls back to composition config and enables the runtime.
21
+ The configurable set is the Host runtime configuration plus `enabled: boolean` (default true). `enabled` is the kill switch: when false the Host keeps the settings namespace, client card, and passive message cleanup defined in [ADR 0010](0010-session-log-derived-recovery-tips.md). The next permitted accepted step may clear earlier PTC declarations. It does not install the runtime bridge, edit transport, direct-surface owner, system prompt section, tool registrations, or execution hooks, and does not read binding storage. When true the same runtime as pre-settings PTC Plus is installed. On the generations that expose a section installer, every field is live when its owner can reconcile it: the Host observes the settings scope and installs, uninstalls, or reconfigures owners without replacing existing session-bound bindings. The newest settings generation exposes no section installer and serves only fields marked volatile in the plugin's exported `Config`; the Host provides the form and commits volatile-only changes into the live references, notifying the owning fiber through the public `loader/volatile-update` event. The plugin subscribes and reconciles through its existing update path instead of running a per-field settings watch. Node fixes a worker's V8 `maxOldGenerationSizeMb` limit at construction, so changing that field while a session worker is active is rejected and the settings provider is restored to the previous value; other reconfiguration failures use the same compensation path. The TypeScript language check occurs at activation, allowing disabled settings to load on a host using another code runtime while rejecting and rolling back an enable attempt. If the settings service is absent, the Host falls back to composition config and enables the runtime.
22
22
 
23
23
  Every settings-card and PTC Plus tool-row string is registered into the DSH client locale namespace `settings.ptcPlus` and follows the active DSH client locale. Field copy exists in both locales from the single `internal/config-spec.js` source (`label`/`labelEn`, `description`/`descriptionEn`); display chrome copy is owned by the Client half. The stable REPL guidance remains plugin-owned protocol text without UI branding. The transport names remain `run_code`/`edit_run_code`; DSH owns their identity.
24
24
 
@@ -24,6 +24,8 @@ Cordis tools remain native program bindings under `tools.*`. The PTC code-only d
24
24
 
25
25
  Cordis definitions and Runs are process-local, while PTC journals replay every settled program binding as a recorded value without redispatch. On the first prompt for an agent or a new Cordis enable generation, PTC Plus derives whether normalized journals contain a Cordis transcript. If they do, it emits the fixed `tools:ptc-plus-cordis-recovery` runtime context: recorded values remain journal data, but the model must perform a live read-only Cordis Inspect before relying on prior IDs, state, approvals, or capability observations. The context remains until a newly settled successful `cordis_inspect*` call appears in the session log. It neither asserts that live state was lost nor reruns a mutating call.
26
26
 
27
+ Companion Skill resolution is capability-based. The generations that discover presets from their composition directories publish an absolute composition path for the shipped `cordis` preset, and PTC Plus reads the sibling `skills` root. A generation that declares presets without publishing any composition path publishes no companion Skill root through `agentPresets` at all: PTC Plus reports that missing publication as an unsupported surface, naming the surface and its consequence rather than a shape failure of a healthy host, and keeps the existing rollback or single-warning withdrawal instead of assuming a directory. An unusable preset (`broken`) is reported as unavailable before any path shape is considered.
28
+
27
29
  ## Alternatives Considered
28
30
 
29
31
  1. Add the Cordis row to the PTC preset. Rejected: PTC Plus is installed as a host plugin and does not own or fork DSH's shipped preset files; a plugin setting keeps the optional mount within the plugin's ownership boundary.
@@ -28,12 +28,23 @@ artifact rewrite API when one exists. Until then, PTC Plus must not rewrite
28
28
  files obtained from private storage paths or race the persistence provider's
29
29
  append/flush queue. Legacy `ptc-plus/recovery-boundary` artifacts therefore
30
30
  remain an explicit, startup-before-restore migration concern rather than a
31
- runtime event handler concern.
31
+ runtime event handler concern. The dedicated retired-event converter accepts
32
+ only a Session format 0 artifact with a contiguous zero-based source identity graph, removes the retired events
33
+ and rewrites every supported Host and PTC sequence relation through one closed
34
+ old-to-new map. Before writing, it validates current-surface replacement and
35
+ compaction ranges, provenance, command and title sources, and complete
36
+ recovery-boundary application; invalid or unknown relations fail closed. If a
37
+ header records a seeded session, the converter also maps its exact inherited-
38
+ event cut across removed boundary events so child-owned events cannot become
39
+ inherited.
32
40
 
33
41
  Host format upgrades are also explicit pre-restore work. The migration CLI may
34
42
  resolve the selected Host's public Session format catalog and use its strict
35
- conversion and current validation. PTC result metadata remains opaque to that
36
- catalog. The CLI therefore proves an ordered one-to-one relation between the
43
+ conversion and current validation. When the selected catalog requires
44
+ parent-specific child evidence, the caller supplies the complete direct-child
45
+ facts or explicitly declares that the artifact has no children; the CLI does
46
+ not infer an empty child set. PTC result metadata remains opaque to that catalog.
47
+ The CLI therefore proves an ordered one-to-one relation between the
37
48
  unchanged tool records, remaps only PTC-owned sequence references, and validates
38
49
  the resulting timeline. Original call arguments and recorded effects are never
39
50
  rewritten or executed. Ambiguous records, invalid PTC evidence and mixed retired
@@ -6,15 +6,15 @@ Repeated project helpers are useful across sessions, but ordinary REPL bindings
6
6
 
7
7
  ## Decision
8
8
 
9
- Global User Bindings is an optional PTC Plus capability controlled by `userBindingsEnabled`, which defaults to `false`. Disabled mode does not read storage, inject values or new declarations, register management RPC or commands, or render management UI. The next permitted accepted step can withdraw a previously delivered declaration through the PTC binding catalog contract in [ADR 0010](0010-session-log-derived-recovery-tips.md). Enabling the capability does not change DSH authority, approval, scheduling, cancellation, sandbox, or the code-only direct-tool projection.
9
+ Global User Bindings is a PTC Plus capability controlled by `userBindingsEnabled`, which defaults to `true` so its management and authoring entry points are available on installation. An explicit `false` remains authoritative, including across upgrades; omission uses the current default. This feature switch does not change any saved entry's enabled state, create helpers, or save Agent drafts automatically. Disabled mode does not read storage, inject values or new declarations, register management RPC or commands, or render management UI. The next permitted accepted step can withdraw a previously delivered declaration through the PTC binding catalog contract in [ADR 0010](0010-session-log-derived-recovery-tips.md). Enabling the capability does not change DSH authority, approval, scheduling, cancellation, sandbox, or the code-only direct-tool projection.
10
10
 
11
11
  Each entry is a TypeScript module with named value exports, a stable ID, display/call name, `namespace` or `top-level` scope, selected symbols, purpose, enabled state, and optional `modelContext`. Omitted symbol selection derives every named value export; an explicit selection limits the exposed API. One strict normalizer derives body-free declarations, binding kinds and durability from source, fingerprints the complete stored entry, and rejects any supplied derivative that disagrees. Activated entries are ordinary writable REPL bindings; a model redeclaration follows the configured binding policy and shadows the default only for that session.
12
12
 
13
13
  New-generation export descriptors consume the shared TypeScript value normalizer used by module compilation, including enum and namespace values and erased type-only declarations. Original type-name evidence remains available for bounded signature projection. Validation derives this evidence without executing module source; historical snapshot transforms retain their recorded descriptor rules.
14
14
 
15
- `modelContext` contains `includeDeclaration` (default `true`) and `instructions` (default empty, at most 4096 UTF-16 code units). The checkbox controls injection of the existing source-derived interface; a nonempty prompt is injected independently. There is no separately authored interface. Unchecking the declaration and clearing the prompt omits both without disabling execution. Source-derived declarations remain canonical for conflict checks and recovery. The enabled set's selected declarations and prompts have an aggregate 16384-code-unit budget in addition to the existing source-derived declaration budget. The shared Client-safe metadata normalizer preserves these fields in accepted draft history.
15
+ `modelContext` contains `includeDeclaration` (default `true`) and `instructions` (default empty, at most 4096 UTF-16 code units). The checkbox controls injection of the existing source-derived interface; a nonempty prompt is injected independently. There is no separately authored interface. The projection preserves unshadowed environment type names and emits the referenced closure of local interfaces, type aliases, enums and classes in an entry-private declaration namespace. Public class instance fields, constructor parameter properties, methods and accessors are part of the projected class shape. Imported aliases that cannot produce a self-contained declaration are rejected during normalization; qualified import types retain their module reference. Unchecking the declaration and clearing the prompt omits both without disabling execution. Source-derived declarations remain canonical for conflict checks and recovery. The enabled set's selected declarations and prompts have an aggregate 16384-code-unit budget in addition to the existing source-derived declaration budget. The shared Client-safe metadata normalizer preserves these fields in accepted draft history.
16
16
 
17
- Omitting `modelContext` preserves the existing entry serialization and fingerprint; stored documents need no migration. Historical snapshot recovery additionally requires the transform evidence described below. When present, normalized metadata participates in the existing fingerprint. Previously saved `enabled` and `declaration` fields retain their normalized representation for fingerprint verification, including the old declaration string limit of 8192 code units, but custom declarations no longer enter model or UI presentation. A legacy disabled prompt maps to `includeDeclaration: false` and empty instructions; otherwise its prompt is retained and the source-derived interface is included. An explicit `includeDeclaration` takes precedence. Editing and saving through the workbench writes current fields. Existing entries without metadata gain first-turn discovery through the default declaration setting.
17
+ Omitting `modelContext` preserves the existing entry serialization and fingerprint; stored documents need no migration. Historical snapshot recovery additionally requires the transform evidence described below. When present, normalized metadata participates in the existing fingerprint. Previously saved `enabled` and `declaration` fields retain their normalized representation for fingerprint verification, including the historical declaration string limit of 8192 code units; custom declarations are excluded from model and UI presentation. A legacy disabled prompt maps to `includeDeclaration: false` and empty instructions; otherwise its prompt is retained and the source-derived interface is included. An explicit `includeDeclaration` takes precedence. Editing and saving through the workbench writes current fields. Existing entries without metadata gain first-turn discovery through the default declaration setting.
18
18
 
19
19
  For new cells, the complete snapshot fingerprint is an integrity check, not a module reuse key. For the same active entry ID, the worker reuses the module when its exact source, scope, namespace call name, and ordered selected exports match. Changes to model context, purpose, or a top-level entry's display name preserve module state and do not repeat initialization. Execution-input changes, removal, and disablement retain their activation and shadow rules. Each cell still records the complete current snapshot and fingerprint.
20
20
 
@@ -30,7 +30,7 @@ The workbench keeps a save revision with the loaded source. Catalog-only changes
30
30
 
31
31
  Source is the only implementation authority. Both candidate execution and session activation resolve relative imports from the directory containing `bindings.json`; a session cwd therefore cannot change a persistent helper's dependency graph. The parser accepts named value exports and rejects default exports, re-exports, reserved bindings, invalid selected symbols, and conflicting enabled call names. Model-visible declarations retain useful annotations and bounded inferred shapes but omit implementation bodies and private helpers.
32
32
 
33
- `internal/stateful-module-compiler.js` owns binding-module compilation, shared by validation, live/cold activation, candidate execution and the draft console. Its maintained TypeScript transform owner remains `internal/typescript-transform.js`. Snapshot version 2 records either the historical `amaro@1.1.11` transform or `stateful-module-v1+amaro@1.1.11`, and includes that exact identity in the snapshot fingerprint. The latter applies the shared logical scope rules before TypeScript transformation; the former retains its historical lowering. Entry fingerprints and stored source remain source-owned. Unsupported identities cannot be substituted with the current compiler, and a transform change participates in runtime reuse identity. The complete language and journal-generation decision is [ADR 0025](0025-use-versioned-logical-binding-identities.md).
33
+ `internal/stateful-module-compiler.js` owns binding-module compilation, shared by validation, live/cold activation, candidate execution and the draft console. Its maintained TypeScript transform owner remains `internal/typescript-transform.js`. Snapshot version 2 records one of `amaro@1.1.11`, `stateful-module-v1+amaro@1.1.11`, or `stateful-module-v2+amaro@1.1.11` and includes that exact identity in the snapshot fingerprint. Both stateful transforms apply shared logical scope rules before TypeScript transformation; v2 additionally resolves program namespaces through compiled logical roots. The legacy transform retains its historical lowering, and v1 retains its worker-global program bridge. Entry fingerprints and stored source remain source-owned. Unsupported identities cannot be substituted with the current compiler, and a transform change participates in runtime reuse identity. The complete language and journal-generation decision is [ADR 0025](0025-use-versioned-logical-binding-identities.md).
34
34
 
35
35
  Version 1 snapshots did not record the native compiler. A matching source,
36
36
  declaration, durability classification or cell completion does not prove matching
@@ -53,13 +53,13 @@ Configured prompts and interfaces never enter `PromptAssembly.sections` or its v
53
53
 
54
54
  Configured documentation is the only new model-visible source of binding prompts and interfaces. Successful activation, session-local shadows and worker reconstruction do not append an activation announcement or resend an unchanged configuration. Execution results and diagnostics own actual execution facts; an availability check observes a known name without external effects. A separate active-declaration channel would duplicate the configured API and make every first successful cell repeat the whole binding context. The reader still accepts historical binding configuration and `tools:ptc-plus-user-bindings` sections: the next permitted accepted recovery snapshot omits them and explicitly supersedes the earlier claims once, including when bindings are disabled. Current documentation is supplied independently as a catalog. Existing messages and journals are not rewritten. Binding contents do not modify `tools:sdk`, direct-tool schemas, or tool order. Ordinary requests receive neither module source nor management operations. Configured API documentation remains a statement of defaults and does not preserve session-local state across compaction or recovery.
55
55
 
56
- The worker activates entries before the cell and reports entry-level failures without blocking independent code. A request-owned program namespace or error class takes precedence over a same-name user entry, which is excluded from that request's activated snapshot. Every current request namespace is also exposed to binding modules through a stable worker-global bridge, but each call resolves the AsyncLocalStorage execution lease that reached it; a continuation from a completed cell cannot borrow a later cell's capabilities. A request namespace that collides with any existing worker global fails before bridge installation because replacing a Node intrinsic cannot preserve both environments. BindingCatalog records `user-global` provenance and attaches current entries per call identifier: a session-local shadow suppresses only that name from subsequent global activation while the entry's remaining names keep activating, so one local override neither erases a sibling helper nor resets the module state that provides it. Journals migrated from versions 1 through 7 keep the historical whole-entry suppression, and `userBindingsShadowPolicy` fixes which rule each cell replays under. Namespace members and top-level exports read their live module values until assignment or a permitted redeclaration creates that shadow. Each settled cell persists the exact successfully activated snapshot in private result metadata, while journal versions 5 and later record its fingerprint or an explicit `null` when no snapshot exists. Per-name cells additionally record the `provider`/`local`/`absent`/`unknown` attachment facts the worker reported at settlement, validated against that snapshot. Replay re-activates the recorded snapshot and re-executes the recorded source, then requires the facts reported during that replay to equal the recorded ones: the record verifies replay instead of installing names, and a divergence is rejected rather than resolved from the current store. If a failed initializer issued a program call, the cell becomes volatile because that snapshot cannot supply its replay source. Cold recovery validates the journal-to-snapshot relation and executes recorded source rather than consulting the current store; missing, malformed, or source-inconsistent evidence contracts the recoverable frontier under the existing fail-closed journal rules.
56
+ The worker activates entries before the cell and reports entry-level failures without blocking independent code. A request-owned program namespace or error class takes precedence over a same-name user entry, which is excluded from that request's activated snapshot. Current v2 binding modules resolve request namespaces through their compiled logical root; each cell receives a namespace view bound to that cell's lease. Historical v1 and legacy modules use their recorded worker-global bridge, whose calls resolve the AsyncLocalStorage execution lease that reached them. Neither path lets a continuation from a completed cell borrow a later cell's capabilities. A historical bridge that collides with an existing worker global fails before installation because replacing a Node intrinsic cannot preserve both environments. BindingCatalog records `user-global` provenance and attaches current entries per call identifier: a session-local shadow suppresses only that name from subsequent global activation while the entry's remaining names keep activating, so one local override neither erases a sibling helper nor resets the module state that provides it. Journals migrated from versions 1 through 7 keep the historical whole-entry suppression, and `userBindingsShadowPolicy` fixes which rule each cell replays under. Namespace members and top-level exports read their live module values until assignment or a permitted redeclaration creates that shadow. Each settled cell persists the exact successfully activated snapshot in private result metadata, while journal versions 5 and later record its fingerprint or an explicit `null` when no snapshot exists. Per-name cells additionally record the `provider`/`local`/`absent`/`unknown` attachment facts the worker reported at settlement, validated against that snapshot. Replay re-activates the recorded snapshot and re-executes the recorded source, then requires the facts reported during that replay to equal the recorded ones: the record verifies replay instead of installing names, and a divergence is rejected rather than resolved from the current store. If a failed initializer issued a program call, the cell becomes volatile because that snapshot cannot supply its replay source. Cold recovery validates the journal-to-snapshot relation and executes recorded source rather than consulting the current store; missing, malformed, or source-inconsistent evidence contracts the recoverable frontier under the existing fail-closed journal rules.
57
57
 
58
- An exported function may escape into an ordinary session binding before its global entry is updated, disabled, or removed. Reachability cannot be proved inside the worker, so every successfully exposed binding module retains its relative-import parent mapping and dynamic program-namespace bridge until that worker ends. Failed modules that expose no value release their temporary mapping. When no user binding has ever been exposed, disabled or empty activation installs no bridge; if every attempted activation fails, any bridge installed for that attempt is removed before the cell executes.
58
+ An exported function may escape into an ordinary session binding before its global entry is updated, disabled, or removed. Reachability cannot be proved inside the worker, so every successfully exposed binding module retains its relative-import parent mapping until that worker ends; historical modules also retain their dynamic program-namespace bridge. Failed modules that expose no value release their temporary mapping. When no historical binding has ever been exposed, disabled or empty activation installs no bridge; if every attempted historical activation fails, any bridge installed for that attempt is removed before the cell executes.
59
59
 
60
60
  Installed provider setters can likewise remain callable after their entries disappear. BindingCatalog retains their name eligibility along the accepted execution ancestry, separately from current entries and the visible binding inventory. A later setter write may therefore establish a local value without reactivating its provider. Provider facts still require the current activated snapshot and must not conflict with request-owned names; failed activation or preflight does not establish historical eligibility. Worker reset clears this evidence, and cold replay rebuilds it only from the retained verified ancestry, including historical whole-entry cells. Recovery contraction cannot carry eligibility across a discarded boundary.
61
61
 
62
- The workbench code console runs the current unsaved source draft in a separate bounded Node REPL worker and never accesses the Agent session kernel or its journal. Named exports are available directly; commands accept TypeScript and top-level await, return inspected expression values and logs, and preserve declarations across executions. Ordinary syntax and runtime errors preserve the environment and prior partial effects. The existing one-shot candidate RPC remains compatible. Both paths retain DSH process authority and can produce irreversible Node/OS effects before failure or cancellation; worker state isolation is not a security sandbox.
62
+ The workbench code console runs the current unsaved source draft in a separate bounded Node REPL worker and never accesses the Agent session kernel or its journal. Its commands and binding modules share that worker's native Node realm, matching the session kernel's intrinsic and `globalThis` contract without sharing session state. Named exports are available directly; commands accept TypeScript and top-level await, return inspected expression values and logs, and preserve declarations across executions. Ordinary syntax and runtime errors preserve the environment and prior partial effects. The existing one-shot candidate RPC remains compatible. Both paths retain DSH process authority and can produce irreversible Node/OS effects before failure or cancellation; worker state isolation is not a security sandbox.
63
63
 
64
64
  An authenticated user request lazily creates an opaque Host-generated environment handle. Each workbench owns its handle, one command at a time, with at most four environments per owner. Worker wall, output and memory limits use the existing configuration. Source and command inputs are each limited to 1 MiB. Ten minutes without code execution releases the worker without erasing displayed history. Source replacement at the next execution, switching entries, saving changed source, leaving the workbench, explicit reset, cancellation, timeout, output failure, worker failure, disablement or owner disposal also releases it. No action replays earlier commands automatically. Folding, ordinary editing and clearing displayed history do not execute code. The user may explicitly start again from the current draft after release.
65
65
 
@@ -36,11 +36,11 @@ New-generation cell returns leave source scopes through a private labelled break
36
36
 
37
37
  ## Language and recovery generations
38
38
 
39
- Journal version 9 requires the closed `languageSemantics` field: `legacy-v1`, `stateful-v1` or `protected-v1`. Versions 1 through 8 migrate to `legacy-v1`, preserving their independently recorded binding, rewrite, module, reuse and shadow policies. Replay selects the recorded compiler; live requests select the current configuration. Frozen `legacy-*` preparation, parser, module rewrite, convenience and catalog owners preserve historical semantics, including bare-declaration clearing and older import closures. A void completion does not justify substituting a newer compiler. This extends [ADR 0014](0014-persist-cell-rewrite-policy.md).
39
+ Journal version 10 requires the closed `languageSemantics` and `moduleTransform` fields. The language field records `legacy-v1`, `stateful-v1` or `protected-v1`; the transform field records the exact parser, compiler and lowering generation, and only compatible pairs are accepted. Versions 1 through 8 migrate to `legacy-v1` with the frozen legacy transform while preserving their independently recorded binding, rewrite, module, reuse and shadow policies. Version 9 keeps its recorded language and maps it to the transform shipped with that journal generation: stateful uses `stateful-module-v1`, protected uses `protected-module-v1`, and legacy uses the legacy transform. Replay consumes that exact transform; live requests record the transform selected by current configuration. Frozen `legacy-*` preparation, parser, module rewrite, convenience and catalog owners preserve historical semantics, including bare-declaration clearing and older import closures. A void completion does not justify substituting a newer compiler. This extends [ADR 0014](0014-persist-cell-rewrite-policy.md).
40
40
 
41
41
  The post-transform native adapter records physical lexical declarations independently of logical declaration kind. The binding catalog preserves those facts across revisions and supplies them to migration, dynamic selection and publication. Only a successful current storage probe proves initialization; static declaration facts cannot establish recoverability. An unrelated same-named global property cannot override proven initialized lexical storage or confer writability on absent or readonly storage.
42
42
 
43
- Binding snapshots likewise distinguish `amaro@1.1.11` from `stateful-module-v1+amaro@1.1.11`. Source metadata and fingerprints remain canonical; an unsupported transform cannot be silently replaced with the current transform. A generation change participates in module reuse identity. Actual worker initialization and source facts advance the catalog; parsing a declaration alone never proves that its value exists. Model-visible provenance, verified journal ancestry and the existing recovery contraction rule still bound every retained identity.
43
+ Binding snapshots distinguish `amaro@1.1.11`, `stateful-module-v1+amaro@1.1.11`, and `stateful-module-v2+amaro@1.1.11`. Source metadata and fingerprints remain canonical; an unsupported transform cannot be silently replaced with the current transform. The v2 generation resolves program namespaces through compiled logical roots, while v1 and legacy snapshots retain their historical worker-global bridge. A generation change participates in module reuse identity. Actual worker initialization and source facts advance the catalog; parsing a declaration alone never proves that its value exists. Model-visible provenance, verified journal ancestry and the existing recovery contraction rule still bound every retained identity.
44
44
 
45
45
  Current protected module graphs use the distinct `protected-module-v1+amaro@1.1.11` compilation identity. They retain native declaration and import protection while sharing callable source facts, dynamic interfaces and module loading with current computations. This live module identity does not add a persisted binding snapshot transform or reinterpret historical modules.
46
46
 
@@ -58,7 +58,7 @@ Eval checks lexical conflicts before initializing its ordered declaration plan.
58
58
 
59
59
  `dynamic-native-runtime.js` owns stable interfaces for exactly six native intrinsics: eval, the four Function constructors, and Function.prototype.toString. Owned entry points prepare these interfaces before source can capture them. `dynamic-native-calls.js` selects the owning realm and generation's interface at source value and invocation boundaries, including property reads, reflected native results and asynchronous resumption. Cells that only save an intrinsic value use the same boundary. Native and opaque consumers of these values therefore use the same interface as compiled calls. Direct eval recognizes the exposed identity but executes the captured original intrinsic with its explicit caller environment. Constructors delegate coercion, validation and newTarget prototype selection to their original native operation before adapting the resulting source. Canonical user functions and module namespaces are never wrapped by this interface. Separately created user realms retain their own intrinsics.
60
60
 
61
- All global and prototype properties retain their original native identities, including Function.prototype.toString. Replacing global eval would invalidate native direct eval in escaped legacy closures; replacing toString would invalidate their saved intrinsic identity observations. Temporary restoration around synchronous calls cannot preserve asynchronous continuations. Kernel ambient getters return the original values while retaining volatile-read accounting. `native-root-compilation.js` adapts legacy cells after frozen declaration lowering; `native-root-dynamic.js` supplies their stable legacy interface and retains helper ancestry through the existing import namespace owner. Legacy dynamic source uses the native REPL environment; new-generation source uses its logical root. Both consume managed module namespaces. Legacy compilation units keep their native declaration behavior, environments and saved interface identities before, during and after new-generation execution, including newly created legacy cells and modules after a mode change. Interface preparation never writes user-visible properties. Module runtime creation shares interfaces, intrinsic identity associations and source facts. Invocation context carries the selected runtime and source provenance through native and asynchronous callbacks; callbacks outside such an invocation use their interface's realm owner. Interfaces remain live while escaped values can use them and end with the owning realm.
61
+ All global and prototype properties retain their original native identities, including Function.prototype.toString. Each session kernel and binding workbench uses its worker's native Node realm for REPL evaluation and Node module execution. Cell code, managed imports, provided require and binding modules therefore share intrinsic identities and `globalThis`; user-created VM contexts and independent runtimes keep their own realms. Replacing global eval would invalidate native direct eval in escaped legacy closures; replacing toString would invalidate their saved intrinsic identity observations. Temporary restoration around synchronous calls cannot preserve asynchronous continuations. Compiler and source analysis record ambient reads for durability without interposing getters on user-visible globals. `native-root-compilation.js` adapts legacy cells after frozen declaration lowering; `native-root-dynamic.js` supplies their stable legacy interface and retains helper ancestry through the existing import namespace owner. Legacy dynamic source uses the native REPL environment; new-generation source uses its logical root. Both consume managed module namespaces. Legacy compilation units keep their native declaration behavior, environments and saved interface identities before, during and after new-generation execution, including newly created legacy cells and modules after a mode change. Interface preparation never writes user-visible properties. Module runtime creation shares interfaces, intrinsic identity associations and source facts. Invocation context carries the selected runtime and source provenance through native and asynchronous callbacks; callbacks outside such an invocation use their interface's realm owner. Interfaces remain live while escaped values can use them and end with the owning realm.
62
62
 
63
63
  For legacy top-level await, `native-await-declarations.js` retains source declarations for Node's persistent root instantiation and function hoisting. Direct eval uses a separate cell activation inside that root and outside nested lexical scopes. Initializer writes retain native ordering, including partial destructuring writes on failure; indirect eval and Function continue to use the native realm root.
64
64
 
@@ -1,21 +1,37 @@
1
- # Persist the delivery verdict against the verified candidate
1
+ # Persist incremental review lanes against the verified candidate
2
2
 
3
3
  ## Problem
4
4
 
5
- A complete-tree independent review returns a sampled conclusion for one tree state. Nothing bound that conclusion to the candidate, so the same source bytes could be reported clean by one review and expose three reproducible defects to the next, and a clean verdict never stopped the following review from starting. The verification proof already bound `npm run check` to `{HEAD, fingerprint}`, but the review stayed a transcript outside the commit gate, and the gate allowed a commit whenever no proof, no ledger or only a historical clean review existed.
5
+ A single complete-tree independent review bound a clean conclusion to one tree, but every correction invalidated the whole conclusion. Earlier parallel reviews remained diagnostic transcripts even when a fix could not affect their owners, inputs, assumptions, or consumers. This forced repeated complete review, discouraged early parallelism, and allowed review boundaries to drift during execution without a machine-visible plan. Retaining every earlier conclusion without dependency information would be unsound for the opposite reason: a change to a shared owner can invalidate consumers whose own files did not change.
6
6
 
7
7
  ## Decision
8
8
 
9
- The delivery gate is a persisted verdict in checkout-local Git metadata (`review-findings/verdict`) holding `{schema, status, head, fingerprint, base, evidence}`. `status` is `clean`; `head` and `fingerprint` are the frozen candidate the independent complete review examined; `base` is the scope base commit and must be an ancestor of `HEAD`; `evidence` names the retained copy of the original review report and its SHA-256. `recordReviewVerdict` is the only writer: it requires both the `HEAD` and the fingerprint captured before the review, refuses a candidate where either changed, refuses any report whose last non-empty line is not `VERDICT: NO FINDINGS`, and copies the report into `review-findings/evidence` before hashing it. A report that is not clean retires the standing proof and verdict instead of leaving an earlier clean verdict in force. `preCommitReviewLedger` is fail-closed and requires a proof for the current `HEAD`, equal source and index fingerprints, and a clean verdict whose head, fingerprint and scope cover that candidate and whose evidence still hashes to the recorded value. An absent ledger, an absent proof or documentation-only work is not an exemption. A proof whose `HEAD` moved is retired together with its verdict, and a verdict that no longer matches the verified candidate is discarded without touching the proof; either case blocks the commit. The recording entry resolves the scope base to a full commit id, binds the current `HEAD`, and refuses a base that is not an ancestor of it, so a stored record cannot name a candidate other than the one under review. The bound values come from the `verified <head> <fingerprint>` line that `npm run check` prints and stores in the proof, and the independent report must stay outside the checkout or be ignored because the fingerprint covers untracked non-ignored paths.
9
+ Independent review starts from a checkout-local `REVIEW_PLAN.json`, created from `.agents/templates/REVIEW_PLAN.json` and recorded under Git metadata before reviewers run. This root file is the sole active plan source. Schema `dsh-review-plan/v1` declares obligations and semantic lanes. The five standard obligation IDs remain mandatory; a plan may add change-specific obligations but cannot replace the standard review surface. Each lane has a stable ID, scope, exact file or directory-prefix inputs, upstream lane dependencies, assigned obligations, owners, consumers, and discriminating counterexamples. Obligations are either covered by at least one lane or explicitly excluded with a non-applicability reason. Every path changed between the plan base and the current source tree must match at least one lane; the implementation never silently expands a lane to absorb an unplanned path.
10
+
11
+ The recorded plan resolves its base to a commit that is an ancestor of current `HEAD`. Before review state can use or record a clean conclusion, it parses the active file and compares its canonical hash with the recorded plan. Missing, malformed, or semantically different active content fails closed before an old clean conclusion can authorize delivery; JSON formatting alone is immaterial. Negative review disposition is fail-closed in the other direction: it can retire recorded authorization even while the active plan or current source has drifted. A revision reuses the recorded base unless a base is explicitly supplied. A lane fingerprint hashes the lane declaration, its persistent invalidation `{epoch, revision}`, the canonical Git mode and blob identity including raw pathname bytes of every current source-tree entry selected by that lane's path rules, and the fingerprints of all declared upstream lanes. Plan path rules match those raw bytes as UTF-8 encoded exact names or directory prefixes; diagnostics encode undecodable paths reversibly rather than confusing their identities. The dependency graph must be acyclic. A change to one lane's declaration, generation, or selected content changes that lane fingerprint and recursively changes every dependent fingerprint, while unrelated lanes retain their identity. Re-recording a revised plan preserves only lane verdicts whose base, lane identity, evidence identity, and resulting fingerprint still match; this makes a boundary revision explicit without discarding unrelated evidence.
12
+
13
+ Reviewers may run concurrently from the fingerprints printed by `review:plan` or `review:status`. `recordReviewLaneVerdict` retains the captured `HEAD` as provenance and accepts a clean report when the captured lane fingerprint still matches. An unrelated concurrent edit or `HEAD` advance therefore does not reject the report. A changed direct or upstream input does reject it. A report ending in findings or `VERDICT: INCOMPLETE` is inspected before current-candidate equality and retires that lane and its declared dependent closure from the recorded plan, not unrelated lanes. Temporary source or active-plan drift therefore cannot make rejected evidence effective again after restoring the earlier candidate. Each accepted report is copied under `review-findings/evidence`, hashed, and referenced by a `dsh-review-lane-verdict/v1` record whose internal lane ID and evidence name must match its declared lane and fingerprint.
14
+
15
+ Plan recording, lane verdict recording or retirement, aggregate finalization, clearing, and pre-commit authorization are serialized by one atomic repository-local lock under Git metadata. The lock records the owner PID and a unique release token and bounds acquisition; it never automatically reclaims an owner because no portable pathname operation can prove and remove that exact generation without an ABA race. Crash recovery is an explicit operator action after confirming no review-state command is active, scoped to the exact `review-findings/state.lock` path resolved by Git. A negative report ordered after an older clean recorder advances a persistent per-lane invalidation revision within a random epoch even if the lane is temporarily absent from the current plan, before retiring its current closure. Reaching `Number.MAX_SAFE_INTEGER` rotates to a different random epoch at revision zero, preserving both invalidation and future progress. The absent lane must already have a retained tuple; an unknown ID cannot create one, and every active lane requires an explicit tuple. The tuple is part of that lane's fingerprint and therefore every dependent fingerprint; reports captured before retirement cannot overwrite it after the lane is re-added. Generations survive normal clearing and lane removal. Missing, partial, or malformed generation state blocks authorization; clear preserves valid state but removes damaged state, and explicit plan reconstruction creates a new epoch so a damaged lifecycle cannot restore an older authorization identity. A new clean review captured after retirement remains valid. Status is diagnostic and need not hold the mutation lock. Because the active plan, source tree, index, proof, and evidence can also be changed outside these commands, finalization and pre-commit obtain a stable final observation of their relevant identities before persisting or returning authorization.
16
+
17
+ After all lanes are effective, `npm run check` produces the existing whole-source verification proof for current `{HEAD, fingerprint}`. `review:finalize` writes `dsh-review-verdict/v2`, containing that whole-tree identity, the base, the complete plan hash, and every effective lane fingerprint and evidence hash. The pre-commit hook separately requires an absent or terminal findings ledger, a proof for current `HEAD`, equal source and index fingerprints, complete changed-path coverage, an effective verdict for every lane, intact evidence, and a composite verdict exactly matching that plan and proof. Advancing `HEAD` retires the proof and aggregate verdict. Source or index drift makes both records ineffective while the mismatch remains; restoring their exact candidate identity makes them effective again, while accepting a changed candidate requires another deterministic proof and aggregate finalization. Lane evidence remains reusable when its semantic declaration, direct inputs, upstream fingerprints, base ancestry, and evidence hash still hold.
18
+
19
+ `REVIEW_FINDINGS.md`, `REVIEW_PLAN.json`, reports, lane records, plans, proofs, and aggregate verdicts remain checkout-local. The two root working files are installed into `.git/info/exclude`; reports must stay outside the checkout or be ignored. The old `dsh-review-verdict/v1` single-report format and `verdict` command are rejected rather than treated as composite evidence.
10
20
 
11
21
  ## Alternatives considered
12
22
 
13
- **Keep the review as an unpinned transcript.** Recording only that a clean review happened leaves the gate bypassable by editing after the review, by reusing a verdict for another candidate, or by deleting the metadata; the observed clean-then-three-defects sequence is exactly the failure it hides.
23
+ **Repeat one complete-tree review after every fix.** This binds review to exact bytes but discards unaffected independent evidence and serializes work that has explicit semantic boundaries.
24
+
25
+ **Partition only by changed file paths.** File ownership is mechanically convenient, but intrinsic handling, declaration publication, callable reconstruction, module contracts, and recovery cross file boundaries. Paths select fingerprint inputs; semantic scope, dependencies, owners, consumers, and counterexamples define what the reviewer must establish.
26
+
27
+ **Keep every clean lane unless one of its own files changes.** This misses shared-owner and contract changes. Upstream lane fingerprints enter dependent fingerprints so invalidation follows the declared semantic graph.
28
+
29
+ **Never permit plan changes after review starts.** A fixed incorrect boundary would preserve a known coverage gap. Plan revisions are allowed but versioned by content, must cover every changed path, and invalidate only lanes whose declarations or dependency inputs changed.
14
30
 
15
- **Let the gate pass when no proof or ledger exists.** This preserves the previous behaviour for small or documentation-only changes, but it also preserves the bypass: removing or archiving the metadata becomes a way to commit without any review.
31
+ **Automatically add uncovered paths to a nearby lane.** This avoids stopping the workflow, but a file path does not prove semantic ownership. The gate reports uncovered paths and requires an explicit plan revision.
16
32
 
17
- **Store the verdict inside the verification proof.** A single file is simpler, but `npm run check` runs before the review and must not require a verdict to exist; the two records have different producers and lifetimes, so the proof gains a verdict-identity check instead of the verdict's storage.
33
+ **Store lane evidence without a final whole-tree proof.** Lane fingerprints establish review inputs, not deterministic test success or exact prospective commit contents. The composite verdict therefore remains paired with `npm run check` and the index-tree gate.
18
34
 
19
35
  ## Consequences
20
36
 
21
- A clean verdict now binds one candidate and one report hash, so editing after the review invalidates the commit instead of silently passing. The cost is that every commit, including a documentation-only slice, needs a fresh `npm run check` and one complete independent review; the alternative is a gate that any metadata deletion bypasses. The hook cannot judge review quality: it proves that a clean report for these exact bytes was recorded, not that the review was complete, which is why the coverage matrix and the `VERDICT: INCOMPLETE` outcome live in AGENTS.md as review obligations.
37
+ Independent review can begin in parallel after focused checks, and a correction normally reruns only the failed lane and its dependency closure. A small change may use one lane, so partition overhead remains proportional to the work. The plan author must identify semantic dependencies accurately; automation proves declared coverage and evidence identity, not that the declarations are intellectually complete. A newly discovered dependency is a plan defect that must be recorded before review continues. Finalization still requires one stable-tree `npm run check`, but it no longer requires another reviewer to repeat every already effective lane.
@@ -2,20 +2,24 @@
2
2
 
3
3
  ## Problem
4
4
 
5
- The session kernel previously executed user cells in a `node:worker_threads` worker owned by the DSH process. Reclaiming a stuck or unresponsive kernel required `worker.terminate()` inside that process; on Node 24 and 26 that teardown can reach an upstream cppgc finalizer defect (`node::contextify::ContextifyScript` or `ContextifyContext`) that writes through a destroyed `node::Realm`. Because the worker lived in the DSH process, the fault ended the whole process. The available Windows reproductions and stacks identify the defect on Node 24 and 26; the fix below does not depend on proving which other Node lines can reach it, so reclamation cannot rely on downgrading Node, retrying CI, or claiming that an in-host kill is safe.
5
+ Running the session kernel in a `node:worker_threads` worker owned by the DSH process makes reclamation of a stuck or unresponsive kernel depend on `worker.terminate()` inside that process. On Node 24 and 26, that teardown can reach an upstream cppgc finalizer defect (`node::contextify::ContextifyScript` or `ContextifyContext`) that writes through a destroyed `node::Realm` and ends the DSH process. The available Windows reproductions and stacks identify the defect on those Node lines. Reclamation therefore cannot rely on downgrading Node, retrying CI, or treating an in-host kill as safe; the process boundary must contain the failure without requiring proof about other Node lines.
6
6
 
7
7
  ## Decision
8
8
 
9
9
  The session kernel runs inside a plugin-owned helper process that the host may kill without killing DSH. `internal/kernel-child.js` receives one `init` message over process IPC, creates the existing kernel worker with the supplied `workerData` and `resourceLimits`, keeps that worker's private `MessagePort` inside the helper, and relays only plain data in both directions. Kernel output reaches the host through the helper's own platform stdio pipes, so no output byte is duplicated into IPC messages or counted by two owners.
10
10
 
11
- `internal/isolated-worker.js` exposes the worker-shaped transport that existing callers already use: `message`, `error`, `exit`, `close`, `stdout`, `stderr`, `postMessage` to the worker's parent port, and `terminate()`. The handshake exposes a process-local port adapter for the private kernel channel; the real `MessagePort` never crosses the process boundary. The transport records the real child exit immediately for stop deadlines, then publishes its worker-shaped `exit` event only after child `close` proves the platform output pipes drained; outward `exit` still precedes outward `close`. Every close has cutoffs anchored at its start: a release grace, a kill of the helper process, then a positive window for the real child exit. A shutdown acknowledgement proves that the helper released its own machinery, but it does not reclaim the instance.
11
+ `internal/isolated-worker.js` exposes the worker-shaped transport expected by callers: `message`, `error`, `exit`, `close`, `stdout`, `stderr`, `postMessage` to the worker's parent port, and `terminate()`. The handshake exposes a process-local port adapter for the private kernel channel; the real `MessagePort` never crosses the process boundary. The transport records the real child exit immediately for stop deadlines, then publishes its worker-shaped `exit` event only after child `close` proves the platform output pipes drained; outward `exit` still precedes outward `close`. Every close has cutoffs anchored at its start: a release grace, a kill of the helper process, then a positive window for the real child exit. A shutdown acknowledgement proves that the helper released its own machinery, but it does not reclaim the instance.
12
12
 
13
13
  `internal/isolated-worker.js` also owns every started transport until its real exit, cleanup, and output close. The kernel client, the workbench console, and the candidate runner each create one owner. `releaseAll()` frees current instances while the owner remains usable for reconfiguration; `dispose()` is terminal and refuses new starts. Reclamation failures remain visible to every aggregation and to later disposal instead of becoming unhandled rejections.
14
14
 
15
- Caller and helper environment boundaries are explicit. Each creation site projects the host environment with `normalizeWorkerEnvironment`, which keeps the user-visible contract and strips host-only instrumentation such as `NODE_V8_COVERAGE`. `IsolatedWorker` snapshots that projected object before `child_process.fork`; the fork call may mutate its own env object by copying `NODE_V8_COVERAGE` into the helper, so the pre-fork snapshot is what `kernel-child.js` passes to `new Worker({ env: ... })`. The helper itself may retain the coverage variable, but the inner user Worker and the child processes it creates receive only the projected environment. An explicit transport/coverage test can opt into instrumentation to verify worker branches; production paths do not change the user environment to collect coverage.
15
+ Caller and helper environment boundaries are explicit. Each creation site projects the host environment with `normalizeWorkerEnvironment`, which keeps the user-visible contract and strips host-only instrumentation such as `NODE_V8_COVERAGE`. `IsolatedWorker` snapshots that projected object before `child_process.fork`; the fork call may mutate its own env object by copying `NODE_V8_COVERAGE` into the helper, so the pre-fork snapshot is what `kernel-child.js` passes to `new Worker({ env: ... })`. When the Host executable is Electron, `IsolatedWorker` overlays `ELECTRON_RUN_AS_NODE=1` only on the fork environment so the packaged executable starts the helper module instead of reopening the desktop application. The inner user Worker and the child processes it creates still receive the original projected snapshot, without that helper-only override. An explicit transport/coverage test can opt into instrumentation to verify worker branches; production paths do not change the user environment to collect coverage.
16
16
 
17
17
  The helper answers an on-demand utilization-sample request from its own loop, and `IsolatedWorker` exposes `sampleUtilization()`. `SessionCellExecutor` starts the wall bound at request submission, awaits that fresh baseline, then starts the compute interval before it posts the prepare or run frame, so work completed before submission is excluded while prepare blocking remains counted. The exception owned by [ADR 0024](0024-repl-console-observation.md) is a confirmed unfinished observation on the same worker: the executor may post prepare before starting budgets so the observation can finish, and the matching observation-completion/readiness acknowledgement starts them. A sample that times out, cannot be sent, disconnects, or exits is a bounded worker-exit failure: pending requests are cleared and no prepare/run frame is dispatched. The ready handshake still contributes an additional startup sample, but it is not the per-cell baseline and it does not reset or defer budgets.
18
18
 
19
+ Helper stdout and stderr are part of cell settlement, not unowned process noise. For every run, the Host chooses a nonce and arms one output round before posting source. The kernel writes nonce-bearing start markers to both native descriptors and waits for the Host to observe both before executing the cell. It writes matching end markers after evaluation, pending program calls and value encoding settle, but before posting `done`. The Host releases `done` only after both end markers arrive. Bytes between those fences, including direct fd 1/2 writes and inherited child stdio, belong to that physical run and share its aggregate output budget. Structured console logs retain their own order; stdout and stderr each retain pipe order, but the merged presentation does not claim a total chronology across the independent control and descriptor channels.
20
+
21
+ Bytes before a new start fence prove that a settled run still produced descriptor output, so the new run is rejected and the worker is reset rather than attaching those bytes to it. A structured console or stream callback keeps its scheduling execution identity through the worker's private async-local store; output after that execution closes sends a `late-output` control event and likewise rejects any affected run. Bare descriptor bytes carry no scheduling identity, so bytes that actually arrive between a later run's acknowledged start and end fences follow the physical-arrival rule instead of being attributed to an unknowable callback. Fence mismatch, overlap, excess output or out-of-round output is an explicit output-attribution failure and resets the transport. The first idle out-of-round chunk closes capture and starts reset immediately; when no request is active, the Host retains one failure for the next execution instead of continuing to drain an unbounded producer without a diagnostic.
22
+
19
23
  ## Alternatives considered
20
24
 
21
25
  **Keep the worker in the DSH process and only improve cooperative shutdown.** Asking user code to release its own realms cannot bound a wedged kernel, and any fallback in-host kill reaches the same upstream teardown path that ends DSH.
@@ -30,8 +34,8 @@ The helper answers an on-demand utilization-sample request from its own loop, an
30
34
 
31
35
  ## Consequences
32
36
 
33
- A synchronously stuck kernel is reclaimed by killing a plugin-owned helper process; DSH survives and observes a real child exit, output close, and cleanup outcome. This containment removes the plugin's in-host kill path, but it does not repair, characterize, or claim the same cause for every upstream Node teardown path.
37
+ A synchronously stuck kernel is reclaimed by killing a plugin-owned helper process; DSH survives and observes a real child exit, output close, and cleanup outcome. This containment keeps session-worker teardown out of DSH, but it does not repair, characterize, or claim the same cause for every upstream Node teardown path.
34
38
 
35
39
  The transport gains one process and an IPC hop. Ports, shared memory, and transferred buffers cannot cross the process boundary, so they stay inside the helper or become plain data; output continues over the helper's stdio pipes. The helper's own `execArgv` is emptied so it does not inherit host startup arguments.
36
40
 
37
- Environment provenance is now explicit in code: the user Worker receives the caller's projected environment, while coverage instrumentation stays on the helper side except in the explicit transport test. A reclamation refusal stays owned and observable instead of being reported as success or surfacing as an unhandled rejection.
41
+ Environment provenance is explicit in code: the user Worker receives the caller's projected environment, while coverage instrumentation and an Electron Host's Node startup override stay on the helper side. A reclamation refusal stays owned and observable instead of being reported as success or surfacing as an unhandled rejection.
@@ -30,12 +30,23 @@ generation is.
30
30
  **Selection is a live capability.** The plugin's static injection names only the
31
31
  services both generations provide; the seam owner waits through `inject` for
32
32
  whichever execution service the host registers, in a scope that also requires the
33
- plugin's own services, and attaches once. When both are
34
- registered, the current generation wins, and the preceding generation attaches
35
- only when the current one is absent. Attachment runs in the injected scope, so
33
+ plugin's own services, and owns one live attachment at a time. When both are registered, the current
34
+ generation wins, including when it appears after a preceding-generation attachment.
35
+ That transition first disposes the legacy injected fiber and its complete effect
36
+ tree, then attaches in the current service's scope; cleanup from the retired scope
37
+ cannot clear the new owner. If that attach fails, the owner marks the current
38
+ service object unusable, re-arms the preceding-generation attachment
39
+ immediately, and reports the failure instead of leaving the plugin with no
40
+ execution seam; the failed object is never retried, while a replacement current
41
+ service supersedes the restored attachment. The preceding generation therefore
42
+ attaches only when the current one is absent or is the recorded unusable object.
43
+ Attachment runs in the injected scope, so
36
44
  the plugin is unloaded when the host unregisters that service and reattaches when
37
45
  it is registered again. A service that satisfies the name but not the contract
38
- (`run` or `resolve` missing) is reported as a load failure naming the service.
46
+ (`run` or `resolve` missing) follows the same path and is reported as a load
47
+ failure naming the service; when a preceding-generation attachment exists, the
48
+ report accompanies its restoration so `run_code` never silently returns to the
49
+ host provider.
39
50
 
40
51
  **Execution is one neutral call shape.** The owner publishes `invokeUpstream`,
41
52
  which reproduces each generation's own call shape — directly for
@@ -93,8 +104,17 @@ escalation it thinks it is offering.
93
104
  The plugin activates on both the current and the preceding host generation, and
94
105
  one test owner covers the selection rules, the neutral call shape, the descriptor
95
106
  takeover, and the release semantics for both. A host that registers neither
96
- execution service leaves the plugin waiting, exactly as a required injection did,
97
- rather than loading a plugin whose entry points can never run.
107
+ execution service cannot be served, and its activation settles with a bounded
108
+ diagnostic naming the missing seam — `no host execution seam (ptcRuntime or
109
+ codeRuntime) is registered` — after the attachment window instead of staying
110
+ pending: the host awaits loader settlement before it becomes usable, so an
111
+ unbounded wait would park every agent, native tool, and unrelated plugin rather
112
+ than failing this entry.
113
+
114
+ A current-generation service that fails to attach cannot leave the plugin
115
+ unattached while the preceding service is still registered: the preceding
116
+ attachment is restored and the failure is reported through the plugin's own
117
+ logger in addition to the injected fiber's activation result.
98
118
 
99
119
  `run_code` on the current host no longer advertises a per-call deadline or file
100
120
  sandbox, and DSH rejects those arguments with its own message instead of the
@@ -0,0 +1,29 @@
1
+ # Close semantic obligations by owner
2
+
3
+ ## Problem
4
+
5
+ Focused tests and coverage can prove their selected examples executed, but they cannot show that every plugin-owned semantic transformation or execution boundary has an owner, contract and independent oracle. Adding more examples to a single compiler or realm matrix leaves module, transport, recovery, host and client boundaries outside that matrix, while treating all Node behavior as one fidelity surface erases intentional PTC differences and bounded external assumptions. An unregistered source boundary therefore needs a deterministic failure before review, not a reviewer remembering to extend a list.
6
+
7
+ ## Decision
8
+
9
+ `semantic-obligations.json` is the tracked graph of plugin-owned semantic boundaries. Each obligation records one semantic owner, exact implementation files, disposition, owning contract, preserved observables or declared differences, execution entries, lifecycle states, language or data generations, platform bounds, consumers, oracle, executable evidence and upstream obligations. Dispositions distinguish behavior preserved from an external owner, intentional PTC differences and bounded external surfaces; an omitted or uncertain obligation is unknown and fails validation rather than being relabeled as preserved.
10
+
11
+ `scripts/semantic-obligations.mjs` validates the graph before build and coverage in `npm run verify`. The exact inventory covers every JavaScript implementation file in `internal/` and `src/`, the public `index.js` and `client.js` entries, and the journal migration entry, with exactly one semantic owner per file. Adding, removing or assigning a source twice fails closed until the graph changes. Contract and evidence files must exist, every obligation needs executable test evidence, dependencies must resolve without cycles, journal versions must remain a contiguous recorded range, and declared language and module generations must equal their executable owners. The command emits counts for preserved, intentional-difference, bounded-external and unknown obligations; zero unknown means closure over the declared plugin source boundary, not equivalence with all current or future Node or DSH behavior.
12
+
13
+ The graph complements, rather than replaces, focused tests, coverage and independent review lanes. A boundary-specific registry can enforce a stronger relation where the implementation supplies one: worker realm mutations use their classified installation entry and AST check, journal generations use their closed schema, and language/module generations use exported sets. Other records bind exact owner files and evidence so a new boundary cannot enter the tracked source inventory silently; review still evaluates whether an edit inside an existing owner changes its obligation or dependencies.
14
+
15
+ `docs/semantic-validation.md` explains how to choose an oracle and extend evidence. `REVIEW_PLAN.json` remains the checkout-local snapshot partition: its lanes may split or combine tracked obligations for review cost, but must preserve the graph's owner dependencies and changed-path coverage. A clean graph report establishes declared coverage only; deterministic verification and clean independent lane verdicts remain separate delivery requirements.
16
+
17
+ ## Alternatives considered
18
+
19
+ **Expand the Test262 or compiler matrix until it appears comprehensive.** Those matrices are strong independent oracles for selected language behavior, but they do not own worker transport, program bindings, journals, host integration or client projection and cannot detect an omitted entry outside their axes.
20
+
21
+ **Use line and function coverage as the global model.** Coverage shows code execution, not which observable must be preserved, whether a difference is contractual, or whether the expected value came from an independent source.
22
+
23
+ **Make the worker realm inventory the global registry.** Realm mutation is only one boundary. Folding compiler, module, wire, recovery and host behavior into Node surface rows would obscure their owners and recreate a manually sampled API matrix.
24
+
25
+ **Derive ownership only from each temporary review plan.** Review plans are candidate-specific and checkout-local. They cannot serve as the durable source inventory or contract graph required before a plan exists.
26
+
27
+ ## Consequences
28
+
29
+ New implementation files and generation changes require an explicit obligation update, and stale evidence blocks the normal gate early. The graph is intentionally bounded to plugin-owned JavaScript sources and declared platform contracts; dependency internals, arbitrary Node APIs and future DSH behavior remain outside the equivalence claim. Exact file assignment adds maintenance cost, but makes source growth and ownership movement reviewable instead of silent.
@@ -5,14 +5,14 @@ This directory records stable design constraints for PTC Plus. An ADR states a d
5
5
  ## Rules
6
6
 
7
7
  - **A new or changed durable decision updates or adds an ADR** in the same change. Record architecture, public or cross-module contracts, persisted or wire formats, and process or tooling choices that a maintainer may reasonably revisit. A difficult or non-trivial implementation of an existing decision does not by itself require an ADR.
8
- - **`## Alternatives considered` is mandatory.** Name each genuine alternative and why it lost, one bold-led paragraph per alternative. A decision recorded without what it beat invites re-litigation.
8
+ - **`## Alternatives considered` is mandatory for a new or changed ADR.** Name each genuine alternative and why it lost, one bold-led paragraph per alternative. A decision recorded without what it beat invites re-litigation. Entries written before this rule may use the shorter `## Alternatives` heading; repair them when they are next touched.
9
9
  - **Naming.** Files follow `NNNN-kebab-case-title.md`. Keep the number sequence monotonic; never reuse a number.
10
- - **Format.** One physical line per paragraph:
10
+ - **Format.** One physical line per paragraph in new entries, or the entry's own consistent wrapping when it already wraps; the headings and their order are what make an ADR readable:
11
11
  - `# <title>` — the decision in one line
12
- - `## Problem` — the motivation, written to stand without the solution
12
+ - `## Problem` or `## Context` — the motivation, written to stand without the solution
13
13
  - `## Decision` — shipped reality in the present tense; keep it current with what actually shipped
14
14
  - bespoke technical sections as needed
15
15
  - `## Alternatives considered` — mandatory
16
- - `## Consequences` — what the trade-off cost and bought
16
+ - `## Consequences` — what the trade-off cost and bought; older entries may carry `## Verification` instead or omit it
17
17
  - **Supersession.** When a later decision replaces an ADR, fold every unique rationale, alternative, and consequence into the current owner and repair inbound links before deleting the old file. Partial supersession keeps both files cross-linked. Git history is not the only copy of rationale.
18
18
  - **Kept current.** When the code later moves a file, renames a surface, or changes a default, update the owning ADR in the same change (facts only, not the decision itself).