dsh-completion-guard 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/CHANGELOG.zh-CN.md +42 -0
- package/README.md +20 -12
- package/README.zh-CN.md +20 -12
- package/bin/dsh-completion-guard-host-lock.mjs +16 -0
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.js +2 -2
- package/dist/{domain-DebMrpyX.js → domain-BqmJLHcu.js} +3835 -1055
- package/dist/{index-BZYtgqlu.d.ts → index-Dcee_NYF.d.ts} +765 -43
- package/dist/index.d.ts +3 -2
- package/dist/index.js +441 -34
- package/docs/ARCHITECTURE.md +29 -2
- package/docs/COMPATIBILITY.md +73 -4
- package/docs/HOST_LOCK_UPGRADE.md +53 -5
- package/docs/LOCAL_ACCEPTANCE.md +10 -2
- package/docs/PORTING_NOTES.md +22 -0
- package/docs/SEMANTIC_COMPATIBILITY.md +24 -0
- package/docs/upstream-deltas.json +30 -4
- package/manifests/supported-host.v1.json +173 -578
- package/package.json +34 -31
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -20,10 +20,33 @@ The effective plugin configuration and the DSH Session append-only log are the i
|
|
|
20
20
|
- effective plugin configuration — initial enablement (`opt-in` starts disabled; `always` starts enabled before log replay);
|
|
21
21
|
- `command/run` — later enablement (`/context-guard on|off|clear`) and epoch transitions;
|
|
22
22
|
- `user/message` — captured contract clauses;
|
|
23
|
-
- `tool/call` + `tool/result` — bounded evidence and completion-certificate attempts
|
|
23
|
+
- `tool/call` + `tool/result` — bounded evidence and completion-certificate attempts;
|
|
24
|
+
- `tool/ptc-dispatch-start` + `tool/ptc-dispatch` — evidence for sub-calls dispatched from a `run_code` program. These are the current names; the retired `tool/code-dispatch*` vocabulary is ignored and mints nothing;
|
|
25
|
+
- `compaction/summary` — the compaction cut that re-arms the recovery reminder;
|
|
26
|
+
- `goal/change` — the recorded Goal reference, revision, and phase used by the completion gate.
|
|
27
|
+
|
|
28
|
+
Everything else in the DSH log is deliberately ignored. In particular a V3 `system/message` is a plugin-sourced surface node rather than root authority, a compaction checkpoint `user/message` stays plugin context, and `request/header`, `request/context`, `assistant/attempt`, `session/end-seed` and raw `assistant` streams carry no contract state.
|
|
24
29
|
|
|
25
30
|
The in-memory `GuardProjection` is a rebuildable cache: `deriveProjection` applies the effective activation configuration, replays the native log deterministically, recomputes every contract, evidence, and certificate, and flags `corrupt` when a recorded certificate no longer re-derives from the evidence in the log. The projection and its evidence are session-scoped: a new DSH session starts a new projection and cannot import, look up, or certify evidence IDs from another session. A completed workflow that needs a certificate must therefore produce its evidence and call `context_guard_checkpoint` in the same session. Under `always`, replay begins enabled; changing an existing profile from `opt-in` to `always` can therefore bring earlier persisted user messages into the derived contract. A recorded `/context-guard off` disables capture from that point until a later `on`. A recorded `/context-guard clear` supersedes every pending requirement and acceptance under a `CLEAR:<revision>` sentinel (prohibitions are retained) and bumps the contract revision, so a fresh empty-binding checkpoint can certify while the guard stays enabled. Captured contracts always carry a concrete subject/surface, so no unrelated evidence can close a requirement.
|
|
26
31
|
|
|
32
|
+
## Session lifecycle: silent start, first-message activation
|
|
33
|
+
|
|
34
|
+
The runtime separates what it injects from what it certifies. An internal lifecycle phase — `armed` (protection enabled, waiting for the first real root input), `active` (real input entered a step), `disabled` (explicitly off) — expresses the startup strategy only; certification still depends solely on durable events, the current contract, and the evidence chain.
|
|
35
|
+
|
|
36
|
+
Session start (`agent/session-start`) registers tools and the runtime, reads history, and arms recovery for resume/compact. It appends nothing, so a fresh session stays blank (`seq === 0`) and a DSH preset can still be selected while the session is new. The Web surface treats a session as blank until a `turn/start` (server preset lock) and falls back to `seq === 0` for cold list entries; Guard writes no message at T0, so both stay satisfiable. Guard reads history only through the DSH Session V3 `snapshotEvents()` API and refuses a session that does not expose it, so no V2 log can be projected as if it had V3 semantics.
|
|
37
|
+
|
|
38
|
+
At `agent/pre-step` the loop has CLAIMED this step's input but has not persisted it yet. A pure preview reads only the validated claim: under `always`, the first claimed batch that carries a real root user message (non-empty text, or any image/attachment part) injects the `Context Guard protocol boundary: v4.0.0` notice and a compact first-step guidance message ahead of the claimed messages, inside the same step batch. The formal projection never derives from the preview — the boundary and the user message become durable events when the loop appends the batch, and the contract is re-derived from them exactly as from any other log. `opt-in` never auto-injects; delegated/subagent sessions receive no boundary, guidance, or activation (their scope arrives through the parent's delegation prompt). Rejection, cancellation, or a filtered batch injects nothing and retries on the next legal input.
|
|
39
|
+
|
|
40
|
+
Recovery packets keep the existing content-dedup and ride the next entered step. The first 0.5 write into a pre-0.5 session carries the v4 boundary with it — that message is the explicit version cut: obligations and certificates recorded before it keep the frozen 0.4 rules (including exact-shape rebind replay), while later messages use the 0.5 confirmation grammar.
|
|
41
|
+
|
|
42
|
+
## Unified diagnosis and preparation
|
|
43
|
+
|
|
44
|
+
`deriveItemDiagnosis` is the single pure judge shared by checkpoint, recovery, the rebind item query, `context_guard_prepare`, and `/context-guard status`. Per item it reports a task kind (`inquiry`/`action`/`constraint`/…), certification support (`unsupported`/`needs_target`/`needs_evidence`/`unavailable`/`supported`), repairability (agent-repairable, needs user input, unsupported, historical gap, none), the exact missing target fields and evidence facets, and one concrete next action with a resume condition and a stable attempt fingerprint. Inquiries stay captured obligations whose honest next step is to deliver the answer; they are never prescribed a rebind. An effect recorded without its resolution prestate is a historical gap: read back observed state, never re-execute to mint evidence.
|
|
45
|
+
|
|
46
|
+
`context_guard_prepare` is read-only. Before a stateful action it renders the supported command shape from the same audited parser the executor uses, the required resolution/effect/state order, reusable evidence references, the host capability verdict, and the exact missing target fields. It performs no action and never turns a guessed default into user authority.
|
|
47
|
+
|
|
48
|
+
A log-derived retry ledger keys each rejected rebind attempt by its stable inputs and outcome. An identical second attempt returns `unchanged` with the resume condition instead of a fresh rejection; new related evidence, a new root instruction, or a changed target produces a new key and re-opens evaluation.
|
|
49
|
+
|
|
27
50
|
## Synchronization
|
|
28
51
|
|
|
29
52
|
The runtime rebuilds the projection from the log before each step. Before evidence is produced, the runtime awaits `ctx.sessions.flush(session)`; if no durability listener participated, evidence is marked `durability-unknown`, which fails closed.
|
|
@@ -53,7 +76,11 @@ A legal plugin `user/message` notice marks the 0.4.2 capture boundary. Earlier e
|
|
|
53
76
|
|
|
54
77
|
`context_guard_rebind` accepts `operation: propose|query|withdraw`, `item_id`, `proposal_id`, `clauses`, and optional `clarification_item_ids`. It has no model confirmation flag. A proposal's 1–8 clauses must concatenate to the complete original normalized text, and its serialized body must fit 8 KiB. Each clarification ID is either empty (keep the source clause) or names a later pending direct-root item that explicitly includes that clause and preserves captured identities and method constraints. The proposal records both root sources, item/revision identities, session, epoch, contract revision, candidate action/target/acceptance, and a digest. A GUI clause cannot be mapped to an installation-only result.
|
|
55
78
|
|
|
56
|
-
The tool returns a candidate without mutating the projection. A matching durable tool result registers the proposal on replay.
|
|
79
|
+
The tool returns a candidate without mutating the projection. A matching durable tool result registers the proposal on replay. Replay validation is versioned: 0.5-era results match on structured semantic fields (status, reason code, proposal identity and digest) while display text may evolve; results carrying the frozen 0.4 response shapes validate byte-for-byte against the frozen 0.4 rules. Anything else is tampered or unknown and never replays.
|
|
80
|
+
|
|
81
|
+
A proposal that would keep every clause at `generic_run` when the original is already `generic_run` is refused as `no_certification_gain`: it would spend a user confirmation without improving certification. Partition mismatches return the bounded exact source (text, length, digest) instead of a generic error.
|
|
82
|
+
|
|
83
|
+
Since 0.5.0 a durable root message is one atomic confirmation transaction. The first non-empty top-level line may be the control line `确认重绑定 <proposal ID>`; the confirmation validates against the state BEFORE that message, and the remaining lines keep their own semantics — an explanation request stays conversational, a new task is captured like any other instruction, and an explicit reversal ("先不要确认") makes the whole message ambiguous and unapplied. A control string buried in a sentence, inside quotes, or inside a code block is malformed and never confirms; a matching control line that is not in first position, or two control lines, is ambiguous with no partial effect. Confirmation rechecks the proposal against the current contract; changed, withdrawn, cross-session, or non-durable inputs keep the old item pending, and a matching confirmation observed in a not-yet-durable log is reported as `not_durable` — distinguishable from one that was never sent. Every child is constructed before the original is marked superseded. `supersededByItems` preserves the one-to-many relation, and `reboundFrom` preserves the proposal and confirmation source. A later root clarification keeps its own authority; partitioning alone cannot authorize a new mutation. Duplicate confirmation is idempotent.
|
|
57
84
|
|
|
58
85
|
No digest-v3 wire format or upstream fixture changes are needed. A replacement changes the item/status set and contract revision, invalidating the earlier certificate; evidence is never copied into a passed state. A fresh checkpoint must revalidate the exact action, target, executor, host lock, and transition. Evidence predating the authoritative root clause referenced by a replacement is rejected while retaining its historical ID.
|
|
59
86
|
|
package/docs/COMPATIBILITY.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
Compatibility is pinned to exact host package sets. A nearby version or a partial package match is not treated as supported.
|
|
4
4
|
|
|
5
|
+
## 0.5.1 support policy
|
|
6
|
+
|
|
7
|
+
Version 0.5.1 supports **DSH >= 0.1.5-rc.1** and nothing older. There is no
|
|
8
|
+
backward compatibility: the previous Session V2 API, the V2 event vocabulary,
|
|
9
|
+
and every older host cohort were removed rather than kept behind a fallback.
|
|
10
|
+
`0.1.5-rc.1` is the version this release was implemented and tested against; it
|
|
11
|
+
is the baseline, not a ceiling.
|
|
12
|
+
|
|
13
|
+
Two separate judgments decide whether a host is usable, and neither replaces the
|
|
14
|
+
other:
|
|
15
|
+
|
|
16
|
+
1. **Version policy** — `src/domain/host-version.ts` orders host versions with
|
|
17
|
+
the SemVer prerelease rules. `peerDependencies` publish the range
|
|
18
|
+
`>=0.1.5-rc.1`; because a range cannot express "every future prerelease at
|
|
19
|
+
any base", the range is the conservative install-time statement and the
|
|
20
|
+
module is the explicit decision path. `0.1.4` and `0.1.5-alpha.9` are
|
|
21
|
+
refused. `0.1.6-rc.1` and `0.2.0-rc.1` order above the bound but do not
|
|
22
|
+
resolve from the published range and are not registered cohorts.
|
|
23
|
+
2. **Host identity** — the exact 33-row DSH core graph must match one registered
|
|
24
|
+
cohort row for row. A newer host that has not been registered is reported as
|
|
25
|
+
unverified, never as supported: the version range alone never admits a graph.
|
|
26
|
+
|
|
27
|
+
If you are upgrading from a profile that ran DSH 0.1.2-rc.1, start a **new
|
|
28
|
+
session**. Guard does not migrate V2 logs, proposals, or certificates, and old
|
|
29
|
+
user data is never deleted or reinterpreted.
|
|
30
|
+
|
|
31
|
+
### Exact rc.1 and rc.2 host sets
|
|
32
|
+
|
|
33
|
+
The registered cohorts are `dsh-0.1.5-rc.1-core-v1` and `dsh-0.1.5-rc.2-core-v1`. Each contains 33 exact package identities from the corresponding npm release. A complete set must match atomically; mixing rc.1 and rc.2 rows fails closed.
|
|
34
|
+
|
|
35
|
+
Both record `auditProvenance: registry-derived-pending-native-audit`, an empty `auditedPlatforms` list and `acceptedPlatforms` containing `posix` and `windows`. These fields describe the registry source of the shipped graph, not a live acceptance result. The provenance is included in `hostLockDigest`. Native acceptance must be established by a separate annex bound to the exact Guard artifact, host cohort and platform; a host-lock certificate alone is insufficient.
|
|
36
|
+
|
|
37
|
+
Every older cohort — `0.1.1-rc.2`, `0.1.2-alpha.2`, the alpha.2 + dshmarket
|
|
38
|
+
1.39.0 combination, `0.1.2-alpha.3`, and `0.1.2-rc.1` — stays in the shipped
|
|
39
|
+
manifest and source registry as a historical identity so previously accepted
|
|
40
|
+
annexes stay verifiable. An installed runtime built from one of them fails
|
|
41
|
+
closed (`host_lock_version_mismatch`). No floating range and no alpha support is
|
|
42
|
+
claimed.
|
|
43
|
+
|
|
5
44
|
## 0.4.3 core-lock policy
|
|
6
45
|
|
|
7
46
|
`dsh-core/v1` uses manifest version 2 and four exact 33-package DSH core graphs, retaining the previously audited DSH and Cordis versions. Market is not a core row. Its transitive dependencies remain part of active-graph traversal, so replacing or duplicating a core dependency still blocks certification. No floating DSH version range is introduced.
|
|
@@ -28,11 +67,11 @@ DSH is still a developer preview and may make breaking changes. Version 0.4.0 th
|
|
|
28
67
|
- Audited platforms: native macOS/posix runtime, plus the native Windows rc.1 host graph verified on the live Windows host (host-lock inspect/inject, composed-config verify-dump, cold Web boot)
|
|
29
68
|
- Evidence boundary: host-graph audits are source/runtime-level evidence and do not replace the cross-platform exact-artifact acceptance of one frozen package; unregistered host cohorts keep failing closed
|
|
30
69
|
|
|
31
|
-
DSH rc.1 replaces the public `Session.events` getter with `snapshotEvents()` and `eventAt()`. The candidate
|
|
70
|
+
DSH rc.1 replaces the public `Session.events` getter with `snapshotEvents()` and `eventAt()`. The 0.4.1-rc.1 candidate used `snapshotEvents()` when present and retained `events` for older registered cohorts. **Superseded by 0.5.1**, which supports only the Session V3 API and refuses a session that does not expose `snapshotEvents()`; the historical fallback no longer exists in the shipped plugin. The flush path, Goal disarm, and `update_goal` contract noted here still hold.
|
|
32
71
|
|
|
33
72
|
## Upstream adaptation policy
|
|
34
73
|
|
|
35
|
-
Version 0.
|
|
74
|
+
Version 0.5.1 targets DSH >= `0.1.5-rc.1` with `0.1.5-rc.1` as the implemented and tested baseline; alpha releases are observed for trend only and are never adaptation or validation targets. A newer upstream tag does not establish support by itself: support starts when that exact RC or release is added as its own registered cohort with source, CI, and native acceptance. The upstream [tags page](https://github.com/deepseek-ai/deepseek-harness/tags) tracks later releases. The host-side API differences that this adaptation had to absorb are listed in the repository's upstream API audit (`UPSTREAM_API_AUDIT.md` at the repository root), which is a maintainer document and is not part of the published package.
|
|
36
75
|
|
|
37
76
|
## Platform and release evidence
|
|
38
77
|
|
|
@@ -44,9 +83,15 @@ Version 0.4.0 remains frozen on the alpha.3 setup above. Alpha.4 and later alpha
|
|
|
44
83
|
|
|
45
84
|
## Historical compatibility cohorts
|
|
46
85
|
|
|
86
|
+
These are verification records, not support entries. An installed runtime built
|
|
87
|
+
from any of them fails closed under the 0.5.1 policy.
|
|
88
|
+
|
|
47
89
|
- DSH `0.1.1-rc.2` + dshmarket `1.36.0` + Cordis `4.0.1` is a retained, published-line cohort.
|
|
48
90
|
- DSH `0.1.2-alpha.2` + dshmarket `1.38.1` + Cordis `4.0.2` is the published 0.3.2 cohort checked natively on macOS and Windows.
|
|
49
91
|
- DSH `0.1.2-alpha.2` + dshmarket `1.39.0` + Cordis `4.0.2` remains a deterministic compatibility cohort. It is no longer a native 0.4.0 release blocker.
|
|
92
|
+
- DSH `0.1.2-alpha.3` + dshmarket `1.39.0` + Cordis `4.0.2` is the recorded 0.4.0 release baseline.
|
|
93
|
+
- DSH `0.1.2-rc.1` + dshmarket `1.41.0` + Cordis `4.0.2` is the 0.4.1-rc.1 / 0.5.0 cohort, checked natively on macOS and Windows.
|
|
94
|
+
- DSH `0.1.5-rc.1` + Cordis `4.0.2` is the **active** 0.5.1 cohort, with no dshmarket row.
|
|
50
95
|
|
|
51
96
|
## Rejection rules
|
|
52
97
|
|
|
@@ -64,7 +109,7 @@ Market versions do not select a core cohort. Market restart has its own protocol
|
|
|
64
109
|
|
|
65
110
|
The package exposes a named `apply(ctx)` function and a named `inject` array (`['sessions', 'commands']`) with no default export. Its `dsh.bundle.patch` points at `cordis.patch.yml`, which inserts the `context-guard` bundle row.
|
|
66
111
|
|
|
67
|
-
The plugin accepts an `activation` configuration value of `opt-in` or `always`. The default is `opt-in`; `always`
|
|
112
|
+
The plugin accepts an `activation` configuration value of `opt-in` or `always`. The default is `opt-in`; `always` means every session is protected automatically from its first real user message. Since 0.5.0, session start writes nothing into the session log: the versioned protocol boundary and first-step guidance are delivered inside the same step batch as — and ahead of — the first real user message, so a new session stays blank (`seq === 0`) and a DSH preset can be selected before anything is sent. An explicit `off` suppresses `always` in that session until the next `on`. Invalid values fail during plugin configuration instead of silently falling back. A DSH profile can select `always` with an ID-targeted `config` override in its `cordis.patch.yml`; see the README quick start for the complete example.
|
|
68
113
|
|
|
69
114
|
### Host-lock setup
|
|
70
115
|
|
|
@@ -102,7 +147,20 @@ The ordinary runtime packages are host-provided peers:
|
|
|
102
147
|
|
|
103
148
|
Goal support uses two exact optional peers as one capability. `@deepseek-ai/dsh-goal` owns Goal state, while `@deepseek-ai/dsh-tool-goal` owns the audited `update_goal` name, schema, and arguments. Both host-graph rows and the live Goal service and tool must agree. A profile without this complete pair can still load, but Goal-dependent integration stays inactive.
|
|
104
149
|
|
|
105
|
-
|
|
150
|
+
Version 0.5.1 publishes one range per DSH package: `>=0.1.5-rc.1`, with Cordis `^4.0.2` (Cordis is versioned independently and unchanged at `4.0.2`). The range is the floor of the support policy, never a claim that any graph above it works: runtime acceptance still requires an exact injected host lock and atomic selection of one complete registered cohort.
|
|
151
|
+
|
|
152
|
+
Two npm facts are worth stating plainly, because a bare `>=` reads stronger than it is:
|
|
153
|
+
|
|
154
|
+
- A version carrying a prerelease resolves from `>=0.1.5-rc.1` only when its
|
|
155
|
+
`major.minor.patch` tuple is `0.1.5`. So `0.1.5-rc.2` and `0.1.5` resolve,
|
|
156
|
+
while `0.1.6-rc.1` and `0.2.0-rc.1` do not. Later `x.y.z` releases resolve
|
|
157
|
+
normally.
|
|
158
|
+
- The development dependencies pin the exact `0.1.5-rc.1` packages this release
|
|
159
|
+
actually verified, so the tested baseline is recorded even though the peer
|
|
160
|
+
range is wider.
|
|
161
|
+
|
|
162
|
+
Historical peer declarations belong to their own release sections above and are
|
|
163
|
+
not part of the 0.5.1 contract.
|
|
106
164
|
|
|
107
165
|
## Terminal outcome contract
|
|
108
166
|
|
|
@@ -113,6 +171,17 @@ exit; it does not append `[exit code: 0]`. Version 0.1.1 therefore accepts an
|
|
|
113
171
|
unmarked completed foreground `bash` result as successful evidence, matching the
|
|
114
172
|
existing `pwsh` behavior.
|
|
115
173
|
|
|
174
|
+
Version 0.5.1 re-checked that rule against the shipped 0.1.5-rc.1 renderer
|
|
175
|
+
sources. The two session renderers registered by `@deepseek-ai/dsh-base`
|
|
176
|
+
(`dsh-tool-bash`, `dsh-tool-pwsh`) append a marker only for negative facts and
|
|
177
|
+
non-zero exits in both host versions, so an unmarked completed foreground
|
|
178
|
+
result stays a clean success **for those two names under a supported host
|
|
179
|
+
lock**. The out-of-bundle persistent renderer gained two markers in 0.1.5-rc.1 —
|
|
180
|
+
`[Command finished with exit code N]` and `[Command timed out or OOM]` — and
|
|
181
|
+
both are now classified explicitly, so a persistent result is read by its own
|
|
182
|
+
marker instead of falling through to the unmarked rule. That package is not in
|
|
183
|
+
the registered cohort, so such a host also fails the whole graph lock closed.
|
|
184
|
+
|
|
116
185
|
This does not make arbitrary shell text authoritative. A result-level error or
|
|
117
186
|
negative terminal marker wins over output text; background commands remain
|
|
118
187
|
unknown; and the generic `shell` alias remains unknown without an explicit exit
|
|
@@ -29,14 +29,36 @@ GUARD_HOST_LOCK="$DSH_PROFILE_ROOT/node_modules/.bin/dsh-completion-guard-host-l
|
|
|
29
29
|
dsh --profile web --dump-config | "$GUARD_HOST_LOCK" verify-dump --runtime-root "$DSH_RUNTIME_ROOT" --profile-root "$DSH_PROFILE_ROOT" --dump-config -
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
**Run this block after the runtime is already on the target DSH version, not
|
|
33
|
+
before.** `inject` records the absolute runtime and profile roots and binds the
|
|
34
|
+
graph it finds there, and runtime replay re-reads those same roots. Injecting
|
|
35
|
+
against the old runtime therefore writes a lock that describes a graph the new
|
|
36
|
+
runtime no longer has, and it will fail on the next replay. Order: upgrade the
|
|
37
|
+
runtime, restart it, then inspect/inject/verify.
|
|
38
|
+
|
|
39
|
+
`inject` **writes to `<profile>/cordis.patch.yml`** — it replaces or adds Guard's
|
|
40
|
+
managed block in that file. Back the file up first. The same file is the one
|
|
41
|
+
`docs/LOCAL_ACCEPTANCE.md` tells you to preserve.
|
|
42
|
+
|
|
43
|
+
**Read the verdict from the JSON body, not from the exit status.** All three
|
|
44
|
+
commands print a JSON object whose `status` is the verdict — `supported`,
|
|
45
|
+
`unsupported` or `unavailable` — together with `cohort_id`, `host_lock_digest` and
|
|
46
|
+
`audit_provenance`. Note that `inspect`, `inject` and `verify-dump` exit **0** even
|
|
47
|
+
when that status is `unsupported`; only `inspect-graph` exits non-zero on an
|
|
48
|
+
unsupported graph, and only a thrown error produces `status: "unavailable"` with a
|
|
49
|
+
`reason_code` on stderr and exit 1. So a shell check of `$?` alone will not tell
|
|
50
|
+
you whether the graph was accepted.
|
|
51
|
+
|
|
32
52
|
For Headless, use its profile path and `--profile headless`. On Windows, use the
|
|
33
|
-
installed `.cmd` launcher and Windows absolute paths.
|
|
53
|
+
installed `.cmd` launcher and Windows absolute paths. **Windows is accepted for
|
|
54
|
+
evaluation but has not been natively audited for this cohort**, so treat a
|
|
55
|
+
Windows result as unverified until the native gate runs. A strict repeat leaves
|
|
34
56
|
the package and profile contents unchanged. Restarting or enabling a daily
|
|
35
57
|
profile remains a separate user action.
|
|
36
58
|
|
|
37
59
|
## Check a Headless profile before installation
|
|
38
60
|
|
|
39
|
-
A DSH `0.1.
|
|
61
|
+
A DSH `0.1.5-rc.1` Headless profile can have no external dependencies and no private `node_modules` or lockfile. From an accepted package or matching source checkout, `node bin/dsh-completion-guard-host-lock.mjs inspect-graph --runtime-root <runtime> --profile-root <profile>` checks that state without initializing or launching the profile.
|
|
40
62
|
|
|
41
63
|
This narrow case requires exactly the installation-owned `dsh-base` and `dsh-headless` bundles, a complete audited runtime core, and matching bundle versions, package-map origins and patch files. Declared but uninstalled dependencies, partial map/lock pairs, unexplained local modules and foreign parent-module fallbacks are rejected. Existing profiles with both graph files retain their active-importer checks; damaged files are not treated as an empty graph.
|
|
42
64
|
|
|
@@ -49,9 +71,35 @@ source roots, platform/profile kind and the complete 33-row core graph. The
|
|
|
49
71
|
core manifest is version 2. Runtime replay re-reads those graph sources and
|
|
50
72
|
requires the same exact core before using certificate authority.
|
|
51
73
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
Version 0.5.1's active cohort is the DSH `0.1.5-rc.1` core graph, and its rows
|
|
75
|
+
are the exact published npm tarball identities rather than a graph read off a
|
|
76
|
+
running host. The cohort therefore records
|
|
77
|
+
`auditProvenance: registry-derived-pending-native-audit` with an empty
|
|
78
|
+
`auditedPlatforms` list, and that provenance is part of the digest. A lock
|
|
79
|
+
generated from it can certify the bytes, but no certificate may describe it as
|
|
80
|
+
a native pass. Reading the native gate as "not run" is the accurate reading.
|
|
81
|
+
Every successful `inspect`, `inspect-graph`, `inject` and `verify-dump` readback
|
|
82
|
+
prints the same value as `audit_provenance`, next to the cohort id and the
|
|
83
|
+
digest, so you can tell which of the two you are holding without decoding the
|
|
84
|
+
digest. (A failing command prints only a status and a reason code: no cohort was
|
|
85
|
+
resolved, so there is no provenance to report.)
|
|
86
|
+
|
|
87
|
+
**Which failure code you see depends on the lock generation you are holding**, and
|
|
88
|
+
that matters for deciding whether you are migrating or just drifting:
|
|
89
|
+
|
|
90
|
+
- A **pre-0.4.3** lock — no `hostLockPolicy: dsh-core/v1`, or no recorded
|
|
91
|
+
runtime/profile roots — reports `host_lock_migration_required`. Removing its
|
|
92
|
+
market row by hand is not migration. Reinspect, inject and verify the actual
|
|
93
|
+
environment.
|
|
94
|
+
- A **0.4.3-or-later** lock already carries the policy and the roots, so it never
|
|
95
|
+
reports `host_lock_migration_required`. It reports the mismatch instead:
|
|
96
|
+
`host_lock_version_mismatch` when the installed core package versions differ from
|
|
97
|
+
the cohort, or `host_lock_installed_graph_drift` when the re-read graph resolves
|
|
98
|
+
to a different digest than the lock recorded. Both are the expected answers after
|
|
99
|
+
a DSH upgrade, and both are cured by re-running inspect, inject and verify against
|
|
100
|
+
the new runtime rather than by editing the lock.
|
|
101
|
+
|
|
102
|
+
Historical cohorts, requirements and session records
|
|
55
103
|
are retained; old certificates do not become certificates for the new lock.
|
|
56
104
|
The shared digest-v3 encoder and its upstream fixtures are unchanged.
|
|
57
105
|
|
package/docs/LOCAL_ACCEPTANCE.md
CHANGED
|
@@ -2,13 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Each section names its evidence boundary. Deterministic checks, isolated DSH_HOME composition, native-platform lifecycle runs, model sessions, CI, and public release readback are separate claims; none substitutes for another.
|
|
4
4
|
|
|
5
|
+
## 0.5.1 candidate scope
|
|
6
|
+
|
|
7
|
+
The candidate supports exact DSH `0.1.5-rc.1` and `0.1.5-rc.2` core graphs. Development tests retain the rc.1 baseline; rc.2 graph tests additionally reject missing, mixed, forged and unregistered package identities. Dependency-free Headless preflight selects the matching registered cohort and checks its launcher version.
|
|
8
|
+
|
|
9
|
+
Candidate results are recorded outside packaged documents after the source and package bytes are frozen. Require the local deterministic matrix, exact-candidate portability CI, and separate macOS and Windows native annexes for the same frozen tgz. An earlier rc.1 artifact's result does not establish acceptance of an artifact that adds rc.2 support. Real-model behaviour, daily profile adoption and publication remain separate gates.
|
|
10
|
+
|
|
11
|
+
The shipped graphs retain their registry-derived provenance in the host-lock digest. Read a matching native annex for platform acceptance; the provenance field alone establishes neither a native pass nor a failed native run.
|
|
12
|
+
|
|
5
13
|
## Host-bound acceptance for the 0.4.3 line
|
|
6
14
|
|
|
7
15
|
This line separates core and optional-provider acceptance while retaining completion feedback and root-confirmed rebinding. Local regression tests exercise compound capture, source authority, one-to-many replacement, stale/partial replay, target matching, large pages, snapshot changes, small recovery budgets and qualified pending boundaries. Local tests and the existence of a host driver do not establish native DSH acceptance.
|
|
8
16
|
|
|
9
17
|
The versioned entrypoint is `scripts/native_acceptance.py`. Its default `portable_artifact` profile checks exact source/tgz identity, isolated installation, installed-file parity, second-install no-op and JavaScript syntax. `--gate-profile host_bound --runtime-root <audited-runtime>` additionally creates isolated Web and Headless profiles, injects and reads back their host locks, then runs `scripts/native_host_probe.mjs` inside the real DSH composition. The probe uses the host AgentRegistry, ToolRuntime and durable Session services for nonempty test certification, generic refusal, rebind confirmation, history queries, compact/resume and a qualified pending boundary. Web checks require an owned-host restart, a different host process, persisted-session recovery and listener cleanup; they do not depend on a market restart API. The installed launcher shim is checked separately.
|
|
10
18
|
|
|
11
|
-
Supplied daily target paths use the [read-only installation preflight](HOST_LOCK_UPGRADE.md#check-a-headless-profile-before-installation). A dependency-free rc.1 Headless target may have no private map or lockfile; the preflight verifies its installation-owned bundles and labels that state separately. The isolated lifecycle still installs Guard before checking its private graph, lock and second-install no-op. A successful target preflight alone is not a native gate result or proof of live adoption.
|
|
19
|
+
Supplied daily target paths use the [read-only installation preflight](HOST_LOCK_UPGRADE.md#check-a-headless-profile-before-installation). A dependency-free `0.1.5-rc.1` or `0.1.5-rc.2` Headless target may have no private map or lockfile; the preflight verifies its installation-owned bundles and labels that state separately. The isolated lifecycle still installs Guard before checking its private graph, lock and second-install no-op. A successful target preflight alone is not a native gate result or proof of live adoption.
|
|
12
20
|
|
|
13
21
|
The host driver deliberately makes no model request. It first checks that the normal Headless task driver stops with `MISSING_CREDENTIAL` in the isolated environment, then disables that task driver for the separate real-service probe. A required package-update probe installs an inert local fixture at version 1, then clarifies and confirms a generic requirement, applies version 2 through the real producer/action tools, independently reads it back and requires a nonempty certificate. Capability skips appear in the returned annex. Never treat a synthetic test or an empty probe case set as a passed native run.
|
|
14
22
|
|
|
@@ -24,7 +32,7 @@ The driver creates a new temporary DSH_HOME, explicit temporary HOME/USERPROFILE
|
|
|
24
32
|
|
|
25
33
|
The historical 0.4.2 candidate at `6b92b3b7a5eb642686df9f2a1b4d66d54455f503` passed [candidate CI](https://github.com/GreenLv/dsh-completion-guard/actions/runs/34128172642). Its frozen tgz SHA-256 was `9d3e0a0bb948b137f27303a98ad38d3ecc8a901c5c579ce7e3b3c664530c3b4a`. Native macOS and Windows each passed all 28 required host-bound gates, including the normal Headless credential boundary and package-update probe, with cleanup passed. Both annexes retained the `real_model_request` capability skip. These are historical candidate results, not a release or evidence for later package bytes.
|
|
26
34
|
|
|
27
|
-
The core annex uses `native-acceptance/v2`, gate profile `host_bound_core`, and the DSH-specific `capability_skips`, `host_driver_sha256`, `host_lock_digests`, `host_lock_policy` and `market_interface` fields. A generic closed v2 validator correctly rejects those extensions. The historical 0.4.2 `host_bound` annex retains its original `dsh-host-bound/v1` contract; v1 and
|
|
35
|
+
The core annex uses `native-acceptance/v2`, gate profile `host_bound_core`, and the DSH-specific `capability_skips`, `host_driver_sha256`, `host_lock_digests`, `host_lock_policy` and `market_interface` fields. A generic closed v2 validator correctly rejects those extensions. The historical 0.4.2 `host_bound` annex retains its original `dsh-host-bound/v1` contract; the historical v1/v2 profiles and the current v3 profile are not interchangeable. A consumer that provides the explicit `dsh-host-bound/v3` contract profile must validate the original annex with independently supplied expected commit, artifact SHA-256, and probe SHA-256; do not remove fields to make it pass. `host_driver_sha256` identifies `native_host_probe.mjs`, not the Python wrapper. Windows checkout CRLF bytes can produce a different probe hash from macOS LF bytes; bind each platform to its actual reviewed file bytes. Failed probe annexes may additionally contain bounded `host_probe_failures` diagnostics. The profile consumer is separate tooling and is not installed by this npm package.
|
|
28
36
|
|
|
29
37
|
Every subsequent frozen package needs its own CI and same-byte native annexes, recorded outside its packaged documentation. Publication and public readback are separate gates. A disabled daily installation remains disabled until the user separately requests an upgrade and enablement.
|
|
30
38
|
|
package/docs/PORTING_NOTES.md
CHANGED
|
@@ -15,6 +15,28 @@ fixtures and an explicit delta ledger.
|
|
|
15
15
|
| portable protocol and digest fixtures | Mirror exact upstream bytes and verify their hashes |
|
|
16
16
|
| product-specific or newer Codex behavior | Record explicitly in the delta ledger before porting |
|
|
17
17
|
|
|
18
|
+
## Current host boundary (0.5.1)
|
|
19
|
+
|
|
20
|
+
Version 0.5.1 ports Guard onto DSH >= 0.1.5-rc.1 and keeps no path back to the
|
|
21
|
+
older host. Concretely:
|
|
22
|
+
|
|
23
|
+
- Session history is read only through the DSH Session V3 `snapshotEvents()`
|
|
24
|
+
API. The V2 `events` getter is gone, and a session that does not expose the
|
|
25
|
+
V3 API is refused instead of being treated as an empty log.
|
|
26
|
+
- Dispatch evidence comes from the current `tool/ptc-dispatch-start` and
|
|
27
|
+
`tool/ptc-dispatch` vocabulary. The retired `tool/code-dispatch*` names are
|
|
28
|
+
ignored, so an old log cannot mint evidence under the new protocol.
|
|
29
|
+
- A V3 `system/message` is a plugin-sourced surface node, never root
|
|
30
|
+
authority, and a compaction checkpoint message stays plugin context.
|
|
31
|
+
- Guard never resumes a Goal the user paused: its Goal access surface has no
|
|
32
|
+
resume entry point, and turn stopping yields while a Goal is paused, blocked,
|
|
33
|
+
completed, or not yet read back.
|
|
34
|
+
|
|
35
|
+
The host identifier is the exact 33-row DSH core graph. The active 0.1.5-rc.1
|
|
36
|
+
cohort is registry-derived with its native audit still pending, and that
|
|
37
|
+
provenance is bound into the host-lock digest rather than inferred from a
|
|
38
|
+
version number.
|
|
39
|
+
|
|
18
40
|
The DSH port derives guard state from native DSH session events, connects the
|
|
19
41
|
completion gate to Goal handling, and fails closed when it cannot verify the
|
|
20
42
|
host or evidence. Version 0.3.2 has passed same-package Web and Headless
|
|
@@ -79,6 +79,30 @@ event vocabulary `root_message`, `delegated_message`, `tool_result`,
|
|
|
79
79
|
runner executes every mirrored case without skips and compares the bounded
|
|
80
80
|
result contract; it does not translate a missing capability into a pass.
|
|
81
81
|
|
|
82
|
+
## 0.5.1 host adaptation note (2026-09-10)
|
|
83
|
+
|
|
84
|
+
The DSH host moved from Session format 0 to format 3 under Guard 0.5.1. That is
|
|
85
|
+
a host-side change, and one part of it touches a shared asset: the
|
|
86
|
+
session-identity digest input.
|
|
87
|
+
|
|
88
|
+
DSH Session V3 moved the fork-inherited prefix length out of the session header
|
|
89
|
+
(`seedLength`) onto the Session itself (`inheritedEventCount`). Guard feeds that
|
|
90
|
+
same durable value into the existing `seedLength` token and leaves the
|
|
91
|
+
`ccg.sessionRefDigest.v3` domain unchanged, so **every byte-mirrored digest
|
|
92
|
+
vector still reproduces identically** and no re-mirror is required. V3's
|
|
93
|
+
`header.isSeeded` marker was deliberately left out of the shared domain: an
|
|
94
|
+
absent optional field still encodes a presence-0 row, so adding it would change
|
|
95
|
+
every digest and silently invalidate the pinned parity evidence. The decision,
|
|
96
|
+
its root cause, and its impact boundary are recorded in
|
|
97
|
+
[`upstream-deltas.json`](upstream-deltas.json).
|
|
98
|
+
|
|
99
|
+
Everything else in the host adaptation is host-specific and stays out of the
|
|
100
|
+
shared fixture: the V2→V3 event vocabulary, the required `surfaceOp` metadata,
|
|
101
|
+
the renamed PTC dispatch events, the terminal renderer markers of 0.1.5-rc.1,
|
|
102
|
+
and the registry-derived host cohort. The maintainer document
|
|
103
|
+
`UPSTREAM_API_AUDIT.md` at the repository root records those differences; it is
|
|
104
|
+
not part of the published package.
|
|
105
|
+
|
|
82
106
|
## Recorded 0.4.0 alignment status (2026-09-03)
|
|
83
107
|
|
|
84
108
|
The semantic implementation described here entered the DSH `0.4.0` line from implementation baseline `ffc6fe9e1246a815f0bb630943c59d14b6505716`. The shared-contract reference is the Codex `0.10.0` source at `e4fccf690bcbc2be79d0b8d42a1a269f87072120`; this covers only the named contracts, not full product parity. Exact release commit, artifact, native-platform, and publication identities are recorded outside this semantic document because each is a separate evidence scope.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"ledgerVersion": "2",
|
|
3
3
|
"description": "Current, evidence-bounded delta ledger for behavior shared between codex-context-guard and dsh-completion-guard. It separates aligned behavior, partial host-native equivalents, missing shared behavior, and Codex-only lifecycle features.",
|
|
4
|
-
"updatedAt": "2026-09-
|
|
4
|
+
"updatedAt": "2026-09-10",
|
|
5
5
|
"source": {
|
|
6
6
|
"product": "codex-context-guard",
|
|
7
7
|
"currentRelease": "v0.11.0",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"target": {
|
|
13
13
|
"product": "dsh-completion-guard",
|
|
14
|
-
"currentRelease": "v0.
|
|
15
|
-
"currentReleaseHead": "
|
|
14
|
+
"currentRelease": "v0.5.1",
|
|
15
|
+
"currentReleaseHead": "uncommitted candidate on 09df9ecfdc94d7880ddabb37774e626486aca972",
|
|
16
16
|
"implementationBaseline": "ffc6fe9e1246a815f0bb630943c59d14b6505716",
|
|
17
|
-
"host": "DSH 0.1.
|
|
17
|
+
"host": "DSH 0.1.5-rc.1 / Cordis 4.0.2 (registry-derived cohort; native audit pending)"
|
|
18
18
|
},
|
|
19
19
|
"alignmentClaim": "DSH 0.4.0 aligns the named evidence and proof obligations with Codex 0.10.0. It does not claim full product parity and does not include all Codex 0.11.0 changes.",
|
|
20
20
|
"dispositions": [
|
|
@@ -113,6 +113,32 @@
|
|
|
113
113
|
"plainLanguage": "Codex Hook trust, plugin-cache recovery, and the Codex installer do not exist in the DSH host model.",
|
|
114
114
|
"implementation": "DSH uses Cordis bundles, DSH profiles, host-lock checks, and DSH-native lifecycle events. Shared safety behavior must be adapted through those mechanisms rather than copied.",
|
|
115
115
|
"tests": []
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"capability": "session-identity-digest-across-host-format-bump",
|
|
119
|
+
"introducedBy": "dsh-completion-guard v0.5.1 (host adaptation: DSH Session V2 -> V3)",
|
|
120
|
+
"disposition": "aligned",
|
|
121
|
+
"targetRelease": "dsh-completion-guard v0.5.1",
|
|
122
|
+
"plainLanguage": "The shared session-identity digest keeps one meaning even though the host moved where it stores the inherited-prefix length, so certificates from either side stay comparable.",
|
|
123
|
+
"implementation": "DSH Session V3 moved the fork-inherited prefix length from SessionHeader.seedLength to Session.inheritedEventCount. Guard feeds that same durable value into the existing seedLength digest token and leaves the ccg.sessionRefDigest.v3 domain unchanged. V3 header.isSeeded is deliberately NOT added as a digest input: an absent optional field still encodes a presence-0 row, so adding it would change every digest and break the byte-mirrored vectors upstream. Identity remains bound by id, createdAt, parentSession, seedLength, delegationDepth, origin and formatVersion, and a non-V3 header is refused before hashing.",
|
|
124
|
+
"impactBoundary": "No shared fixture byte changes; all 29 mirrored digest_v3 vectors still reproduce identically. Cross-repository parity therefore needs no re-mirror for this round. If upstream later wants isSeeded inside the shared domain, that is a new shared-semantics decision requiring a new fixture family and a joint re-pin.",
|
|
125
|
+
"tests": [
|
|
126
|
+
"tests/domain/digest-v3.test.ts",
|
|
127
|
+
"tests/domain/v051-dsh015-adaptation.test.ts"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"capability": "turn-boundary-continuation-ownership",
|
|
132
|
+
"introducedBy": "dsh-completion-guard v0.5.1 (host fact: DSH 0.1.5-rc.1 pauses a Goal immediately and only a human resume re-arms it)",
|
|
133
|
+
"disposition": "partial-equivalent",
|
|
134
|
+
"targetRelease": "dsh-completion-guard v0.5.1",
|
|
135
|
+
"plainLanguage": "When no Goal is running, the shared rule for whether a turn may be continued is unchanged. When a Goal exists and is paused, blocked, completed, or not yet read back, the DSH product yields instead of continuing, because only the user may restart paused work.",
|
|
136
|
+
"implementation": "decideTurnBoundary is part of the portable production surface. Guard 0.5.1 added one guard before the root-persistence correction steer: if projection.currentGoalRef is set but the Goal is not the active+armed continuation owner, the decision is stop with goal_paused_by_user_safe_yield (paused) or goal_not_continuable_safe_yield (blocked, complete, or phase not yet read back). Guard's Goal access exposes only get and disarm; there is no resume entry point anywhere in the plugin.",
|
|
137
|
+
"impactBoundary": "All 37 mirrored portable cases behave identically: exactly one case uses force_continue (stop-protocol-correction-once) and it carries no Goal reference, so the shared continuation path is untouched. The divergence is confined to an input state the Codex product has no equivalent for, which is why the two new reason codes are deliberately NOT added to the mirrored reasonCodeVocabulary — that fixture is a byte mirror and describes the shared contract, while these are host-specific stop reasons. No mirrored byte changed. There is no fixture self-check that would force the vocabulary to grow.",
|
|
138
|
+
"tests": [
|
|
139
|
+
"tests/domain/portable-semantics.test.ts",
|
|
140
|
+
"tests/domain/v051-dsh015-adaptation.test.ts"
|
|
141
|
+
]
|
|
116
142
|
}
|
|
117
143
|
]
|
|
118
144
|
}
|