dsh-ptc-plus 0.4.1 → 0.4.2
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.
- package/README.en.md +6 -10
- package/README.md +6 -10
- package/client.js +262 -31
- package/compiler-core.cjs +132 -130
- package/compiler-core.cjs.map +3 -3
- package/docs/README.md +1 -0
- package/docs/adr/0023-global-user-bindings.md +6 -6
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +3 -3
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +5 -5
- package/docs/architecture.md +9 -5
- package/docs/client-ui.md +1 -1
- package/docs/durability-design.md +6 -3
- package/docs/installation.md +4 -4
- package/docs/runtime-reference.md +5 -1
- package/docs/stateful-binding-updates-proposal.md +8 -4
- package/docs/user-bindings.en.md +5 -3
- package/docs/user-bindings.md +4 -2
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +15 -1
- package/internal/async-local-storage-intrinsics.js +38 -0
- package/internal/binding-declaration-contract.js +8 -0
- package/internal/binding-source-analysis.js +381 -64
- package/internal/binding-update-policy.js +7 -1
- package/internal/cell-analysis.js +21 -8
- package/internal/compiler-intrinsics.js +9 -43
- package/internal/compiler-module-links.js +7 -4
- package/internal/dynamic-environment-integration.js +8 -4
- package/internal/dynamic-environment-runtime.js +24 -3
- package/internal/dynamic-native-calls.js +4 -1
- package/internal/dynamic-native-runtime.js +15 -1
- package/internal/failure-reporting.js +38 -30
- package/internal/isolated-worker.js +17 -10
- package/internal/kernel-worker.js +493 -331
- package/internal/module-compilation.js +5 -4
- package/internal/module-transform-contract.js +32 -2
- package/internal/record-utils.js +24 -15
- package/internal/repl-value-observer.js +6 -3
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/session-cell-executor.js +2 -1
- package/internal/session-journal-schema.js +30 -13
- package/internal/session-journal.js +19 -4
- package/internal/session-runtime.js +1 -0
- package/internal/source-position-map.js +19 -0
- package/internal/stateful-root-compiler.js +3 -1
- package/internal/typescript-transform.js +4 -2
- package/internal/user-binding-console-worker.js +101 -41
- package/internal/user-bindings.js +10 -2
- package/internal/value-wire.js +101 -71
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +20 -0
- package/internal/worker-repl-realm.js +134 -0
- package/package.json +2 -1
- package/src/client-activity.js +8 -1
package/docs/README.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
## Maintenance
|
|
23
23
|
|
|
24
24
|
- [Deterministic Verification](verification.md): complete checks, backend test concurrency, coverage, and focused diagnostics.
|
|
25
|
+
- [Focused Verification](verification-optimization-work.md): bounded coverage diagnostics and their relationship to the final verification gate.
|
|
25
26
|
- [Semantic Validation](semantic-validation.md): pinned Test262 cases, dialect contracts, native differential matrices and their limits.
|
|
26
27
|
- [Publishing](publishing.md): release checks, package contents, permissions, and platform validation.
|
|
27
28
|
- [Client UI](client-ui.md): current UI boundary and reevaluation criteria.
|
|
@@ -12,9 +12,9 @@ Each entry is a TypeScript module with named value exports, a stable ID, display
|
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Problem
|
|
4
4
|
|
|
5
|
-
|
|
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
|
|
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: ... })`.
|
|
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
|
|
|
@@ -30,8 +30,8 @@ The helper answers an on-demand utilization-sample request from its own loop, an
|
|
|
30
30
|
|
|
31
31
|
## Consequences
|
|
32
32
|
|
|
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
|
|
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 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
34
|
|
|
35
35
|
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
36
|
|
|
37
|
-
Environment provenance is
|
|
37
|
+
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.
|
package/docs/architecture.md
CHANGED
|
@@ -13,7 +13,7 @@ PTC Plus 把 DSH PTC 模式的顶层 `run_code` 变成与 session 绑定的连
|
|
|
13
13
|
| Journal / replay | PTC Plus + session log | 记录 call transcript、settlement、completion 和恢复边界 |
|
|
14
14
|
| Presentation | DSH + PTC Plus | 保留 native guidance,并追加 REPL 指引与最小 explorer 声明 |
|
|
15
15
|
|
|
16
|
-
求值层由插件自有的 helper 进程承载:Host 只持有 `IsolatedWorker` transport,真实 `node:worker_threads` session worker 与其私有 `MessagePort` 都留在 helper 内,IPC 只传输 plain data。宿主回收卡住的计算时只强杀自己的 helper process
|
|
16
|
+
求值层由插件自有的 helper 进程承载:Host 只持有 `IsolatedWorker` transport,真实 `node:worker_threads` session worker 与其私有 `MessagePort` 都留在 helper 内,IPC 只传输 plain data。宿主回收卡住的计算时只强杀自己的 helper process,DSH 进程内没有需要终止的 session worker,因此不会触达已测得会落入 Node 24/26 cppgc teardown fault 的 in-host worker 强杀路径;`IsolatedOwner` 只在该实例的 real exit、output close 和 cleanup 都完成后释放。kernel、console、candidate 三个入口各自拥有 owner。helper 的 `init` 携带 fork 前 snapshot 的投影环境,user Worker 及其子进程保持原 env 契约,不会继承 `NODE_V8_COVERAGE` 等宿主 instrumentation;Electron Host 只在 helper fork 环境覆盖 `ELECTRON_RUN_AS_NODE=1`,该启动变量不进入 user Worker。inner Worker 的 compute budget 在每次请求提交时通过 helper 的 on-demand sample 取新鲜 `eventLoopUtilization` baseline,ready handshake 另有启动样本;采样失败按 worker-exit 有界失败且不派发 prepare/run。唯一例外由 [ADR 0024](adr/0024-repl-console-observation.md) 所有:同一 worker 已确认存在未完成的 observation 时,prepare 可先于预算启动,确认 observation 完成后才开始计时。
|
|
17
17
|
|
|
18
18
|
主入口接管模型直接发起的顶层 `run_code`,并通过 DSH tool registry 真实注册 `edit_run_code`。
|
|
19
19
|
使用 code-only direct-tool projection 的 PTC request 始终按固定顺序暴露 `[run_code, edit_run_code]`;插件用 agent scope 的
|
|
@@ -64,7 +64,7 @@ Client half 通过宿主当前代的设置座位呈现全部配置:旧代际
|
|
|
64
64
|
|
|
65
65
|
## Global User Bindings
|
|
66
66
|
|
|
67
|
-
`internal/user-bindings.js` 是条目、文档、请求快照和有界声明的严格规范化 owner。它从命名 value export 的 TypeScript 源码派生 symbols、binding kind、body-free declaration、durability 与 fingerprint,并封闭校验所有衍生字段;调用方不能提交一份与源码不一致的声明或 snapshot
|
|
67
|
+
`internal/user-bindings.js` 是条目、文档、请求快照和有界声明的严格规范化 owner。它从命名 value export 的 TypeScript 源码派生 symbols、binding kind、body-free declaration、durability 与 fingerprint,并封闭校验所有衍生字段;调用方不能提交一份与源码不一致的声明或 snapshot。源码声明保留未被遮蔽的环境类型,并收集公开签名引用的本地 interface、type alias 与 class 闭包;各条目使用独立声明 namespace,公开 class shape 包含实例字段与 constructor parameter property。无法形成自足声明的 imported type 在持久化前拒绝,不能静默替换为 `unknown`。`namespace` scope 产生一个条目名对象,`top-level` scope 产生选定导出;保留名称和启用集合中的调用标识符冲突在持久化或请求激活前拒绝。
|
|
68
68
|
|
|
69
69
|
可选 `modelContext` 与源码一起持久化,包含默认开启的接口注入开关 `includeDeclaration` 和独立注入的提示词 `instructions`。声明只有源码派生这一份,不另行编写。非空 metadata 参与条目 fingerprint;旧条目省略该字段时保持原序列化与 fingerprint,存储文档无需迁移。此前保存的 `enabled` / `declaration` 字段保留规范化形式以验证旧 fingerprint,但旧自定义声明不用于展示或注入;旧关闭状态映射为声明关闭、提示词为空,下一次编辑保存使用新字段。Client 安全的结构校验和偏好映射由 `internal/user-binding-model-context.js` 复用,预算和完整 schema 见 [ADR 0023](adr/0023-global-user-bindings.md)。
|
|
70
70
|
|
|
@@ -74,7 +74,9 @@ prompt assembly 为每个 PTC request 取得一次当前启用条目快照,作
|
|
|
74
74
|
|
|
75
75
|
配置段是全局绑定提示词与接口的唯一注入来源,不包含实现源码;成功初始化、session-local shadow 和 worker 重建本身不生成活动公告,也不触发相同配置重发。执行结果与诊断拥有实际行为证据;需要验证可用性时只对已知名称做无副作用观察。历史 `tools:ptc-plus-user-bindings` 活动段保留读取支持,下一次允许且接受的快照撤销旧活动声明一次。`tools:sdk` 与 direct-tool schema 不随条目内容改变。配置 API 不证明当前值,也不延长被 compaction 遮蔽的 session-local 状态。runtime 在 cell preflight 前把期望集合映射到 BindingCatalog,再由 worker 激活:当前覆盖粒度为 `per-name`,同名 session-local binding 只覆盖对应全局名称,同条目的其他名称继续激活;v1-v7 历史 cell 保留整条 entry 退出的旧粒度。条目级失败产生诊断并从该 cell 排除,不阻塞独立代码。失败 initializer 一旦发起 program call,整个 cell 进入 volatile,因此只包含成功条目的结果 snapshot 不会被误作该调用的 cold replay source。
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
每个 session kernel 和 binding workbench 各自使用所在 worker 的原生 Node realm。cell、PTC 管理模块、provided `require` 与 binding module 因而共享 intrinsic identity 和 `globalThis`;用户显式创建的 `node:vm` context 或独立运行时保留自己的 realm。
|
|
78
|
+
|
|
79
|
+
worker 对 namespace 成员和 top-level 导出保留 ECMAScript module live read;对顶层名称的赋值或重声明将该名称转换为 session-local binding,并使该名称在后续全局激活中保持 session-local 覆盖,同一条目的其他名称不受影响;v1-v7 历史 cell 仍按整条来源条目退出。当前 `stateful-module-v2` binding module 通过编译后的 logical-root resolver 取得 program namespace,并为每个 cell 建立绑定原 lease 的 namespace view。`stateful-module-v1` 与 legacy binding module 保留其记录代际的 worker-global bridge。两条路径都使旧 continuation 无法借用后续 cell 的 authority,并在后续 request 反映 namespace 的新增与移除。需要安装历史 bridge 且名称与既有 worker global 冲突时,安装在写入前整体失败,避免覆盖 Node intrinsic 或留下部分 namespace。一个导出闭包一旦可能被普通 session binding 保存,worker 就无法证明其不可达,因此相应 synthetic-module 解析基准与历史 bridge 保守保留到 worker 结束。worker 从未成功暴露过需要 bridge 的条目时,disabled 或 empty activation 不安装 bridge;若本次尝试全部失败,则在执行 cell 前移除本次安装的 bridge。
|
|
78
80
|
|
|
79
81
|
配置段以消息文本直接投递,不进入 system renderer;提示词与声明中的 `{{...}}` 保持字面量,不被解释为宿主变量。投递遵守 runtime-context suppression、取消和步骤准入,解除屏蔽后的下一请求同步当前说明。worker 对同一条目 ID 只比较源码、scope、namespace 调用名和有序导出列表来决定模块复用;模型上下文、purpose 或 top-level 显示名称变化不重置模块状态,也不重复初始化。
|
|
80
82
|
|
|
@@ -143,8 +145,10 @@ cell 的静态 import 与 remote re-export 产生有序 preload,Node 继续拥
|
|
|
143
145
|
|
|
144
146
|
```ts
|
|
145
147
|
{
|
|
146
|
-
version:
|
|
148
|
+
version: 10,
|
|
147
149
|
languageSemantics: "legacy-v1" | "stateful-v1" | "protected-v1",
|
|
150
|
+
moduleTransform: "amaro@1.1.11" | "stateful-module-v1+amaro@1.1.11" |
|
|
151
|
+
"stateful-module-v2+amaro@1.1.11" | "protected-module-v1+amaro@1.1.11",
|
|
148
152
|
bindingPolicy: {
|
|
149
153
|
variableRedeclarations: boolean,
|
|
150
154
|
functionClassRedeclarations: boolean
|
|
@@ -168,7 +172,7 @@ cell 的静态 import 与 remote re-export 产生有序 preload,Node 继续拥
|
|
|
168
172
|
}
|
|
169
173
|
```
|
|
170
174
|
|
|
171
|
-
`languageSemantics`
|
|
175
|
+
`languageSemantics` 选择语言契约,`moduleTransform` 选择确切 parser、compiler 与 lowering generation;两者必须是允许的配对。v1–v8 固定迁移为 legacy transform,v9 按发布时映射恢复,其中 `stateful-v1` 使用 `stateful-module-v1`,不能按当前 transform 重解释。`bindingPolicy`、`rewritePolicy` 与 `moduleSemantics` 保留历史细分契约;新代际从统一策略派生它们,旧代际由冻结编译器消费。`userBindingsFingerprint` 以 `null` 证明不存在 Global User Binding 输入,或以 SHA-256 绑定并行私有快照;声明存在但快照缺失或不一致时,node 形成 unknown boundary。`userBindingsShadowPolicy` 固化该 cell 的 session-local 覆盖粒度,`userBindingNames` 以按名称排序的 `{name, state}` 记录结算时的 provider/local/absent/unknown 事实,因此 cold replay 按历史粒度重放覆盖关系,不从当前实现推断 v1-v7 cell 的整条 entry 语义;provider 事实必须对应并行快照的条目 ID,并覆盖该快照公开的每个名称,否则 node 形成 unknown boundary。`calls` 只保存 global、member、PTC Value Graph 编码的 args/result 或 error,以及 settlement 序号。cold replay 校验调用名称、参数、数量和提交顺序,并按 recorded settlement order 释放 recorded result;不会重新 dispatch program binding 或重做外部 effect。该规则同样适用于 native tools、owner-provided namespace 和 `code.run`,不按名称分支。Cordis 的进程内对象不会因此被宣称已恢复;presentation 可以从已验证 transcript 派生重新检查要求,但不能改变 replay。若基础设施终止时仍有未结算 binding,heap 回滚到 durable frontier,discarded journal 以最先观察到的 `global.member` 保留 possible-effect boundary。effect、completeness 和 source metadata 属于 capability explorer,不伪装成 journal 字段。
|
|
172
176
|
|
|
173
177
|
journal 通过 `run_code.output.presentationMeta` 附着到最终 result,再由 `tools/result` 做两阶段确认。live binding catalog 在 worker 结算时随实际状态更新,下一条排队 cell 使用这份目录准备;journal 确认只推进持久历史,迟到或逆序的确认不能覆盖较新的 live 目录,也不能恢复已重置的状态。缺失、损坏或被替换的 journal 形成 unknown/volatile 边界;未进入 runtime 的 call 由后续 `confirms` 以对应 `tool/call.seq` 证明为 no-op。volatile 源码保留在原 session log,但不参与 cold replay。
|
|
174
178
|
|
package/docs/client-ui.md
CHANGED
|
@@ -93,7 +93,7 @@ PTC session 的头部弹窗在功能启用时增加 Session 与 Global 页签。
|
|
|
93
93
|
|
|
94
94
|
`enhancedToolView` 开启且插件启用时,Client 通过公共 keyed `tool.call.toolview` 注册 `run_code` 与 `edit_run_code`;任一开关关闭时实时 dispose 两个注册,让 owner 恢复 DSH 原生 fallback。这个正文 slot 只依赖 Host 提供的 key、`toolName`、`sessionId`、`useSessions`、运行中/已结算 `block` 与 `inspect` 公共契约。增强行保留 Code / Code edit 标题、可展开的原始源码(`arguments` 与 `argsRaw` 任一公共形态均可读)、结果、可见且可访问的运行/失败/中断状态和 Inspect 入口;在提供时优先使用公共 `DisclosureRow` 与 `CodeBlock`,缺少 `DisclosureRow` 时回退到插件自有行,缺少 `CodeBlock` 时回退为纯文本源码。`DisclosureRow` 路径把运行/失败/中断状态、摘要和已证明的功能标记放进同一行始终可见的单行预览;完成态由标题与摘要表达,运行/失败/中断状态由文字 chip 承担并保持可访问。预览间距由插件自有类对称提供,并按单行内容布局,不依赖 Host primitive 的行内几何;源码、结果和 Inspect 只出现在展开主体。结果内容与原生 ioCard 采用相同的灰色圆角背景(`--dsw-alias-markdown-code-block` 加 12px 圆角与边框),失败态使用错误色文字;代码块的语言/复制栏保持原生 CodeBlock 的常亮可见;`检查调用` 入口采用原生 inspectButton 同款胶囊样式,默认 opacity 0,仅在卡片 `:hover` 或 `:focus-visible` 时淡入(opacity .1s),不触发任何布局位移。窄屏下回退路径的摘要允许换行。
|
|
95
95
|
|
|
96
|
-
功能标记不是计数,也不把“插件已启用”冒充成一次功能收益。Client 只在完整 v1-
|
|
96
|
+
功能标记不是计数,也不把“插件已启用”冒充成一次功能收益。Client 只在完整 v1-v10 journal 和对应附属 metadata 能证明时显示:自动改写 import(附模块名)、自动剥离 export、自动拆分混合重声明(附已有 binding)、带完整 target/derived-run/non-noop/可选恢复边界关系且与调用目标前置条件一致的安全编辑执行、成功的 `code.run`、由 `PTC-R002` 的 `warning/recover/rolled-back` 语义元组证明本次确实发生的持久重放,以及 `repl.state` 操作。Client 对 v4 同时封闭校验 `bindingPolicy`、`rewritePolicy` 与 `moduleSemantics`,对 v5 还要求 `userBindingsFingerprint`,对 v6 进一步要求 `userBindingsReusePolicy` 为 `fingerprint-v1` 或 `implementation-v1`,对 v7 还要求 `moduleSemantics` 携带可识别的 `importExpressionBoundary`(v1-v6 的 `moduleSemantics` 保持只含 `defaultExportBinding` 的封闭字段集),对 v8 还要求 `userBindingsShadowPolicy` 与 `userBindingNames` 通过封闭校验,对 v9 进一步要求已知的 `languageSemantics`,对 v10 还要求 `moduleTransform` 与语言契约匹配;任一缺失或畸形都不产生功能标记。进程保留或 discarded 状态不作为正文功能标记。普通变量或 function/class 重声明、顶层 native 调用是否来自 canonicalizer、`cordis_*` 成员是否由官方可选 Cordis mount 提供,以及是否实际选择了 prompt 恢复提示没有独立的 Client-only 事实,因此不根据可复制的代码形状、工具名前缀或设置默认值推测;恢复边界本身不展示。
|
|
97
97
|
|
|
98
98
|
正文工具行和头部 Session 清单不检查或改写宿主 DOM,不调用 Host、不主动加载历史。头部卡片只展示随结果持久化的名称与定义源码,不使用值预览;全局管理操作单独使用前述管理 Remote。这些展示不改变 canonical result、tool schema、system prompt、runtime context、journal schema 或迁移器,也不向模型公开状态。未知 journal 版本、未知 metadata 字段和损坏 metadata 只会让对应功能标记或 binding 列表缺席,不会隐藏源码或结果;无法脱离 session call identity 解析非空 v1 `confirms` 时同样只省略标记,不触发历史读取或迁移。因此 UI 是否安装、能否渲染以及用户是否悬浮、聚焦或展开正文行,都不会改变模型请求或会话继续语义,也不能作为在模型 surface 收缩后继续保留 runtime binding 的证据。
|
|
99
99
|
|
|
@@ -30,8 +30,10 @@ PTC Plus 的正确承诺是:
|
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
{
|
|
33
|
-
version:
|
|
33
|
+
version: 10,
|
|
34
34
|
languageSemantics: "legacy-v1" | "stateful-v1" | "protected-v1",
|
|
35
|
+
moduleTransform: "amaro@1.1.11" | "stateful-module-v1+amaro@1.1.11" |
|
|
36
|
+
"stateful-module-v2+amaro@1.1.11" | "protected-module-v1+amaro@1.1.11",
|
|
35
37
|
bindingPolicy: {
|
|
36
38
|
variableRedeclarations: boolean,
|
|
37
39
|
functionClassRedeclarations: boolean
|
|
@@ -67,7 +69,8 @@ PTC Plus 的正确承诺是:
|
|
|
67
69
|
字段含义:
|
|
68
70
|
|
|
69
71
|
- `durable`:创建可重放 node,推进 `durableHead`;
|
|
70
|
-
- `languageSemantics
|
|
72
|
+
- `languageSemantics`:固定语言契约;新统一策略选择 `stateful-v1` 或 `protected-v1`,显式旧设置兼容态与 v1–v8 历史使用 `legacy-v1`;
|
|
73
|
+
- `moduleTransform`:固定确切 parser、compiler 与 lowering generation。冷重放直接使用该字段,不从 `languageSemantics` 或当前配置反推;
|
|
71
74
|
- `bindingPolicy`:记录该 cell 实际采用的变量重声明和 function/class 重声明语义;冷重放读取每个 node 的完整记录值,并用它重建 binding 可写性,不读取恢复时的 profile 配置;
|
|
72
75
|
- `rewritePolicy`:记录该 cell 解析和 lowering 时使用的三个 AST rewrite 开关;冷重放读取每个 node 的记录值,不读取恢复时的 profile 配置;
|
|
73
76
|
- `moduleSemantics`:保留旧模块 lowering 的独立代际;`legacy-v1` 按记录值恢复 default binding 与模块引用写入的语句边界。当前 live cell 写入 `live-readonly` 与 `statement-safe`,但新语言的可写 alias、default 关联和提交规则由 `languageSemantics` 决定,不能仅凭历史字段中的 `readonly` 推断当前 binding 不可写;
|
|
@@ -92,7 +95,7 @@ SessionRuntime 创建 kernel 时完全忽略历史 nodes、head、checkpoints
|
|
|
92
95
|
|
|
93
96
|
journal、diagnostic、source、cause、call、operation、completion 和 completion error 都使用封闭字段集合;未知、symbol 或非枚举自有字段会使 journal 无效。capability-call `args`/`value` 与 return completion `value` 都是封闭、规范化的 `ptc-value-graph/v1` envelope。诊断结构、source frame 依赖和稳定代码见[架构说明](architecture.md#journal-与恢复)。
|
|
94
97
|
|
|
95
|
-
当前实现只写入 `version:
|
|
98
|
+
当前实现只写入 `version: 10` schema。v10 必须携带 `languageSemantics` 与匹配的 `moduleTransform`。v1–v8 固定迁移为 `legacy-v1` 和 legacy transform;v9 保留其语言字段,并按该版本发布时的映射补入 transform:`stateful-v1` 使用 `stateful-module-v1`,`protected-v1` 使用 `protected-module-v1`,`legacy-v1` 使用 legacy transform。恢复不能因当前配置或新 lowering 改变隐藏状态([ADR 0025](adr/0025-use-versioned-logical-binding-identities.md))。v1-v9 作为封闭 predecessor 输入规范化为 v10:v1-v3 的旧 `bindingMode` 精确映射到 `bindingPolicy.variableRedeclarations`,而 `functionClassRedeclarations` 固定为 `false`,因为旧 pipeline 不具备该语义;`moduleSemantics.defaultExportBinding` 固定迁移为 `legacy-variable`,使 loose 历史保留旧的可写生成 binding、strict 历史保留旧的 const 行为;v1-v6 的 `moduleSemantics.importExpressionBoundary` 固定迁移为 `legacy`,使历史写入沿用其记录时的语句 lowering,v7 保留自身记录的边界代际。v1 仍使用三个 rewrite 开关全关的历史默认值,并只在 session log 唯一证明 call identity 时迁移字符串 confirmation;v2/v3 保留自身 `rewritePolicy`。v4/v5 保留已有 binding/rewrite/module 语义;v6 与 v7 保留其记录的 `userBindingsReusePolicy`。v1-v4 的 `userBindingsFingerprint` 固定为 `null`,v5 及之后的代际保留自身记录的快照指纹;v1-v5 的 `userBindingsReusePolicy` 固定为 `fingerprint-v1`。v1-v7 的 `userBindingsShadowPolicy` 固定迁移为 `whole-entry`,`userBindingNames` 固定为 `null`,因此历史 node 继续按整条条目退出,只有 v8 起的 cell 使用 `per-name` 名称证据。无法表示为非负 event sequence 的 confirmation 必须形成 unknown boundary 并触发状态收缩。包括 `languageSemantics`、`moduleTransform`、`bindingPolicy`、`rewritePolicy`、`moduleSemantics`、`userBindingsFingerprint`、`userBindingsReusePolicy`、`userBindingsShadowPolicy`、`userBindingNames`、`diagnostics` 在内的当前必需字段缺失或策略未知时 journal 必须失效,否则会削弱最终持久值与 tentative journal 的严格一致性确认;失效 journal 不证明旧 binding,但也不单独成为后续当前调用的 availability gate。profile 后续切换任一 binding 或 AST rewrite 开关只影响新 cell,历史 node 始终按自身记录的 policy、module semantics 与 transform 重放。新旧全局绑定复用策略与覆盖粒度可共存于同一历史,重复规范化不能把旧策略或旧粒度升级为当前值;没有返回值的 completion 不能证明模块内部状态相等。
|
|
96
99
|
|
|
97
100
|
## Capability Call Transcript
|
|
98
101
|
|
package/docs/installation.md
CHANGED
|
@@ -31,7 +31,7 @@ The Client root requires `settingsScope`, `slots`, `locale`, and `connection`. C
|
|
|
31
31
|
Use this form after the selected version is available from the npm registry:
|
|
32
32
|
|
|
33
33
|
```sh
|
|
34
|
-
dsh plugin --profile <profile> add dsh-ptc-plus@0.4.
|
|
34
|
+
dsh plugin --profile <profile> add dsh-ptc-plus@0.4.2
|
|
35
35
|
dsh --profile <profile> --dump-config
|
|
36
36
|
```
|
|
37
37
|
|
|
@@ -68,7 +68,7 @@ pnpm dsh --profile <profile> --dump-config
|
|
|
68
68
|
|
|
69
69
|
```sh
|
|
70
70
|
npm pack
|
|
71
|
-
dsh plugin --profile <profile> add /absolute/path/to/dsh-ptc-plus-0.4.
|
|
71
|
+
dsh plugin --profile <profile> add /absolute/path/to/dsh-ptc-plus-0.4.2.tgz
|
|
72
72
|
dsh --profile <profile> --dump-config
|
|
73
73
|
```
|
|
74
74
|
|
|
@@ -89,7 +89,7 @@ On Windows, `--browser-channel msedge` can use the existing Edge installation. T
|
|
|
89
89
|
|
|
90
90
|
## Isolated latest-DSH development launcher
|
|
91
91
|
|
|
92
|
-
To test this checkout in a separate DSH installation, double-click `scripts\run-dev-dsh.cmd`. It resolves the newest published DSH release by semantic version over all published versions, prereleases included, rather than following a dist-tag that a release can leave behind; it installs that exact version only when the cached version changes, creates the shipped `web` profile inside an isolated `DSH_HOME`, installs this checkout, and starts DSH.
|
|
92
|
+
To test this checkout in a separate DSH installation, double-click `scripts\run-dev-dsh.cmd`. It resolves the newest published DSH release by semantic version over all published versions, prereleases included, rather than following a dist-tag that a release can leave behind; it installs that exact version only when the cached version changes, creates the shipped `web` profile inside an isolated `DSH_HOME`, installs this checkout, and starts DSH. When no port is supplied, the default Web profile reuses its cached loopback port while that port is available; an invalid cache entry or occupied port is replaced with a free port. This keeps browser authentication stable across ordinary restarts without blocking another DSH on port 3080. The launched Host receives a 64 KiB HTTP request-header limit while retaining existing Node options to accommodate development authentication cookies and the combined Client plugin request during Web boot. The launcher does not modify the repository or your normal DSH home.
|
|
93
93
|
|
|
94
94
|
The launcher defaults to `https://registry.npmjs.org/` for version queries, npm installs and DSH's pnpm subprocesses, including the `@deepseek-ai` scope. This avoids mirror synchronization gaps where a new DSH package is available before its dependencies. It prints the selected registry and refreshes version metadata online; an unavailable version query can still reuse the previously cached version. Set `DSH_DEV_REGISTRY` to an absolute HTTP(S) registry URL to select another source explicitly. The choice applies only to the launcher process and its children; npm configuration files and persistent environment settings are unchanged. Other explicitly configured package scopes retain their own registries.
|
|
95
95
|
|
|
@@ -106,7 +106,7 @@ dsh plugin add github:muyuanjin/dsh-ptc-plus#main
|
|
|
106
106
|
dsh --dump-config
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
-
After an npm release, the package spec may instead be `dsh-ptc-plus@0.4.
|
|
109
|
+
After an npm release, the package spec may instead be `dsh-ptc-plus@0.4.2`. For a local package, use its absolute tarball path. Restart DSH Desktop after installation. Linux Desktop is not a current DSH Desktop release target; use DSH CLI/Web on Linux.
|
|
110
110
|
|
|
111
111
|
## Session format upgrades
|
|
112
112
|
|
|
@@ -12,6 +12,8 @@ An import alias follows its module until an actual successful assignment or decl
|
|
|
12
12
|
|
|
13
13
|
New protected modules retain these native protections and the current callable source reflection contract. Their compilation generation is distinct from historical modules, including when a policy change imports the same source again.
|
|
14
14
|
|
|
15
|
+
Each session kernel owns one native Node realm. Cells, PTC-managed modules, the provided `require`, and activated Global User Binding modules execute in that realm, so Node-produced errors use the same intrinsic constructors as cell code and module evaluation observes cell writes to `globalThis`. Node's `useGlobal` REPL bootstrap is internal: its module shortcuts such as `fs`, `child_process`, and `worker_threads` are removed before code runs, and modules remain available only through the managed import and `require` paths. A binding workbench has the same rule inside its own worker; it does not share state or a realm with an Agent session. A user-created `node:vm` context or independent runtime keeps its own realm and intrinsic identities.
|
|
16
|
+
|
|
15
17
|
Every program namespace is leased to one cell. Namespace objects or member functions captured in the REPL expire when that cell ends. A reusable REPL helper must look up the current namespace inside its body. Global User Binding modules use a dynamic bridge: even a module-captured member resolves the current implementation when invoked by a new cell; a removed member fails until it is available again. Continuations retain their originating cell identity and cannot borrow a later cell's lease.
|
|
16
18
|
|
|
17
19
|
For PTC mode requests using the code-only direct-tool projection, PTC Plus presents two tools in stable order: `run_code` and `edit_run_code`. It recognizes the current Host's `tools:ptc-only` owner section and the preceding Host's `tools:code-only` alias, with the current section authoritative if both appear. The latter tool edits the most recent eligible cell visible when the edit call is dispatched, including a cell that completed successfully but needs a small adjustment. That target remains fixed while the call is in flight; later tool settlements cannot retarget it. The edit accepts exactly one atomic `edits` or `regex_edits` array and an optional `expected_target_call_seq` precondition. Invalid, unavailable, or mismatched-target edits return `{ edited: false, reason }` without executing source or consuming the target. `regex_edits[].replacement` is a JavaScript replacement template: captures are referenced as `$1`, `$2`, ... or `$<name>`, a literal dollar sign is written `$$`, and backslash forms such as `\1` are emitted literally rather than resolved as captures. `pattern` values are JavaScript regular-expression sources without delimiters.
|
|
@@ -99,9 +101,11 @@ Cordis Plugins and Runs are process-local. On a resumed agent or after Cordis is
|
|
|
99
101
|
|
|
100
102
|
Each entry has a stable `id`, display `name`, `namespace` or `top-level` scope, selected symbols, one-line purpose, enabled state, and TypeScript source. A namespace name must be a JavaScript identifier; a top-level entry uses its exported symbols as call identifiers and keeps `name` for display. Source must provide named value exports; default exports and re-exports are rejected. An omitted symbol list derives every named value export, while an explicit list limits the exposed API; clearing the Settings symbol field requests fresh derivation from the edited source. The parser derives declaration kinds, parameter and return annotations, bounded inferred types, and model-visible declarations from the selected source exports. A `namespace` entry contributes one object binding under its name, while a `top-level` entry contributes each selected export. Reserved REPL names and duplicate active identifiers fail validation. The document accepts at most 64 entries, 65,536 UTF-16 code units per source, 262,144 across all sources, and 16,384 across active declarations. Mutations validate the complete enabled declaration set before atomic replacement; an externally written document that exceeds the limit is reported as damaged storage and contributes no active entries.
|
|
101
103
|
|
|
104
|
+
The source-derived interface retains unshadowed environment types, such as `AbortSignal`, `Headers`, and `URL`, and includes the referenced closure of local interfaces, type aliases, enums, and classes. Local type names are isolated per entry so two bindings may expose the same name without colliding. Public class instance fields, constructor parameter properties, methods, and accessors appear in the class shape; private, protected, static, and computed members remain hidden. Getter and setter signatures retain their separate read and write types. An imported type that cannot be represented as a self-contained declaration fails validation instead of being replaced with `unknown`; qualified `import('module').Type` references remain explicit.
|
|
105
|
+
|
|
102
106
|
The current enabled snapshot is the desired input for the next cell. The independent binding API catalog represents `tools:ptc-plus-user-binding-defaults` and supplies configured prompts and selected source-derived interfaces from the first permitted request. One header identifies use inside `run_code` and replacement of the previous global binding API reference, followed only by entry labels and selected documentation. It does not prove successful activation. Successful activation, session-local shadowing and worker reconstruction do not themselves append a new binding context. Unchanged documentation is deduplicated against retained model-visible history; changed or compacted-away configuration is supplied again. Historical configuration and `tools:ptc-plus-user-bindings` snapshot sections remain readable and are withdrawn once by the next permitted accepted recovery snapshot; the current API catalog is delivered separately. The stable `tools:sdk` prefix and direct-tool schemas do not change with binding contents. A request-owned program namespace or error class takes precedence over a same-name user entry; that entry produces an activation diagnostic and is omitted from the settled snapshot without blocking independent code. If a failed initializer issued a program call, the cell becomes volatile because the successful-entry snapshot is not complete replay source for that call transcript.
|
|
103
107
|
|
|
104
|
-
Namespace members and top-level exports preserve ECMAScript module live reads until assignment or a permitted redeclaration creates a session-local shadow. A shadow is not written to the global document and suppresses only the shadowed name from subsequent global activation while the entry's other names keep activating; journals migrated from versions 1 through 7 keep their recorded whole-entry suppression. Updates, disablement, and removal affect unshadowed names from the next submitted cell. Entry imports resolve from the directory containing `bindings.json` during both candidate evaluation and session activation, independently of the session cwd.
|
|
108
|
+
Namespace members and top-level exports preserve ECMAScript module live reads until assignment or a permitted redeclaration creates a session-local shadow. A shadow is not written to the global document and suppresses only the shadowed name from subsequent global activation while the entry's other names keep activating; journals migrated from versions 1 through 7 keep their recorded whole-entry suppression. Updates, disablement, and removal affect unshadowed names from the next submitted cell. Entry imports resolve from the directory containing `bindings.json` during both candidate evaluation and session activation, independently of the session cwd. Current binding modules resolve program namespaces through their compiled logical root, with a namespace view bound to the originating cell lease. Historical `stateful-module-v1` and legacy modules retain their recorded worker-global bridge. Both paths expose newly available namespaces on later requests, stop resolving removed namespaces or members, and prevent expired continuations from borrowing a later cell's authority. When a historical bridge would replace an existing worker global, installation fails before changing that global. Once an exported value may have escaped into an ordinary session binding, its synthetic-module resolution base remains available for that worker lifetime; historical modules also retain their installed bridges. 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.
|
|
105
109
|
|
|
106
110
|
The REPL tab and Settings management modal share a workbench for source editing, validation, declaration preview, revision-checked persistence, import of a local `.ts` file as a disabled entry, enablement, removal, and code execution. The code console evaluates the current unsaved source draft in a separate bounded Node REPL worker hosted by the plugin-owned helper process. Named exports can be called directly from TypeScript commands, with top-level `await` and variables retained across executions. It does not access the Agent session kernel or enter its journal. The compatible `run` RPC separately provides single-use candidate evaluation with an optional exported-function name and JSON argument array. Both execution paths retain DSH process authority: source and imports may create irreversible Node/OS effects before cancellation, timeout, or failure. Console controls and resource limits are documented in [Client UI](client-ui.md#全局用户-binding-工作台).
|
|
107
111
|
|
|
@@ -77,10 +77,10 @@ C1–C6 共同约束结果。“没有错误”不能通过破坏 C2/C3/C4/C5
|
|
|
77
77
|
| --- | --- |
|
|
78
78
|
| run_code、edit_run_code 的派生执行 | 同一语言入口、状态机制、原始参数与 call identity。 |
|
|
79
79
|
| 同 cell、跨 cell、函数、块、参数、catch、switch、循环、类初始化 | 全部声明命名空间归一化,保留各自 scope 和 activation。 |
|
|
80
|
-
| 用户绑定 initializer、候选、工作台及插件创建的 worker/bootstrap | 通过 PTC Plus 编译与状态契约适配,拥有独立 root
|
|
80
|
+
| 用户绑定 initializer、候选、工作台及插件创建的 worker/bootstrap | 通过 PTC Plus 编译与状态契约适配,拥有独立 root 和生命周期;同一 worker 内的 REPL 与 Node 模块共享原生 realm。 |
|
|
81
81
|
| 用户主动调用的 eval、Function 家族及其 alias、原型构造器、bound callable | 保留原生语法目标、编译错误与效果;适配其所属逻辑环境和源码反射,具体契约见第 5.7 节。 |
|
|
82
82
|
| 用户自行创建的 vm、新 realm、native addon 或外部引擎 | 保留该引擎的原生编译与所属环境,不把独立环境映射到调用者的会话 root,也不声称 module hook 接管了这些编译器。 |
|
|
83
|
-
| PTC Plus 自有模块加载(静态/动态/data URL、ESM/CJS) | 在 PTC
|
|
83
|
+
| PTC Plus 自有模块加载(静态/动态/data URL、ESM/CJS) | 在 PTC 执行环境内统一接入;与 cell 共享 worker 的 intrinsic identity 和 `globalThis`,不修改磁盘模块或安装包。模块内的 eval/Function 同样保持所属逻辑环境。 |
|
|
84
84
|
| 插件自有子计算、用户绑定 initializer、候选与工作台 | 编译契约一致,状态、权限与生命周期各自独立。 |
|
|
85
85
|
| 失败继续、配置切换、cold replay、模型可见状态收缩 | 实际状态与证据一致,不留下永久占位、混用语义或未知历史门禁。 |
|
|
86
86
|
|
|
@@ -382,6 +382,10 @@ C1/C6 要求扫描所有声明命名空间,不能只处理普通 lexical;C3
|
|
|
382
382
|
|
|
383
383
|
namespace 形式只有一个公开 namespace 名称,覆盖该名称自然替换整个 namespace 入口。对象成员修改按对象契约处理,不自动扩大成全局配置更新。
|
|
384
384
|
|
|
385
|
+
当前 binding module 通过编译后的 logical-root resolver 取得 request program namespace,并为每个 cell 使用绑定原 lease 的 namespace view。记录为 `stateful-module-v1` 或 legacy transform 的历史模块继续使用其 worker-global bridge;恢复必须按 snapshot transform 选择路径。两条路径都不能让过期 continuation 借用后续 cell 的 request authority。
|
|
386
|
+
|
|
387
|
+
模型可见接口由绑定源码派生。公开签名保留未被源码遮蔽的环境类型,并携带引用到的本地 interface、type alias、enum 与 class 声明闭包;每个条目的本地类型位于独立声明 namespace。class shape 包含公开实例字段、constructor parameter property、方法和访问器,并分别保留 getter 与 setter 的读写类型。无法形成自足接口的 imported type 必须在持久化前给出诊断,不能退化为 `unknown`。
|
|
388
|
+
|
|
385
389
|
整条目遮蔽是需要改变的旧语义,见 [ADR 0023](adr/0023-global-user-bindings.md);当前代际的新 cell 已按名称粒度记录覆盖/来源事实。新代际应记录 entry 级激活证据和 name 级覆盖/来源证据,旧 journal 仍保留当时的整条目行为。新代际中条目更新、禁用或删除不得抹去已经明确形成的会话覆盖;未覆盖名称按条目生命周期调整,旧闭包实际持有的值按引用生命周期保留。
|
|
386
390
|
|
|
387
391
|
这不会给模型新增写全局存储、启停条目或执行用户候选的管理权限,也不会把 session runtime value 自动转成持久源码。
|
|
@@ -478,7 +482,7 @@ cell 使用公开 Node 编译能力创建与当前 context 对齐的 async body
|
|
|
478
482
|
| --- | --- |
|
|
479
483
|
| run_code / edit_run_code | 同一 preparation 与 CompiledUnit;保留原始参数、派生关系、call identity 和 cell lease。 |
|
|
480
484
|
| code.run、插件子 worker | bootstrap 安装编译器,拥有独立 root;父子状态与原有能力关系不变。 |
|
|
481
|
-
| 用户绑定 initializer、候选、工作台 | 在类型变换和 native 编译之前接入;工作台独立状态,不写 Agent journal。 |
|
|
485
|
+
| 用户绑定 initializer、候选、工作台 | 在类型变换和 native 编译之前接入;工作台独立状态,不写 Agent journal;其 REPL 与模块共享所在 worker 的原生 realm。 |
|
|
482
486
|
| eval、Function 家族及其间接调用 | 动态环境 owner 保留所属逻辑环境、原生语法目标、转换次序与反射;不把普通同名函数当作原生编译器。 |
|
|
483
487
|
| 用户自行创建的 vm、new realm、native addon 或外部引擎 | 使用独立引擎的原生编译和环境;不继承 PTC 会话 root。 |
|
|
484
488
|
|
|
@@ -622,7 +626,7 @@ C2/C3/C4 要求分别描述:
|
|
|
622
626
|
|
|
623
627
|
### 8.4 journal 代际与旧代码
|
|
624
628
|
|
|
625
|
-
当前封闭 schema 的版本常量与字段集由 [session-journal-schema.js](../internal/session-journal-schema.js) 拥有,JOURNAL_VERSION 为
|
|
629
|
+
当前封闭 schema 的版本常量与字段集由 [session-journal-schema.js](../internal/session-journal-schema.js) 拥有,JOURNAL_VERSION 为 10;schema 包含 languageSemantics、精确的 moduleTransform、bindingPolicy、rewritePolicy、moduleSemantics(含 `importExpressionBoundary`)、userBindingsFingerprint、userBindingsReusePolicy、userBindingsShadowPolicy 与 userBindingNames 等字段。字段校验、journal 创建与旧代际迁移由 [session-journal.js](../internal/session-journal.js) 拥有,事件关联与折叠恢复由 [session-journal-recovery.js](../internal/session-journal-recovery.js) 拥有。旧 ADR 描述其决策发生时的版本,不能用历史版本叙述替代当前 schema 事实。
|
|
626
630
|
|
|
627
631
|
新代际必须区分:所有作用域可写规则、裸声明、声明 pattern 提交、import/default 来源关联、特殊命名空间、动态 grammar goal、独立单元、name 级用户绑定覆盖和实际操作证据。只重解释原有两个布尔值无法表达这些变化。
|
|
628
632
|
|
package/docs/user-bindings.en.md
CHANGED
|
@@ -6,7 +6,7 @@ Global bindings save reusable TypeScript helpers for use across sessions. For ex
|
|
|
6
6
|
|
|
7
7
|
## Create and use a binding
|
|
8
8
|
|
|
9
|
-
1. Open PTC Plus settings (when the sparkle shortcut is already present, choose **PTC Plus settings** from its menu; the
|
|
9
|
+
1. Open PTC Plus settings (when the sparkle shortcut is already present, choose **PTC Plus settings** from its menu; depending on the DSH interface, you can also find the plugin on the side-bar **Plugins** page and choose **Configure**, or open **Settings → Plugin configuration → PTC Plus**) and enable **Global User Bindings**.
|
|
10
10
|
2. In a PTC session, open the sparkle menu by the composer and choose **Write a new binding**, or enter `/binding new <requirement>`.
|
|
11
11
|
3. Inspect the draft's source, interface, and model prompt in the panel above the composer.
|
|
12
12
|
4. Choose **Save and enable**. Subsequent `run_code` calls load the binding; initialization failures appear in execution results.
|
|
@@ -26,7 +26,7 @@ A new draft opens above the composer. Click the title bar or use Enter/Space to
|
|
|
26
26
|
|
|
27
27
|
The sparkle button shows a PTC Plus tooltip on hover or focus that names it as the Global User Binding entry; a pending draft changes the tooltip to the draft state. The button shows a badge for pending drafts. Open its menu by hovering, clicking, or using the keyboard, then select the draft to show it again. Each session retains one current candidate. A confirmed save or discard closes the panel; failures leave the draft available for retry.
|
|
28
28
|
|
|
29
|
-
The sparkle menu is available before the first message
|
|
29
|
+
The sparkle menu is available before the first message and opens once the pointer dwells on the entry; incidental pointer movement across the composer leaves it closed. A hovered menu closes as soon as the pointer leaves it; clicking keeps it open until you click again, click elsewhere, or press Escape. Global bindings show their names, purposes, and enabled states using text and a checkmark. Click an entry to toggle it for all sessions. The catalog refreshes in the background, and the entries stay usable while it does; toggles are disabled only while saving, and reload after a conflict or failure before trying again. **Manage global bindings** opens the full workbench. **Write a new binding** and **Revise a binding** appear when the authoring command is available; the revision step lists existing entries and prefills `/binding edit <id> `. The reusable REPL binding list shows how many later cells reused each binding, with the total in the section title; the count comes from static references in each later cell's compiled source, and a redeclaration counts as neither a reuse nor a reset of the accumulated count.
|
|
30
30
|
|
|
31
31
|
The original binding request retains its requirement, status, and accepted source in history. Historical inspection does not restore permission to save that draft. When another edit changes the catalog, reload its current state before deciding whether to save.
|
|
32
32
|
|
|
@@ -36,11 +36,13 @@ Each entry has two independent settings:
|
|
|
36
36
|
|
|
37
37
|
| Setting | Purpose |
|
|
38
38
|
| --- | --- |
|
|
39
|
-
| Include interface declaration for the model | On by default. Names, parameters, return types, and API comments come from source; no separate declaration is needed |
|
|
39
|
+
| Include interface declaration for the model | On by default. Names, parameters, return types, related types, and API comments come from source; no separate declaration is needed |
|
|
40
40
|
| Prompt for the model | Optional. Add usage conditions, input constraints, or examples missing from the types |
|
|
41
41
|
|
|
42
42
|
For example, a size formatter might add: “Input is in bytes; display using IEC units.” Usage already clear from the interface need not be repeated.
|
|
43
43
|
|
|
44
|
+
The interface retains standard global types used by public signatures and includes the referenced local `interface`, `type`, `enum`, and `class` declarations. A class interface includes public instance fields, parameter properties, methods, accessors, and any self-contained heritage chain while omitting private, protected, and static members; abstract classes keep an abstract construct signature, and same-named local types from different entries remain isolated. An `import('package').Type` reference can be retained. A type or base class that cannot be represented without its source import produces an error before save instead of silently becoming `unknown`.
|
|
45
|
+
|
|
44
46
|
The model receives one line identifying `run_code` and the updated API reference, followed by entry names, configured prompts and selected interfaces. Ordinary calls do not resend unchanged documentation.
|
|
45
47
|
|
|
46
48
|
Omitting the interface leaves a separate prompt available. Omitting both does not disable execution. Enabled entries are described from the first request in a new session. Saving, enabling, disabling, deleting, or editing an entry updates the next permitted request. DSH runtime-context suppression defers delivery.
|
package/docs/user-bindings.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## 创建和使用
|
|
8
8
|
|
|
9
|
-
1. 打开 PTC Plus 设置(已有星光入口时可直接选择菜单中的 **PTC Plus
|
|
9
|
+
1. 打开 PTC Plus 设置(已有星光入口时可直接选择菜单中的 **PTC Plus 设置**;根据 DSH 界面,也可以在侧栏 **Plugins** 页面找到本插件并点 **Configure**,或打开 **设置 → 插件配置 → PTC Plus**),开启“全局用户绑定”。
|
|
10
10
|
2. 在 PTC 会话中打开输入框星光按钮的菜单,选择“编写新绑定”,或输入 `/binding new <需求>`。
|
|
11
11
|
3. 等待 Agent 提交草稿,在输入框上方检查源码、接口和给模型的提示词。
|
|
12
12
|
4. 选择“保存并启用”。后续 `run_code` 会加载该绑定;如果初始化失败,执行结果会说明原因。
|
|
@@ -36,11 +36,13 @@
|
|
|
36
36
|
|
|
37
37
|
| 设置 | 用途 |
|
|
38
38
|
| --- | --- |
|
|
39
|
-
| 将接口声明提供给模型 |
|
|
39
|
+
| 将接口声明提供给模型 | 默认开启。从源码生成名称、参数、返回类型、相关类型和 API 注释,无需另写声明 |
|
|
40
40
|
| 给模型的提示词 | 可留空。补充类型未表达的使用时机、输入约束或示例 |
|
|
41
41
|
|
|
42
42
|
例如,一个接受字节数的格式化函数可补充:“输入单位为字节,显示时使用 IEC 单位。”函数签名已经清楚的用法无需再写一遍。
|
|
43
43
|
|
|
44
|
+
接口会保留公开签名使用的标准全局类型,并带上实际引用的本地 `interface`、`type`、`enum` 和 `class`。类接口包含公开实例字段、参数属性、方法、访问器和可自包含表示的继承链,不暴露 private、protected 或 static 成员;抽象类仍以抽象构造签名公开,不能被模型当作普通构造器,不同条目中的同名本地类型彼此隔离。`import('package').Type` 形式可以保留,无法脱离源码 import 独立表示的类型或基类会在保存前给出错误,不会静默改成 `unknown`。
|
|
45
|
+
|
|
44
46
|
模型收到一行 `run_code` 调用位置和接口参考文档更新说明,以及各条目的名称、已配置提示词和所选接口。内容未变时不会因普通调用重复发送。
|
|
45
47
|
|
|
46
48
|
关闭接口展示不会关闭独立提示词;两者都省略也不会禁用绑定执行。已启用条目的说明在新会话首轮提供,中途保存、启停、删除或修改后在下一次允许的请求中更新。若 DSH 暂停运行时上下文投递,更新会暂缓。
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Focused Verification
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`npm run coverage:focus` provides a bounded diagnostic loop for executable
|
|
6
|
+
changes. It checks selected gate-owned sources with the smallest test set that
|
|
7
|
+
can distinguish a correction before the repository-wide release gate runs.
|
|
8
|
+
|
|
9
|
+
The focused command does not replace `npm run verify` or `npm run check` and
|
|
10
|
+
does not write a verified-tree proof. [Deterministic verification](verification.md)
|
|
11
|
+
owns command syntax, thresholds, generated evidence, and the final gate.
|
|
12
|
+
|
|
13
|
+
## Contract
|
|
14
|
+
|
|
15
|
+
- Every selected source and test must exist inside the checkout.
|
|
16
|
+
- Selected sources must belong to the full coverage gate, and selected tests
|
|
17
|
+
must be `test/*.test.js` files.
|
|
18
|
+
- Selected but unexecuted sources remain in the report as uncovered.
|
|
19
|
+
- The report applies the full gate's 100% line/function and 95% branch
|
|
20
|
+
thresholds.
|
|
21
|
+
- Compiler bytecode preparation, mock-dependent grouping, real Worker
|
|
22
|
+
instrumentation, source-map filtering, TAP diagnostics, and isolated
|
|
23
|
+
coverage collection match the full coverage runner.
|
|
24
|
+
- Node test options may follow a standalone `--` after the focused source and
|
|
25
|
+
test selections.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
Use focused coverage after the nearest behavioral test passes or after a full
|
|
30
|
+
gate identifies a narrow coverage deficit. Select every changed source whose
|
|
31
|
+
threshold matters and the tests that exercise its distinct paths. A passing
|
|
32
|
+
focused run establishes only that selected relation.
|
|
33
|
+
|
|
34
|
+
Run one final `npm run verify` while the local review ledger has unresolved
|
|
35
|
+
findings. Once every finding is terminal, run `npm run check` on a stable tree
|
|
36
|
+
to produce the proof consumed by the commit hook. Do not run `verify`
|
|
37
|
+
immediately before `check` on the same tree because `check` already invokes it.
|
|
38
|
+
|
|
39
|
+
Temporary concurrency overrides change scheduling only. Use one only when
|
|
40
|
+
current evidence identifies scheduling contention, and do not carry it into a
|
|
41
|
+
later run without that condition.
|
package/docs/verification.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
Both commands validate the ledger, compare generated bundles, check syntax, run Client tests, and run all backend tests with coverage. Backend test files run in separate Node processes. The default process count is half the available CPUs, rounded down and bounded between one and four; each process can also own runtime Workers. Tests within each file retain their existing ordering. Coverage still requires 100% lines and functions and at least 95% branches, including compiler source remapping.
|
|
6
6
|
|
|
7
|
+
Use focused coverage while developing or after a full gate identifies a narrow coverage failure. Select every source whose threshold matters and the smallest test set that can distinguish the correction:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run coverage:focus -- \
|
|
11
|
+
--source internal/source-position-map.js \
|
|
12
|
+
--test test/source-position-map.test.js \
|
|
13
|
+
--test test/compiler-memory-facts.test.js \
|
|
14
|
+
--test test/stateful-source-line-mapping.test.js
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Repeat `--source` and `--test` as needed. Paths must exist inside the checkout; sources must belong to the full coverage gate, and tests must be `test/*.test.js` files. Arguments after a standalone `--` are forwarded as Node test options. The focused runner uses the same compiler bytecode preparation, mock-dependent grouping, real Worker coverage instrumentation, source-map filtering, and 100% line/function plus 95% branch thresholds as the full runner. It includes selected but unexecuted sources as uncovered, so an empty report cannot pass. Its evidence and retained TAP diagnostics use the ignored `coverage/` directory.
|
|
18
|
+
|
|
19
|
+
Focused coverage establishes only the selected source-and-test relation. It does not establish full-suite compatibility and never replaces the final `verify` or `check`. A failed full gate must be diagnosed with the smallest check that reproduces its failure before another full run. Because `check` already invokes `verify`, running both consecutively against an unchanged tree repeats the full suite without adding evidence.
|
|
20
|
+
|
|
7
21
|
Source fingerprints use Git with temporary administrative files, an index and an object directory. Configuration includes and repository attributes preserve canonical content, and newly computed objects stay in the temporary directory. One tagged file inventory identifies tracked, missing, untracked and sparse entries without repeatedly starting Git for each category. The temporary files are written directly, avoiding repeated Git initialization and configuration processes; explicit Git command arguments preserve isolation across Windows/WSL command forwarders.
|
|
8
22
|
|
|
9
23
|
Set `DSH_PTC_TEST_CONCURRENCY` to a positive integer to override the backend process count. Use `1` for serial diagnosis or when CPU/memory contention affects timing-sensitive tests. This changes scheduling, not runtime compute budgets, test selection, or coverage thresholds. For example:
|
|
@@ -20,7 +34,7 @@ Remove-Item Env:DSH_PTC_TEST_CONCURRENCY
|
|
|
20
34
|
|
|
21
35
|
Coverage runs additionally set `DSH_PTC_TEST_WORKER_COVERAGE=1` and load `scripts/instrument-worker-coverage.mjs` through Node's `--import`; that test-only seam adds the coverage variable to the helper's inner-Worker launch environment so real kernel, console, and candidate worker branches are measured. Production never sets the marker and continues to project `NODE_V8_COVERAGE` out of the user Worker environment. Because some transport tests install module mocks before importing the real transport, the runner executes two backend groups into the same coverage directory: the mock-dependent files run without the preload, and the remaining files run with it. Each group writes its own `run-*-mock.tap` or `run-*-instrumented.tap` diagnostic, both managed by the same retention and cleanup lifecycle. Test arguments such as `--test-name-pattern` are placed before the selected file list so Node applies them to test selection rather than treating them as file inputs.
|
|
22
36
|
|
|
23
|
-
`npm run coverage`
|
|
37
|
+
`npm run coverage` and `npm run coverage:focus` print their current stage and total elapsed time. Each invocation collects worker coverage in its own temporary directory under `coverage/`, removed after c8 finishes reporting, so simultaneous runs cannot erase or combine each other's evidence. The default report is printed to the terminal. A separate `coverage/run-*.tap` log retains Node's test diagnostics, including process exit codes and signals that the concise terminal reporter can omit. An explicit Node test reporter option replaces these default reporters. Source changes during verification still invalidate a `check` proof; separate coverage directories do not make concurrent source edits safe.
|
|
24
38
|
|
|
25
39
|
Windows Node 24 and 26 reproductions and stacks identify a cppgc finalizer (`node::contextify::ContextifyScript`, or `ContextifyContext` when coverage was enabled) running after the environment that owned its private realm was gone, which wrote through a dangling `node::Realm` during isolate teardown. The reproduction ended the whole DSH process when an in-host session worker was terminated; macOS runners also observed whole-file aborts under coverage, but the available evidence does not establish that those aborts came from the same Windows stack or that the same cause applies across platforms. The session kernel now runs in a plugin-owned helper process (`internal/kernel-child.js`); `IsolatedWorker` sends a cooperative shutdown and, if the helper does not leave within its bound, kills only that helper. DSH is no longer the worker-teardown target on any supported host, so a wedged kernel is contained as a helper failure rather than a host-native crash. `.github/workflows/ci.yml` sets `DSH_PTC_TEST_CONCURRENCY: 1` and runs `npm run check` once; the former file-level retry wrapper is gone, and any failing test or file-level abort fails that run. This boundary removes the plugin's in-host kill exposure; it neither repairs the upstream Node path nor proves the macOS abort shared the Windows cause.
|
|
26
40
|
|