dsh-ptc-plus 0.4.2 → 0.4.8

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 (89) hide show
  1. package/README.en.md +170 -76
  2. package/README.md +171 -77
  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 +599 -310
  7. package/compiler-core.cjs +162 -160
  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 +49 -11
  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/0017-track-the-latest-dsh-public-surface.md +5 -1
  15. package/docs/adr/0019-plugin-settings-and-kill-switch.md +3 -3
  16. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +3 -1
  17. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +14 -3
  18. package/docs/adr/0023-global-user-bindings.md +1 -1
  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 +4 -0
  21. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +26 -6
  22. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +2 -2
  23. package/docs/adr/0031-close-semantic-obligations-by-owner.md +29 -0
  24. package/docs/adr/README.md +4 -4
  25. package/docs/architecture.md +8 -5
  26. package/docs/binding-review-placement-design.md +1 -1
  27. package/docs/client-ui.md +8 -4
  28. package/docs/durability-design.md +7 -7
  29. package/docs/installation.md +48 -12
  30. package/docs/publishing.md +4 -4
  31. package/docs/release-notes.md +109 -0
  32. package/docs/runtime-reference.md +25 -12
  33. package/docs/semantic-validation.md +7 -3
  34. package/docs/user-bindings.en.md +7 -6
  35. package/docs/user-bindings.md +6 -5
  36. package/docs/value-wire.md +1 -1
  37. package/docs/verification.md +43 -2
  38. package/index.js +39 -34
  39. package/internal/async-local-storage-intrinsics.js +12 -7
  40. package/internal/callable-source-facts.js +37 -1
  41. package/internal/cell-analysis.js +64 -9
  42. package/internal/config-spec.js +1 -1
  43. package/internal/cordis-tools-owner.js +81 -15
  44. package/internal/direct-surface-owner.js +331 -7
  45. package/internal/edit-transport-owner.js +80 -20
  46. package/internal/execution-seam-compat.js +192 -30
  47. package/internal/kernel-worker.js +162 -72
  48. package/internal/message-sources.js +14 -0
  49. package/internal/module-compilation.js +2 -1
  50. package/internal/rejected-cell-editor.js +11 -21
  51. package/internal/repl-memory-projection.js +10 -0
  52. package/internal/repl-scope-normalizer.js +72 -35
  53. package/internal/repl-value-observer.js +141 -45
  54. package/internal/runtime-config.js +62 -2
  55. package/internal/runtime-intrinsics.js +3 -0
  56. package/internal/runtime-messages.js +6 -4
  57. package/internal/session-cell-executor.js +24 -1
  58. package/internal/session-journal-recovery.js +267 -67
  59. package/internal/session-journal.js +466 -40
  60. package/internal/session-log-view.js +5 -4
  61. package/internal/session-runtime.js +45 -21
  62. package/internal/session-state.js +7 -29
  63. package/internal/settings-compat.js +66 -1
  64. package/internal/source-position-map.js +19 -0
  65. package/internal/user-binding-console-worker.js +23 -9
  66. package/internal/user-binding-draft-projection.js +3 -2
  67. package/internal/user-bindings-owner.js +2 -1
  68. package/internal/user-bindings.js +6 -1
  69. package/internal/validated-parse-repair.js +6 -2
  70. package/internal/value-wire.js +95 -30
  71. package/internal/worker-client.js +99 -8
  72. package/internal/worker-cwd-virtualization.js +10 -9
  73. package/internal/worker-output-capture.js +187 -0
  74. package/internal/worker-output-fence.js +26 -0
  75. package/internal/worker-realm-surfaces.js +197 -0
  76. package/internal/worker-repl-realm.js +10 -4
  77. package/package.json +42 -4
  78. package/src/client-activity.js +4 -1
  79. package/src/client-authoring-view.js +121 -62
  80. package/src/client-console.js +4 -2
  81. package/src/client-copy.js +4 -2
  82. package/src/client-feature-gates.js +7 -9
  83. package/src/client-host-compat.js +104 -27
  84. package/src/client-repl-view.js +3 -1
  85. package/src/client-styles.js +12 -1
  86. package/src/client-tool-view.js +3 -1
  87. package/src/client-transport.js +2 -2
  88. package/src/client-workbench.js +10 -7
  89. 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,12 +17,15 @@
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.
25
27
  - [Focused Verification](verification-optimization-work.md): bounded coverage diagnostics and their relationship to the final verification gate.
26
28
  - [Semantic Validation](semantic-validation.md): pinned Test262 cases, dialect contracts, native differential matrices and their limits.
27
29
  - [Publishing](publishing.md): release checks, package contents, permissions, and platform validation.
30
+ - [GitHub Release Notes](release-notes.md): user-perspective priority order, required sections, bilingual style, and a worked example for release notes.
28
31
  - [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
@@ -67,8 +68,10 @@ session-log projection captures the eligible target at the edit call event and a
67
68
  source only when its target sequence matches that snapshot and its journal is valid and non-noop,
68
69
  so live and recovered eligibility derive from the same persisted relation.
69
70
 
70
- The caller sends exactly one of `edits` or `regex_edits`, plus an optional non-negative
71
- `expected_target_call_seq` precondition. The precondition must equal the call sequence of the target
71
+ The public schema is one closed object with optional `edits`, `regex_edits`, and
72
+ `expected_target_call_seq` properties, avoiding duplicated object alternatives in the provider
73
+ prompt. Runtime validation still requires exactly one of `edits` or `regex_edits`, plus an optional
74
+ non-negative `expected_target_call_seq` precondition. The precondition must equal the call sequence of the target
72
75
  captured for the persisted edit event; a mismatch returns an unedited result before derived
73
76
  dispatch. Ordinary model-authored edits omit it and retain latest-target selection. Exact edits
74
77
  contain at most 16 items; each
@@ -94,21 +97,53 @@ tool/result: { edited: true, value?, error?, logs }
94
97
  The complete derived source, its journal, and its target call sequence are stored only in private tool-result metadata, including
95
98
  when the derived cell fails after entering the runtime. Cold
96
99
  recovery folds that explicitly marked derived run into the durable REPL history. The source is not
97
- copied into the model-visible edit result, and assistant stream chunks for the two declared
100
+ copied into the model-visible edit result. Valid assistant stream chunks for the two declared
98
101
  transports pass through unchanged.
99
102
  Consequently the UI and later model requests do not attribute a generated `run_code` call to the
100
103
  model.
101
104
 
105
+ The stream owner handles one bounded provider protocol failure before DSH assembles the assistant
106
+ message. It buffers tool-call material until the terminal event. If the response reports the exact
107
+ invalid-tool-JSON `MALFORMED_RESPONSE` as a terminal chunk or stream exception, it changes that
108
+ terminal reason to `tool-calls`.
109
+ DSH's existing Agent Loop
110
+ then preserves an unparseable argument as a string and routes it through ordinary tool validation,
111
+ execution, and result recording, after which the model receives another step. A malformed tool argument therefore
112
+ cannot become a turn-ending provider failure merely because this adapter parses it earlier than the
113
+ Agent Loop.
114
+
115
+ The stream owner preserves calls only when the buffered body consists entirely of
116
+ tool-call-specific framing plus at most one `usage` event. When that trusted body contains exactly
117
+ one complete, internally consistent declared `run_code` or `edit_run_code` block, the stream owner
118
+ first considers one correction: delete exactly one final `}`. The block index, call ID, name,
119
+ concatenated deltas, and final arguments must agree, and the candidate must parse as an object
120
+ accepted by that request's live direct-tool schema. A successful correction changes the final delta
121
+ and final block arguments before the same `tool-calls` settlement. Without that proof, trusted
122
+ internally consistent complete blocks retain their original identity and argument bytes for the
123
+ ordinary tool-error path. The owner re-emits those calls with canonical
124
+ `block-start`, full-argument delta, and `block-end` framing so provider variants tolerated by the
125
+ assembler also satisfy DSH's stream invariant. A final `block-end` is canonical even when the
126
+ provider emitted no deltas; when deltas exist, their supplied identity fields and accumulated
127
+ arguments must agree with it. An already visible open text or reasoning block is closed from its
128
+ accumulated content before the synthetic call. If any tool block is incomplete or inconsistent, or no tool block was
129
+ emitted, more than one usage event appears, or any other event occurs in the buffered body, the owner
130
+ removes unsafe block and unknown events, retains at most the first protocol-valid `usage`, and emits
131
+ one deterministic `run_code` call with an argument string that cannot parse as a JSON object. That
132
+ call can only fail DSH's ordinary schema
133
+ validation, so no untrusted partial call executes and the model still receives another step. Valid streams and every
134
+ other provider failure pass through unchanged. The rule does not insert missing delimiters, search
135
+ arbitrary edits, reinterpret native calls, or retry effects.
136
+
102
137
  No edit-specific runtime context is emitted. The truthful call/result pair already carries the
103
138
  operation and outcome; changing an aggregate runtime-context snapshot merely to restate that fact
104
139
  would repeat unrelated policy context. Rewrite feedback and unrelated recovery tips retain their
105
140
  own independently justified lifecycles.
106
141
 
107
142
  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
143
+ only the 12 suffixes of one or two closing tokens drawn from `}`, `)`, and `]` against the same
144
+ binding catalog, reserved bindings, redeclaration mode, rewrite policy, and import state as the
145
+ rejected cell. Exactly one candidate across both lengths must complete preparation without a binding
146
+ 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
147
  persistent event sequence. The diagnostic then renders those already-validated
113
148
  `edit_run_code({ edits: [...], expected_target_call_seq })` arguments on one help line. At dispatch,
114
149
  the precondition binds the proof to that rejected cell even if another matching source has become
@@ -139,7 +174,10 @@ claim that the earlier execution was undone or idempotent.
139
174
  out-of-surface call are different protocol facts. Rewriting a real `edit_run_code` destroys a valid
140
175
  identity; normalizing a live-schema-proven native miscall to the declared `run_code` transport gives
141
176
  an otherwise invalid call its executable representation. Native-call canonicalization therefore
142
- remains available while the two declared transports pass through unchanged.
177
+ remains available. The bounded malformed-input correction likewise retains a declared call's identity.
178
+ Fallback settlement preserves arguments for trusted complete internally consistent blocks. Unsafe,
179
+ partial, or mixed buffered material is replaced by a validation-rejected `run_code` call only after
180
+ the provider itself reports the exact terminal protocol failure.
143
181
 
144
182
  ## Consequences
145
183
 
@@ -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.
@@ -10,6 +10,10 @@ PTC Plus must remain independently installable on unmodified official DSH distri
10
10
 
11
11
  The compatibility target is the latest available DSH release. Production behavior, configuration, tests, installation guidance, and current compatibility claims depend on public extension contracts and observed live schemas, never on a DSH version allowlist or comparison. An upstream default projection is not an extension ceiling: when public scoped registration and presentation support a plugin-owned capability, PTC Plus preserves that capability and its model-visible identity instead of deleting or renaming it to match the default. Deterministic normalization remains valid for a call that is outside the declared direct surface when the live schema proves one native target and the lowering preserves arguments, call identity, authority, and result semantics. Deterministic tests exercise the consumed contracts; model-backed and packaging acceptance runners use the installed DSH and record `dsh --version` in generated reports so failures remain attributable without turning the observed value into policy. Concrete DSH release numbers may appear only in source comments that identify historical integration or evaluation evidence and cannot influence execution or acceptance.
12
12
 
13
+ Release discovery is separated from candidate verification. The root manifest declares the official `next` channel for the DSH packages used by development and freezes the resolved cohort in the root lockfile. `compat/latest` declares only the official DSH meta-package on `latest` and freezes that complete graph in its own lockfile. Resolved versions in these generated lock snapshots are reproducibility evidence selected by the channel declarations; they are not compatibility allowlists or runtime branches. Ordinary `verify` and `check` runs make no registry request and fail quickly when the installed root graph differs from the root lock.
14
+
15
+ The scheduled baseline refresh queries the official registry. When either channel moves, it updates both lock snapshots on an automation-owned branch, opens or updates one pull request, and dispatches the normal CI workflow once for that frozen candidate. GitHub suppresses workflow runs from branch and pull-request events produced by the workflow's `GITHUB_TOKEN`, so the explicit dispatch is the candidate's only CI run. If neither tag moved, it does not resolve or install the dependency graph. The Host contract suite tests the packed plugin against the root `next` graph and creates a repository-external consumer from the tracked `latest` lock. That consumer exposes the public packages from the selected Host graph to the plugin and runs the execution-seam, RPC-codec, and compressed Session persistence contracts. No compatibility run independently selects tags for DSH service packages, because their dist-tags need not move as one cohort.
16
+
13
17
  Preceding public contracts remain supported where capability detection is
14
18
  unambiguous. Tools presentation is selected by the installed public schema;
15
19
  Client contributions depend on their slots and supplied hooks rather than unused
@@ -69,4 +73,4 @@ capability, storage and observation rules independently of transport.
69
73
 
70
74
  Feature completion requires evidence from the actual packaged plugin running on the selected unmodified Host, including the affected user flow. Component fixtures and public-interface unit tests validate narrower properties; they do not prove that a required renderer exists or is loaded in that distribution. A clean code review and passing deterministic checks are separate from product acceptance. Both must cover the final change before a feature is described as delivered; commit and publish authorization remain separate user decisions.
71
75
 
72
- Each upstream DSH release becomes the immediate compatibility target and must pass the public-surface, packaging, and model-backed checks appropriate to the change. Users are not blocked by stale version metadata. Historical reports remain attributable through generated runtime metadata or source comments, while a passing older run never substitutes for validation against the latest release.
76
+ Each upstream DSH release becomes the immediate compatibility target and must pass the public-surface, packaging, and model-backed checks appropriate to the change. The automated pull request makes an upstream tag movement an explicit source candidate; the lockfile and CI result keep its proof reproducible after the registry moves again. Users are not blocked by stale version metadata. Historical reports remain attributable through generated runtime metadata or source comments, while a passing older run never substitutes for validation against the latest release.
@@ -8,17 +8,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 whichever public settings transport the installed Host exposes (`configForms` or `settingsScope`).
12
12
 
13
13
  ## Decision
14
14
 
15
15
  PTC Plus registers one DSH settings namespace `ptc-plus` with the same field list, defaults and validation as the Host Config schema. The field definitions live once in `internal/config-spec.js`; `index.js` builds the Cordis Config schema from it, and the esbuild client bundle imports the same module so the UI does not copy defaults or validation.
16
16
 
17
- The settings card'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
 
@@ -14,7 +14,7 @@ Tool registration must finish before the prompt assembly returned to the agent;
14
14
 
15
15
  ## Decision
16
16
 
17
- Add `cordisToolsEnabled: boolean`, default `false`, as a live PTC Plus setting. When enabled, PTC Plus mounts the official `@deepseek-ai/dsh-tool-cordis` plugin and a maintained `@deepseek-ai/dsh-skill-filesystem` provider in each agent scope that exposes every surface the mount publishes through: `run_code`, the `skill` tool, and the public `agentPresets` and `skills` services; disabling it disposes both fibers immediately. The provider resolves the shipped `cordis` preset through the public `agentPresets` service and reads its sibling `skills` root without including default roots. At the public `skills.registerProvider` seam, PTC Plus transparently filters discovery and loading to exactly `cordis-plugin-development`; the maintained filesystem provider still owns parsing, resource bases, watch, invalidation, incomplete observations, and body loading. This prevents unrelated or obsolete sibling Skills from silently enlarging the PTC surface without copying the companion content or switching the current preset. A scope that omits one of those surfaces is not an error: the owner keeps the agent pending, publishes nothing there, and retries on the DSH tools-change signal or the next prompt assembly, because a later registration or provided service can supply the missing member ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
17
+ Add `cordisToolsEnabled: boolean`, default `false`, as a live PTC Plus setting. When enabled, PTC Plus mounts the official `@deepseek-ai/dsh-tool-cordis` plugin and a maintained `@deepseek-ai/dsh-skill-filesystem` provider in each agent scope that exposes every surface the mount publishes through: `run_code`, the `skill` tool, and the public `agentPresets` and `skills` services; disabling it disposes both fibers immediately. The provider resolves the shipped `cordis` preset through the public `agentPresets` service and reads its sibling `skills` root as an immutable bundled Host resource without including default roots or watching the packaged directory. At the public `skills.registerProvider` seam, PTC Plus transparently filters discovery and loading to exactly `cordis-plugin-development`; the maintained filesystem provider still owns parsing, resource bases, incomplete observations, and body loading. This prevents unrelated or obsolete sibling Skills from silently enlarging the PTC surface without copying the companion content or switching the current preset. A scope that omits one of those surfaces is not an error: the owner keeps the agent pending, publishes nothing there, and retries on the DSH tools-change signal or the next prompt assembly, because a later registration or provided service can supply the missing member ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
18
18
 
19
19
  The Skill provider and official Cordis child fiber form one reversible mount. Both must settle, and the scoped `skills` service must prove that `cordis-plugin-development` resolves from the added provider as model-invocable and loadable, before the first prompt assembly is returned. A prepended public `system-prompt/assemble` waterfall listener is the final race barrier: if collection began before the mount settled, it waits for readiness, discards that stale assembly, and invokes public assembly again so DSH recollects the official providers. It does not synthesize or mutate Cordis schemas or guidance. The Cordis fiber's resolved `inject` declaration is the authoritative required-service list, and its live registrations are the authoritative tool names, schemas, and guidance. A scope whose exposed preset, Skill service/tool, declared service, publication, or child fiber contradicts the DSH contract is a configuration error and rolls back every contribution; an absent surface only defers the mount. An unusable scope reached through the host's own calls — `agent/created` and the prepended waterfall — withdraws and reports one warning instead of failing the host operation that created the scope ([ADR 0029](0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)).
20
20
 
@@ -24,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. A generation that publishes an absolute composition path for the shipped `cordis` preset uses its sibling `skills` root. For a pathless generation, PTC Plus asks the Host's public `pluginPackages.packageOf` service for the active installation's `@deepseek-ai/dsh-agent-preset` or `@deepseek-ai/dsh-agent-presets` resource, then selects that generation's known Skill layout. Older generations that do not publish `pluginPackages` may resolve only the historical plural package from the Host's `ctx.baseUrl`; this compatibility path is disabled whenever the service exists, including when it returns no package. It never uses plugin-anchored ambient Node lookup, because a profile or Desktop installation may contain a stale package from another Host generation. PTC Plus accepts a root only when it contains the exact `cordis-plugin-development/SKILL.md`; it does not infer support from a package name or directory alone. An unusable preset (`broken`) is reported as unavailable before path or package resolution, while an invalid published path remains a host contradiction rather than falling through to a different generation.
28
+
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,7 +6,7 @@ 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
 
@@ -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.
@@ -16,6 +16,10 @@ Caller and helper environment boundaries are explicit. Each creation site projec
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,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
@@ -12,7 +12,7 @@ PTC Plus publishes its Remote services through DSH's TYPERT registry, and that r
12
12
 
13
13
  Each generation validates only the member it owns and ignores the other, so one published contract serves whichever shape the installed host implements. Compatibility follows the live acceptance behavior of the registry rather than a release version, and the decoder is published once, so a host that reads both members cannot obtain two different decoders for one wire member.
14
14
 
15
- CI registers the packed contract with the installed host's own registry on both the stable and alpha channels (`scripts/dsh-rpc-contract-smoke.mjs`), so a generation that changes this validation fails the packaging check instead of reaching users.
15
+ CI registers the packed contract with the installed host's own registry from the frozen official `latest` and `next` graphs (`scripts/dsh-rpc-contract-smoke.mjs`), so a generation that changes this validation fails the packaging check instead of reaching users.
16
16
 
17
17
  ## Alternatives Considered
18
18
 
@@ -24,4 +24,4 @@ CI registers the packed contract with the installed host's own registry on both
24
24
 
25
25
  ## Consequences
26
26
 
27
- One plugin build serves the stable and alpha channels for this surface, and the compatibility rule lives in a single module with the decoder published once. A future generation that requires another member, or that rejects a codec carrying a member it does not know, needs this owner updated; the regression test is CI's registration against the installed registry, which fails on the channel that changed instead of on the user's machine. The decoder keeps the project's maintained schema runtime, so a host that validates payloads itself still evaluates the same semantics the plugin's own tests exercise through both members.
27
+ One plugin build serves the preceding and current public codec generations for this surface, and the compatibility rule lives in a single module with the decoder published once. A future generation that requires another member, or that rejects a codec carrying a member it does not know, needs this owner updated; the regression test is CI's registration against the installed registry, which fails on the frozen Host graph that changed instead of on the user's machine. The decoder keeps the project's maintained schema runtime, so a host that validates payloads itself still evaluates the same semantics the plugin's own tests exercise through both members.
@@ -0,0 +1,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).