# Session activation migration / 会话启用模式迁移

A host already at DSH `0.2.1-rc.3` may follow this migration without first upgrading to rc.5, provided its own host graph passes qualification.

已使用 DSH `0.2.1-rc.3` 的宿主无需先升级到 rc.5，即可按本流程迁移；其宿主图仍须通过相应资格核验。

This guide covers upgrades to **0.12.1**, including upgrades from **0.11.0**, 0.10.0 and earlier supported lines. Since 0.9.0, `always` has been the default for **new unseeded root sessions**. A write-once private binding preserves each old session's pre-upgrade effective mode. Mode is independent of `standard` policy, execution/publication authority and completion certificates. Empty old sessions belong in the inventory too. Recorded off/on continues to control enablement; neither configuration nor adoption re-signs history.

本指南用于升级到 **0.12.1**，包括从 **0.11.0**、0.10.0 及更早支持线升级。自 0.9.0 起，**新建无继承根会话**的默认模式为 `always`，旧会话通过不可覆盖私有绑定保留升级前有效模式。模式独立于 `standard` 策略、执行与发布权限及完成证书。旧空会话也必须清点，已记录的 off/on 继续控制启用状态；配置及 adoption 都不重签历史。

Before `inventory`, `inspect`, `adopt` or `verify`, the CLI hashes the full physical inventory and checks it against the official JSONL reader. Reviewed rc.3 and rc.5 backends support `none` and `zstd` compression. For a directory with multiple generations, the tool makes a private temporary copy of the log corpus so the SDK can resolve forks and inherited cuts. It checks every physical generation in that directory and matches the SDK's chosen file to its physical identity. It leaves all source logs in place. Keep all session writers stopped and place reports, selections and receipts outside the session root.

Hidden or corrupt logs, future generations, links and unknown layouts stop the operation. A single-generation session that the official reader lists but explicitly refuses to open can still be reported as pending. Multi-generation verification requires free temporary space for the corpus, up to 1 GiB. Each copied file and each decoded multi-generation log is limited to 256 MiB. On Windows the tool creates the copy with a private ACL on a fixed local drive. If the configured temporary base is shared or redirected, set `TEMP` for this command to a local directory that other accounts cannot replace or write. The tool attempts to remove its temporary copy on completion or failure. If cleanup fails or the process stops abruptly, treat any retained copy as private session data.

The proof binds the supplied physical root, compression, reviewed backend and file identities and contents. It does **not** establish that the supplied root is the active configuration: the operator or manager must verify that independently. An existing ordinary empty root can produce a zero-row inventory, but cannot produce a migration receipt. Missing roots fail. Backend, root, encoding or file changes require a fresh inventory and inspection. Receipts created before physical proofs existed are refused with `activation_inventory_proof_required`; preserve them and regenerate `inventory`, any selection, and `inspect` under the matching configuration.

CLI 在 `inventory`、`inspect`、`adopt`、`verify` 前计算全库日志的摘要，并与官方 JSONL 读取器核对。已审查的 rc.3 和 rc.5 后端支持 `none` 与 `zstd`。遇到同目录保留多代日志时，工具在私有临时目录复制日志库，供 SDK 解析分支和继承切点。工具逐代核验该目录内的日志，并核对 SDK 实际选中的物理文件。所有源日志均保留在原路径。全程停止会话写者，将报告、选择清单和收据写到会话根目录之外。

隐藏或损坏的日志、未来代际、链接和未知布局会中止操作。官方读取器列出但明确拒绝打开的单代会话仍可记录为待处理。多代核验需要可容纳日志库的临时空间，上限为 1 GiB。单个复制文件与单个解码后的多代日志上限均为 256 MiB。Windows 临时副本须位于固定本地磁盘，创建时即设置私有 ACL。若系统临时目录允许其他账号写入或被重定向，仅为此次命令将 `TEMP` 指向其他账号无法替换或写入的本地目录。工具在结束或失败时尝试清理临时副本。如果清理失败或进程意外终止，残留副本应按私有会话数据处理。

证明绑定所传物理根、压缩方式、已审查后端以及文件身份和内容，**不证明所传目录就是当前配置**；操作者或管理器须独立核对。已存在的普通空根可产生零行库存，但不能生成迁移收据；缺失根拒绝。后端、根、编码或文件变化后须重新 inventory 和 inspect。没有物理证明的旧收据会以 `activation_inventory_proof_required` 拒绝；保留原记录，并在匹配配置下重新 inventory、按需选择和 inspect。

## Prepare before changing the installed version / 升级前准备

Stop the relevant Web, Headless and Desktop session writers. Preserve their installed old package and effective configuration readback before upgrade. The new toolkit may run from an independently prepared candidate directory while the old Guard remains installed. Do not read the upgraded default and label it an old mode. Do not include credential values or session bodies in the readback.

先停止相关 Web、Headless、Desktop 会话写者，在升级前保留旧安装包身份及有效配置回读。可从独立准备的候选工具目录运行新工具，此时旧 Guard 仍安装在原位。不能把升级后的新缺省当作旧模式，不得在回读中包含凭据或会话正文。

Prepare an operator-owned JSON file in the following format. `previousPackage.sha256` identifies the preserved old package bytes; `sourceSha256` hashes the relevant sanitized, pre-upgrade source readback. Cohort names describe that verified source. If all relevant cohorts have one known mode, that uniform mode can cover the inventory. If modes differ, each session needs an explicit `sessionIds` mapping based on verified old provenance; absent or contradictory mappings stay `pending`. Profile paths, dates, event counts and `on` markers cannot supply that mapping. A checksum checks integrity; it is not an issuer signature or proof that an operator's asserted mapping is correct. Use the verified old mode in the example; package version alone does not establish whether it is `opt-in` or `always`.

准备以下格式的操作者 JSON 文件。包摘要指向保留的旧包字节，来源摘要指向相关的脱敏升级前回读。来源组名描述已核验来源。所有相关来源模式一致时可覆盖库存；模式不同则必须提供基于已核验旧来源的 `sessionIds` 映射，缺失或冲突保持 `pending`。不能用 profile 路径、日期、事件数量或 on 标记替代来源映射。摘要核验完整性，不是发行签名，也不能证明操作者的映射断言正确。示例中的 `opt-in` 应按已核验的旧模式填写，不能仅按包版本判断。

```json
{
  "schema": "dsh-activation-prior-modes/v1",
  "previousPackage": {
    "name": "dsh-completion-guard",
    "version": "0.9.0",
    "sha256": "<64 lowercase hex characters>"
  },
  "sourceSha256": "<64 lowercase hex characters>",
  "cohorts": [{ "name": "verified-old-web", "mode": "opt-in" }]
}
```

The 0.12.1 toolkit accepts verified prior-mode records for predecessor versions `0.0.x`–`0.11.x`, including `0.11.0`. Versions 0.12.0 and later are outside the prior-mode source format. Existing valid single-generation receipts may still be verified against the same physical inventory.

0.12.1 工具接受前驱版本 `0.0.x`–`0.11.x` 的已核验旧模式来源，包括 `0.11.0`。此前有效的单代收据仍可用于同一物理库存的核验。

If Guard 0.12.0 is already installed and you could not prepare a receipt for a multi-generation library, you can run the new read-only inventory. To prepare a migration receipt, you still need a verified source from before the earlier upgrade that covers each included session. Keep the current installation and logs until that evidence is available.

如果已安装 Guard 0.12.0，此前又无法为多代会话库生成收据，可以先用新工具只读清点。准备迁移收据仍需找到上次升级前已核验的旧模式来源，并覆盖每个要迁移的会话。找不到完整来源时，保留当前安装和原日志。

## Official old-format refusals and an explicit readable subset / 官方旧格式拒绝与显式可读子集

The official persistence reader may reject an older session with `SessionFormatUnsupportedError`. This names a host format-support boundary; it does not by itself prove corruption or a Guard regression. Do not delete, rewrite, rename or repair the raw log to force acceptance. Preserve it, the old package and its verified effective-mode source. `inventory` can record this **specific official open refusal** as pending. Other failures (corruption, permissions, missing files, unknown errors, list/stat failure or drift) abort; they are not automatically skipped. Default `inspect/adopt/verify` still requires the whole inventory to be readable.

官方 persistence 可能以 `SessionFormatUnsupportedError` 拒绝旧格式会话。这说明宿主格式支持的边界，本身不证明日志损坏或 Guard 回归。不要删除、重写、改名或“修复”原日志来绕过拒绝；保留原日志、旧包和已核验的旧有效模式来源。inventory 只将这类**官方 open 拒绝**记为 pending；损坏、权限、丢失、未知异常、list/stat 失败或库存变化均中止，不会被自动跳过。默认 inspect/adopt/verify 仍要求整库可读。

Suppose an inventory contains N sessions, of which M are readable. First freeze the full report, then review the local `rows` and write a JSON array containing only the readable IDs you explicitly choose, for example `["chosen-a", "chosen-b"]`. The example IDs are placeholders; use exact report IDs. No automatic “all readable” selection is made. The report and manifests contain private IDs and metadata hashes, but no event bodies or credentials; keep them local and owner-only. Run this phase before replacing either the host or Guard, with writers stopped. You can copy the preserved logs into a separate, access-controlled workspace for later host-format diagnosis; never change the authoritative originals or share their contents.

假设库存共 N 个会话，其中 M 个可读。先冻结全库报告，查看本地 rows，再将明确选中的可读 ID 写入 JSON 数组，如 `["chosen-a", "chosen-b"]`。示例 ID 是占位符，必须换成报告中的精确 ID；工具不会自动选择“所有可读”。报告与清单含私有 ID 和元数据摘要，不含正文或凭据，应仅在本地以所有者权限保存。替换宿主或 Guard 前、写者停止时完成这一阶段。后续宿主格式诊断可使用另行受控保管的日志副本，不能改动权威原件或外传正文。

```sh
# POSIX shell; use distinct unused output paths. Replace zstd with none if the active configuration uses plain JSONL.
node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs inventory \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --output /path/to/inventory.json

# chosen-ids.json is an operator-reviewed JSON array of exact readable IDs.
node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs select \
  --inventory /path/to/inventory.json \
  --include-file /path/to/chosen-ids.json \
  --output /path/to/selection.json

node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs inspect \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --selection /path/to/selection.json \
  --prior-modes /path/to/old-mode-source.json \
  --output /path/to/selected-receipt.json

# After replacement, before upgraded host startup:
node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs adopt \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --selection /path/to/selection.json \
  --receipt /path/to/selected-receipt.json \
  --dsh-home /path/to/actual-dsh-home

node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs verify \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --selection /path/to/selection.json \
  --receipt /path/to/selected-receipt.json \
  --dsh-home /path/to/actual-dsh-home
```

`inventory_scanned` reports session, generation, multi-generation session, readable and unsupported counts and creates the frozen report. `selection_ready` creates the explicit scope manifest; empty, duplicate, unknown or unsupported IDs refuse. Selected `inspect` reports `ready` only when all included identities have verified old sources, then writes a receipt. Mixed-mode sources need exact per-session mappings. Source mappings may cover excluded IDs too, but exclusions never acquire a mode binding. Never infer a mode from format, date, path, event count or a new default.

inventory_scanned 表示已生成全库报告及会话总数、日志代数、多代会话数、可读及拒绝数量；selection_ready 表示已冻结显式范围，空选、重复、未知或被拒绝 ID 都会拒绝。子集 inspect 仅在所有包含会话的旧来源均可核验时返回 ready 并创建收据。混合模式需逐会话映射；旧来源映射可以包含排除项，但排除项不会被写入模式绑定。不得按格式、日期、路径、事件数或新默认值猜模式。

Every selected `inspect/adopt/verify` rescans the **whole** inventory and checks all listed header/revision hashes, readable birth identities and refusal statuses against the selection. Added, removed, replaced or changed rows—including excluded ones—or changed readability invalidate the scope before adoption. Supplying the same manifest is mandatory on all three commands; full and selected receipts cannot be substituted. An integrity digest binds the asserted inputs; it is not authority or proof that an old-source assertion is true. A host upgrade that changes the scan requires a fresh report and reviewed scope before proceeding.

每次子集 inspect/adopt/verify 都重扫**全库**，核对全部 list header/revision 摘要、可读出生身份及拒绝状态。新增、删除、替换、变化（包括排除项）或可读性变化，会在 adoption 前使范围失效。三条命令均须携带同一 selection，不能混用全库与子集收据。摘要只绑定断言输入，不提供权限，也不能证明旧来源断言正确。宿主升级若改变清点结果，必须重新生成报告并审核范围后再继续。

`selected_complete` means that **only the receipt-selected rows** completed or verified. `selected_partial` means one or more of those rows refused. Both report `scope: receipt_selected`, `wholeInventoryStatus: not_claimed`, and a pending list for all exclusions (`session_format_unsupported` or `not_selected`). Pending remains visible even if the command exits zero. Repeat adoption for the same unchanged scope: completed rows are byte-identical no-ops; missing rows can continue, conflicts remain refused and intact. `verify` leaves source logs and mode bindings untouched. It uses a private temporary copy for multi-generation verification. Preserve all existing reports and receipts; `activation_output_exists` requires a new output name, not deleting the old evidence. Drift requires new inventory/selection/inspect, not editing a digest or reusing a stale scope. The older full-inventory path below remains available without `--selection`.

selected_complete **仅表示收据选中行**完成或核验通过；selected_partial 表示其中至少一行拒绝。两者均输出 scope: receipt_selected、wholeInventoryStatus: not_claimed，以及所有排除项的 pending 清单（session_format_unsupported 或 not_selected）。命令即使零退出，也不能隐藏 pending 或称为整库完成。相同且未变的范围可重复 adopt：完成行字节不变，缺失行可继续，冲突拒绝且原状保留；verify 保留源日志和模式绑定原状，多代核验使用私有临时副本。保留旧报告和收据；activation_output_exists 应换一个输出文件名，而不是删除证据。库存变化后重新 inventory/selection/inspect，不能改摘要或复用过期范围。下方不带 --selection 的原整库路径仍可用。

When a later official host supports the pending format, use its **read-only** persistence reader on the preserved log, generate a fresh inventory, compare actual birth identity and re-establish the preserved old-mode source. Confirm that the existing user authorization covers the newly included scope; ask only if it does not. Create a new selection and receipt, then adopt and verify. A previous migration receipt or certificate grants no new migration/publication authority. If the reader still refuses or the source cannot be recovered, retain pending and continue new work in a fresh qualified root session; do not fabricate origin, inherited cut, old mode or receipt. The original history remains available for later support.

以后官方宿主支持这些格式时，用该宿主的**只读** persistence 读取保留日志，生成新库存，核对实际出生身份并重新核验保留的旧模式来源；核对已有用户授权是否覆盖新增范围，仅在未覆盖时补充确认；随后生成新 selection/收据，再 adopt 和 verify。旧收据或证书不授予新迁移或发布权限。仍拒绝或无可恢复来源时保持 pending，可在新的合格根会话继续工作；不能伪造 origin、继承 cut、旧模式或收据。原历史保留以等待后续支持。

### Copyable migration prompts / 可复制迁移提示词

> Help me migrate session activation to DSH Completion Guard 0.12.1. Lifecycle constraint: [fill in which writers may be stopped and whether restart is allowed]. Reuse scope, write and lifecycle authorization already supplied in this conversation; ask only for missing or materially changed decisions. First report the current host/persistence/compression settings, preserved predecessor package identity (for example 0.9.0) and sanitized pre-upgrade effective-mode sources. If they cannot be verified, keep affected sessions pending. Do not replace packages, stop/restart processes or write bindings before that lifecycle and mutation authority is established. Run the packaged read-only inventory command; show total/readable/official-format-refused counts and a local pending report. Use my existing explicit selection, or ask me to choose the included scope if none was supplied; do not silently expand it or treat readability alone as authorization. Bind that explicit selection through inspect/adopt/verify, detect all inventory changes, preserve raw logs and old sources, and never infer modes/origin/cuts from paths, dates or event counts. No log bodies, credentials or private IDs leave my machine. Once the scope and writes are covered by my authorization, adopt, repeat to check no-op, and verify; report selected completion and remaining pending separately. For unsupported rows, give the future official-reader/re-inventory/source-validation route; without a recoverable source, keep pending or use a new session. Do not treat old certificates as new authority.

> 帮我迁移到 DSH Completion Guard 0.12.1 的会话启用模式。生命周期约束：[填写允许停止的写者及是否允许重启]。沿用本会话已给出的范围、写入及生命周期授权，仅询问缺失或实质变化的决定。先报告现有宿主、持久化目录/压缩配置、保留的前驱包（如 0.9.0）身份及脱敏的升级前有效模式来源；不能核验就将受影响会话保持 pending。取得明确生命周期和写入权限前，不替换包、不停/重启进程、不写绑定。运行打包工具的只读 inventory，报告总数/可读/官方格式拒绝数量并保存本地 pending 报告；沿用我已明确选择的范围，尚未选择时再请我决定；不静默扩大范围，也不把可读性本身当作授权。让显式 selection 贯穿 inspect/adopt/verify，检测全部库存变化，保留原日志和旧来源，不按路径、日期、事件数猜模式/origin/cut。正文、凭据、私有 ID 不离开本机。范围和写入已有授权覆盖后 adopt、重复检查 no-op，再 verify，分别报告选中行完成及剩余 pending。被拒绝项给出未来官方读取器支持后重盘点、核验身份/旧来源的方案；没有可恢复来源就保留 pending 或改用新会话。旧证书不当作新权限。


## Full-inventory inspect, adopt, verify / 整库清点、采纳、核验

The entry `node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs` below uses the independently prepared 0.12.1 toolkit; it does not assume a new command is installed on PATH while the old Guard remains installed. The tool mounts only the official JSONL persistence service, without starting the agent loop, UI or model. `--runtime-anchor` is a file in the physical official runtime; the tool resolves its real path before loading dependencies. `--persistence-root` and optional `--compression none|zstd` must match the active persistence configuration. The default compression is `zstd`; pass `--compression none` for a plain JSONL store. Inspection uses public `list`, read-only `open`, exact header/inherited-cut metadata and revision readback; it outputs no event bodies. Keep writers stopped through the sequence.

下方使用独立准备的 0.12.1 工具入口 `node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs`，不假定旧 Guard 仍安装时新命令已在 PATH。工具只挂载官方 JSONL persistence 服务，不启动 agent loop、界面或模型。runtime anchor 必须是官方 runtime 中的文件，加载依赖前先解析物理路径。持久目录和压缩格式须匹配实际配置。默认使用 `zstd`，普通 JSONL 库须传 `--compression none`。清点使用公开 list、只读 open、精确 header/cut 元数据及 revision 回读，不输出事件正文。整个操作期间保持写者停止。

The following example is for a POSIX shell. Replace `zstd` with `none` for a plain JSONL store. Run `inspect` before replacement; run `adopt` and `verify` before starting the upgraded host. Keep the prepared toolkit path explicit throughout.

以下示例使用 POSIX shell。普通 JSONL 库须将 `zstd` 换成 `none`。替换前执行 inspect，升级后的宿主启动前执行 adopt 和 verify，全程使用明确的候选工具路径。

```sh
node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs inspect \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --prior-modes /path/to/old-mode-source.json \
  --output /path/to/frozen-migration.json

node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs adopt \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --receipt /path/to/frozen-migration.json \
  --dsh-home /path/to/actual-dsh-home

node /absolute/prepared-package/bin/dsh-completion-guard-activation.mjs verify \
  --runtime-anchor /path/to/runtime/package.json \
  --persistence-root /path/to/active-session-storage \
  --compression zstd \
  --receipt /path/to/frozen-migration.json \
  --dsh-home /path/to/actual-dsh-home
```

`inspect` creates a new owner-only receipt with exclusive creation, or reports exact unresolved session IDs and exits nonzero without creating an adoptable receipt. `adopt` first checks receipt identities against the current public inventory, then writes each binding separately; `verify` leaves source logs and mode bindings untouched. It uses a private temporary copy for multi-generation verification. A conflict leaves the other completed rows intact and reports `partial`. Repeating adoption is a byte-identical no-op for completed rows and continues missing rows. Claim completion only after all receipt rows verify. A newly appearing session is not silently included in an old receipt.

inspect 排他创建仅所有者可访问的新收据，或报告未解决会话 ID 并非零退出，不生成可采纳收据。adopt 先用当前公开库存核对身份，再逐会话写绑定；verify 保留源日志和模式绑定原状，多代核验使用私有临时副本。冲突保留其他已完成行并报告 partial，重复采纳对已完成行字节不变，继续缺失行。所有收据行核验通过后才可报告该收据迁移完成；新出现的会话不会被静默加入旧收据。

## Restore, diagnosis and rollback / 恢复、诊断与回退

Bindings live under `DSH_HOME/completion-guard/activation-bindings-v1` (`~/.dsh` when unset), with one hashed slot per SessionId. Birth identity includes createdAt, parent, seeded flag, exact inherited cut, origin and delegation depth; preset, cwd, profile and host lock do not change it. Existing mode overrides defaults. A contradictory explicit configuration refuses `activation_mode_conflict`; removing that contradictory override restores the original binding semantics. To choose another initial mode, create a new root session. Restore/clear/compact/late attach never create a missing binding.

绑定位于上述私有目录，一个 SessionId 对应一个摘要槽。出生身份包含 createdAt、父会话、seed 标记、精确继承 cut、来源及委派深度；preset、cwd、profile、宿主锁不改变模式身份。已有模式覆盖缺省，显式矛盾报具名拒绝；移除矛盾覆盖可恢复原绑定语义，选择另一初始模式请新建根会话。恢复、清空、压缩、迟挂载不补建缺失记录。

Missing/corrupt/changed records invalidate cached projections and certification. Inspect the named reason, then use the preserved verified receipt to adopt the same missing old identity/mode. Corrupt or conflicting final slots refuse automatic repair; preserve them for diagnosis. If no trusted old source remains, keep the session unknown and establish new work in a fresh qualified session. This does not delete history or trigger an endless correction loop. Forks require a parent binding and inherit its mode; the exact cut is supplied and validated by the official Session/persistence contract, without mode inference from prefix length.

缺失、损坏或变化的记录使缓存投影和认证失效。根据具名原因诊断，再使用保留且已核验的收据采纳同一缺失旧身份与模式。损坏或冲突的 final 拒绝自动修复，请保留诊断；无可信旧来源时保持 unknown，在新合格会话中建立新工作。不删除历史，也不触发无穷纠正。fork 需核验父绑定并继承父模式；精确 cut 由官方 Session/persistence 合同提供及验证，不由前缀长度推断模式。

A qualified fresh creation that lost a brief writer-lock race now retries itself: the runtime re-attempts the SAME creation, while the startup intent is still provable, for a bounded budget (at most 8 attempts within 60 seconds of attach), and then reports the explicit `activation_writer_unavailable` status. The retry is idempotent (same-value) and never applies to a session that was ever successfully created, to resume/late attach, or to a deleted binding — those keep the unknown/diagnosis rules below. This automatic retry is not a recovery command and does not need one.

A fresh creation that leaves `.pending`, including a fresh 0.12.0 session, has no general recovery command in this toolkit. `inspect` accepts verified pre-upgrade predecessor sources (`0.0.x`–`0.11.x`, including `0.11.0`), but `adopt` still requires a verified migration receipt for the same old session identity and mode. Predecessor support does not authorize treating a failed fresh creation as a legacy migration or inventing a receipt to repair it. Without an existing trusted legacy receipt, keep the mode unknown, diagnose the retained state, or continue new work in another qualified fresh session. The exported same-value writer is a programmatic controlled recovery primitive, not an operator CLI. Do not delete `.pending` merely to make the final readable.

合格新会话因短暂写锁竞争而失败的首次创建会自行重试：运行时在首创意图仍可证明时，按有界预算（attach 后 60 秒内至多 8 次）重试同一创建，随后返回明确的 `activation_writer_unavailable` 状态。重试是同值幂等的，绝不适用于曾成功创建的会话、resume/迟挂载或被删除的绑定——那些仍按下面的 unknown/诊断规则处理。该自动重试不是恢复命令，也不需要恢复命令。

新建会话（包括 0.12.0 新会话）留下 .pending 时，本工具仍没有通用恢复命令。inspect 可使用已核验的旧版本模式来源（`0.0.x`–`0.11.x`，包括 `0.11.0`），但 adopt 仍需针对同一旧会话身份与模式的已核验迁移收据。支持这些前驱版本不意味着可以把失败的新建会话当作旧会话迁移，或编造收据来修复它。没有既有可信旧收据时，保持模式 unknown、诊断保留状态，或在另一合格新会话中继续新工作。导出的同值 writer 是程序受控恢复原语，不是操作者 CLI；不能为了让 final 可读而删除 .pending。

For rollback, stop writers, retain the receipt and bindings, and select the previous mode explicitly in each old profile before reinstalling the old Guard. A pre-0.9.0 Guard does not read these bindings; mixed-mode inventories need separate correctly mapped profiles or remain unsuitable for rollback. Keep host-lock and certificate identities separate: re-inspect the actual installed host as required, and never re-sign old certificates merely to change mode. Cross-machine transfer includes only verified bindings/receipts, with owner permissions restored; it transfers no host lock, credentials or native authority.

回退先停写者，保留收据与绑定，为旧 profile 显式选择原模式再恢复旧 Guard。0.9.0 之前的 Guard 不读取绑定，混合模式库存需正确映射的独立 profile，否则不适合回退。宿主锁及证书身份另行核验，不为改变模式重签旧证书；跨机仅迁移核验过的绑定与收据并恢复所有者权限，不转移宿主锁、凭据或原生权限。

## Storage capability limits / 存储能力边界

POSIX writes reuse the private writer lock, exclusive temporary creation, full write/file fsync, non-overwriting hard-link publication, directory fsync and final readback. Same identity/mode is a strict no-op preserving provenance. Readers reject malformed/duplicate-key JSON, bad digest/schema, unsafe owner/access modes, leaf links and user-owned ancestor links. Root-owned macOS `/var` and `/tmp` system aliases are the only permitted ancestor link exceptions; writable non-sticky ancestry refuses. These checks do not claim resistance to hostile same-owner processes racing the filesystem.

POSIX 复用私有 writer 锁、排他临时文件、完整写入及文件 fsync、不可覆盖 hard-link 发布、目录 fsync 与 final 回读。同身份同模式严格不改写来源。读取拒绝坏 JSON、重复键、摘要/schema 错误、错误所有者/权限、叶链接及用户祖先链接；仅允许 root 所有的 macOS 系统别名 /var、/tmp，非 sticky 可写祖先拒绝。它不是防御同 owner 恶意并发文件系统操作的绝对保证。

Windows uses the adopted **published-file flush barrier** on qualified local storage supporting same-volume hard links: flush the complete exclusive temporary, publish the non-overwriting link, open the existing final with read/write permissions without create/truncate, verify regular-file identity and exact bytes, fsync that final handle, close it and independently read back. No final bytes or permissions are normalized. Directory fsync remains an observed EPERM capability gap. Microsoft documents file data/metadata flush; applying that file flush to the newly published link is an explicitly bounded engineering inference, not POSIX-directory equivalence, power-loss proof, hardware-cache guarantees or durability of the whole ancestor namespace. Native candidate acceptance must record filesystem/runtime identity, this barrier and the directory gap separately.

Windows 在合格且支持同卷 hard-link 的本地存储上采用**发布后文件 flush 屏障**：完整排他临时文件 flush，不可覆盖 link 发布，以不创建/不截断的可写句柄打开现有 final，核对 regular-file 身份及精确字节，fsync 该句柄，关闭后独立回读。不规范化 final 字节或权限。目录 fsync 的 EPERM 能力缺口保留。Microsoft 说明文件数据/metadata flush；将其应用于刚发布的 link 是具名、有界工程推论，不是 POSIX 目录等价、断电、硬件缓存或整个祖先 namespace 持久性证明。候选原生验收须分别记录文件系统/runtime、文件屏障及目录缺口。

A post-publication failure retains the exclusive `.pending` temporary hard link; readers refuse `activation_publication_incomplete` even when final is visible. Controlled same-value writing reopens and successfully flushes retained temporary bytes, then can verify the exact pending/final identity, complete the barrier and remove the temporary. Recovery does not rewrite bytes or provenance. Temporary cleanup occurs after the required barrier/readback and its crash durability is a separate limit, not covered by that earlier flush. A malformed retained temporary or identity/mode conflict refuses automatic recovery. This is one per-session temporary publication, with no global transaction or birth WAL.

发布后失败保留排他的 .pending 临时 hard-link；即使 final 可见，读者仍拒绝未完成发布。受控同值写入须重新打开并成功 flush 保留临时字节，再核对 pending/final 精确身份、补完屏障并移除临时项，不改字节或来源。临时清理在必需屏障与回读之后，它的 crash 持久性独立，不能借用此前 flush。坏临时项或身份/模式冲突拒绝自动恢复；这是逐会话临时发布，无全局事务或 birth WAL。

The official file-tool guard denies explicit private-storage targets (including resolved path aliases), and shell-tool calls naming the private roots or mode entrypoint. Operator migration runs independently. This is bounded tool-surface protection, not arbitrary command interpretation, a general subprocess sandbox or protection against hostile in-process plugins/encoded shell commands. No broader host interception is claimed.

官方文件工具 guard 拒绝明确的私有目标（含解析后的路径别名），shell 工具拒绝指向私有根或模式入口的调用；操作者迁移独立执行。这是有界工具表面保护，不是任意命令解释、通用子进程 sandbox，也不防御同进程恶意插件或编码 shell 绕过，不声称更广的宿主拦截。
