From f8009e58ea3fc9bc8ffff7aaddc6110309634cce Mon Sep 17 00:00:00 2001 From: Lihua <1017343802@qq.com> Date: Mon, 28 Sep 2026 00:27:42 -0700 Subject: [PATCH 1/4] test(reliability): rehearse offline ledger export and recovery Signed-off-by: Lihua <1017343802@qq.com> --- .../ledger-retention-smoke.py | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 examples/reliability_diagnostics/ledger-retention-smoke.py diff --git a/examples/reliability_diagnostics/ledger-retention-smoke.py b/examples/reliability_diagnostics/ledger-retention-smoke.py new file mode 100644 index 0000000000..23f3a1a224 --- /dev/null +++ b/examples/reliability_diagnostics/ledger-retention-smoke.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +"""Rehearse offline diagnostic export/delete/restore in disposable state only. + +The invariant is byte-preserving recovery of negative evidence through the +real CLI. This is neither a live observer run nor automatic retention policy. +Use --installed with a non-editable installed package to check its entrypoint. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import subprocess +import sys +import tempfile +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +AS_OF = "2026-09-01T12:00:00+00:00" + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--installed", action="store_true") + args = parser.parse_args() + if not args.installed: + sys.path.insert(0, str(REPO_ROOT)) + + import loopx + from loopx.capabilities.reliability_diagnostics import ( + FIXTURE_GOAL_ID, + run_dsh_fixture, + ) + + if args.installed: + assert not Path(loopx.__file__).resolve().is_relative_to(REPO_ROOT), ( + "--installed requires a non-editable installation outside the checkout" + ) + + fixture = run_dsh_fixture() + data = "".join(json.dumps(row) + "\n" for row in fixture["ledger_records"]) + env = dict(os.environ) + env.pop("PYTHONPATH", None) + if not args.installed: + env["PYTHONPATH"] = str(REPO_ROOT) + + with tempfile.TemporaryDirectory(prefix="loopx-retention-smoke-") as tmp: + root = Path(tmp) + runtime = root / "runtime" + runtime.mkdir() + # Synthetic siblings must survive operations on the one ledger. + siblings = { + runtime / name: b'{"synthetic":"unchanged"}\n' + for name in ("goal.json", "todo.json", "quota.json", "gate.json", "session.json") + } + for path, content in siblings.items(): + path.write_bytes(content) + + def cli(command: str, *options: str, at: Path = runtime, stdin: str | None = None) -> dict: + result = subprocess.run( + [sys.executable, "-m", "loopx.cli", "--runtime-root", str(at), + "--format", "json", "reliability-diagnostics", command, + "--goal-id", FIXTURE_GOAL_ID, *options], + cwd=root, env=env, input=stdin, capture_output=True, text=True, + check=False, timeout=30, + ) + assert result.returncode == 0, result.stderr or result.stdout + payload = json.loads(result.stdout) + assert payload["ok"] is True, payload + return payload + + def readback(at: Path = runtime) -> dict: + return cli("status", "--with-receipt", "--as-of", AS_OF, at=at) + + ingest = cli("ingest", "--input", "-", stdin=data) + ledger = runtime / ingest["ledger_ref"] + assert ingest["rejected_event_count"] == 0 + + for expected_status in ("degraded", "invalid"): + if expected_status == "invalid": + # A refused control field leaves a durable marker. Recovery must + # preserve it instead of selecting only accepted envelopes. + refused = dict(fixture["ledger_records"][0], command={"kind": "stop"}) + refusal = cli("ingest", "--input", "-", stdin=json.dumps(refused) + "\n") + assert refusal["ingest_gate_recorded"] is True + assert refusal["rejected_by_reason"] == {"control_field_rejected": 1} + assert b"reliability_ingest_violation_v0" in ledger.read_bytes() + assert b'"command"' not in ledger.read_bytes() + + before = readback() + receipt = before["receipt"] + assert receipt["status"] == expected_status, receipt + assert {"sequence_gap", "backpressure_drop", "raw_material_rejected", + "clock_uncertainty_exceeded"} <= set(receipt["reason_codes"]) + assert receipt["lost_event_count"] == 2 + assert receipt["backpressure_drop_count"] == 3 + assert receipt["clock"]["max_uncertainty_ms"] == 1500 + + content = ledger.read_bytes() + digest = hashlib.sha256(content).hexdigest() + archive = root / f"archive-{expected_status}" + copy_runtime = archive / "readback-runtime" + copy_ledger = copy_runtime / ingest["ledger_ref"] + copy_ledger.parent.mkdir(parents=True) + copy_ledger.write_bytes(content) + (archive / "readback.json").write_text(json.dumps(before), encoding="utf-8") + (archive / "ledger.sha256").write_text(digest, encoding="ascii") + assert hashlib.sha256(copy_ledger.read_bytes()).hexdigest() == digest + assert copy_ledger.read_bytes() == ledger.read_bytes() + assert readback(copy_runtime) == before + + # Tampering with a private export cannot be treated as verified. + damaged = content + b"{}\n" + assert hashlib.sha256(damaged).hexdigest() != digest + assert hashlib.sha256(ledger.read_bytes()).hexdigest() == digest + ledger.unlink() + missing = readback() + assert missing["receipt"]["status"] == "invalid" + assert "no_observations" in missing["receipt"]["reason_codes"] + assert missing["receipt"]["persisted_event_count"] == 0 + + # Exclusive creation is the restore guard: never merge or overwrite + # a file created by a restarted observer. + with ledger.open("xb") as handle: + handle.write(copy_ledger.read_bytes()) + try: + ledger.open("xb").close() + except FileExistsError: + pass + else: + raise AssertionError("restore must refuse an existing ledger") + assert hashlib.sha256(ledger.read_bytes()).hexdigest() == digest + assert readback() == before + assert all(path.read_bytes() == value for path, value in siblings.items()) + projection = before["projection"] + assert projection["mode"] == "read_only" + assert projection["authority"] == "none" + assert projection["worker_influence"] == "none" + assert receipt["outbound_endpoints"] == [] + assert receipt["observation_entered_worker_context"] is False + assert receipt["observation_entered_scheduler_inputs"] is False + + print("reliability-diagnostics ledger-retention-smoke: ok " + f"(synthetic; installed={args.installed}; degraded/invalid evidence preserved)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 694ee014d677f833c8f4ee39ca9b6bdb9de35788 Mon Sep 17 00:00:00 2001 From: Lihua <1017343802@qq.com> Date: Mon, 28 Sep 2026 00:27:51 -0700 Subject: [PATCH 2/4] docs(reliability): add a local retention and recovery rehearsal Signed-off-by: Lihua <1017343802@qq.com> --- ...bility-diagnostics-governed-delivery-v0.md | 10 +- ...-diagnostics-governed-delivery-v0.zh-CN.md | 8 +- .../reliability_diagnostics/README.md | 8 + .../reliability_diagnostics/README.zh-CN.md | 6 + .../docs/local-retention-v0.md | 215 ++++++++++++++++++ 5 files changed, 244 insertions(+), 3 deletions(-) create mode 100644 loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md diff --git a/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.md b/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.md index 494b9fb45d..00bbf53f7f 100644 --- a/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.md +++ b/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.md @@ -532,8 +532,14 @@ envelope and stats records, integrity receipt, read-only diagnostic projection, a deterministic DSH-shaped fixture, and producer-side public-safety rejection before the first ledger append. Still open before P0 exit: an eligible C1 observer run on a real `dsh` session, the reported -overhead measurement, and the ledger retention and deletion profile from -decision 4 below. +overhead measurement, and deployment-owner acceptance of the ledger retention +and deletion profile from decision 4 below. The +[local retention reference (v0)](../../../loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md) +and its synthetic CLI lifecycle smoke supply an offline export/delete/restore +rehearsal, including installed-package readback and preservation of negative +evidence. They do not implement automated retention or prove real-observer +shutdown, filename/tenant isolation, C0/C1 or a deployment's deletion policy. +Implementation and milestone evidence remain in [task #5211](https://github.com/loopx-project/loopx/issues/5211). ### P1 — Benchmark-qualified diagnostic pilot diff --git a/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.zh-CN.md b/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.zh-CN.md index 1a9a1c7577..237c4dd43b 100644 --- a/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.zh-CN.md +++ b/docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.zh-CN.md @@ -453,7 +453,13 @@ overhead;不存在 production authority。 `packages/dsh-loopx-plugin`)落地:provider-neutral envelope 与 stats record、integrity receipt、 read-only diagnostic projection、deterministic DSH-shaped fixture,以及首次写入 ledger 之前的 producer 侧 public-safety 拒绝。P0 exit 之前仍未完成:在真实 `dsh` session 上的 eligible C1 -observer run、overhead 测量报告,以及下文 decision 4 的 ledger retention 与 deletion profile。 +observer run、overhead 测量报告,以及部署 owner 对下文 decision 4 的 ledger retention 与 +deletion profile 的接受决定。 +[本地 retention 参考方案(v0)](../../../loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md#中文) +及其合成 CLI lifecycle smoke 提供离线导出/删除/恢复演练,包含安装包读回与负面证据保留; +它们没有实现自动 retention,也未证明真实 observer 停写、文件名/租户隔离、C0/C1 或部署的 +删除 policy。实现 PR 和 milestone 证据继续归入 +[task #5211](https://github.com/loopx-project/loopx/issues/5211)。 ### P1 — Benchmark-qualified diagnostic pilot diff --git a/loopx/capabilities/reliability_diagnostics/README.md b/loopx/capabilities/reliability_diagnostics/README.md index 8f7b476a08..1edc6f233e 100644 --- a/loopx/capabilities/reliability_diagnostics/README.md +++ b/loopx/capabilities/reliability_diagnostics/README.md @@ -193,10 +193,18 @@ never be silently attributed to the configured goal. Token-level `assistant/chunk` events — a retired type that only older durable logs still replay — are not consumed. +For an operator-run offline export/delete/restore rehearsal, use the +[local retention reference (v0)](docs/local-retention-v0.md). It preserves whole +ledger bytes and negative integrity evidence, requires a frozen writer and an +owner-selected finite retention period, and does not implement automatic TTL +or qualify a live deployment. It also documents the current filename-alias +boundary; ambiguous ownership must hold deletion. + ## Validation ```bash python3 examples/reliability_diagnostics/dsh-shadow-observer-fixture-smoke.py +uv run --extra test python examples/reliability_diagnostics/ledger-retention-smoke.py python3 -m pytest tests/capabilities/test_reliability_diagnostics.py tests/capabilities/test_reliability_diagnostics_dsh_provider.py -q cd packages/dsh-loopx-plugin && pnpm typecheck && pnpm test -- observer ``` diff --git a/loopx/capabilities/reliability_diagnostics/README.zh-CN.md b/loopx/capabilities/reliability_diagnostics/README.zh-CN.md index c21eaf955a..240efa8f65 100644 --- a/loopx/capabilities/reliability_diagnostics/README.zh-CN.md +++ b/loopx/capabilities/reliability_diagnostics/README.zh-CN.md @@ -165,10 +165,16 @@ parity)。启用后,`observer.ts` 只观察 `session/created`、`session/eve 到配置的 goal。token 级 `assistant/chunk`(已退场类型,只有旧 durable 日志还会重放) 不被消费。 +人工离线导出/删除/恢复演练使用 +[本地 retention 参考方案(v0)](docs/local-retention-v0.md#中文)。它保留完整 ledger 字节与 +负面完整性证据,要求冻结 writer 并由 owner 选择有限保留期限;没有实现自动 TTL,也不构成 +live 部署验收。方案说明了当前文件名别名边界,归属不明确时须暂停删除。 + ## 验证 ```bash python3 examples/reliability_diagnostics/dsh-shadow-observer-fixture-smoke.py +uv run --extra test python examples/reliability_diagnostics/ledger-retention-smoke.py python3 -m pytest tests/capabilities/test_reliability_diagnostics.py tests/capabilities/test_reliability_diagnostics_dsh_provider.py -q cd packages/dsh-loopx-plugin && pnpm typecheck && pnpm test -- observer ``` diff --git a/loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md b/loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md new file mode 100644 index 0000000000..cde881c49e --- /dev/null +++ b/loopx/capabilities/reliability_diagnostics/docs/local-retention-v0.md @@ -0,0 +1,215 @@ +# Local diagnostic ledger retention rehearsal (v0) + +[English](#english) · [中文](#中文) · [Capability](../README.md) · +[Owning RFC](../../../../docs/architecture/rfcs/long-running-agent-reliability-diagnostics-governed-delivery-v0.md) + +## English + +This is an **operator-run, offline rehearsal profile**, using the existing +diagnostic ledger and CLI. It makes export, deletion readback and recovery +reproducible before a pilot. It introduces no automatic expiry, retention +scheduler, new command, managed backup or production qualification. The P0 +exit gate still needs C0/C1 and measured observer overhead. A deployment's data +owner must accept its retention period and deletion scope separately. + +### Declare the boundary before collecting events + +Keep a private operator note with the exact goal/session and run identity, +data owner, permitted storage location, retention deadline (timezone-aware), +deletion scope and recovery requirement. Choose a finite period before the +pilot; this reference does not invent a universal period. Apply it to positive, +null, degraded, quarantined and invalid runs equally. An unresolved integrity +failure remains a failure; expiration must not improve a reported denominator. + +The envelope/stats allowlist remains the collection boundary. A byte-preserving +archive can include corrupt bytes or invalid records already in the source; +copying them does **not** certify public safety. Keep the ledger, readbacks, +hash and operator note private. Share only reviewed public-safe aggregates. + +| Lifecycle | Required operator evidence | +| --- | --- | +| Collect | Declared identity and finite retention deadline; default-off observer explicitly enabled for that session | +| Freeze | Observer hooks detached, pending flush settled, and no observer/ingest writer remains for this ledger | +| Export | Whole ledger, SHA-256, fixed-time receipt/projection and pinned installed revision; no filtering of negative records | +| Verify | Same bytes/hash and same receipt/projection from an isolated copy; source still matches the export | +| Delete | Scoped authorization, deadline/hold decision and verified export when recovery is required; missing-ledger readback is `invalid` | +| Restore | Authorization to retain the data again; same goal, no active writer, absent destination, exclusive creation and identical readback | +| Expire all copies | Account for source, exports, copy runtimes, readback files and external backups; never claim secure erasure from unlink alone | + +The deadline and hold decision are manual obligations in this reference, +not machine-enforced settings. If automatic TTL, per-session pruning, concurrent +rotation, cross-host/BYOC backup or tenancy is required, hold that deployment +until its lifecycle owner supplies and qualifies those behaviors. + +### Stop collection without changing worker authority + +Unset the three required variables **before the next harness launch**: + +```sh +unset LOOPX_DSH_SHADOW_OBSERVER_GOAL_ID +unset LOOPX_DSH_SHADOW_OBSERVER_SESSION_ID +unset LOOPX_DSH_SHADOW_OBSERVER_RUN_IDENTITY_JSON +``` + +This leaves the observer row on its feature-off path at the next launch; it +does not detach hooks in an already running process. Use the harness owner's +approved lifecycle to dispose/detach that observer and wait for its final flush. +If this cannot be proven without disrupting an active worker, postpone the +offline operation. Do not let a retention operation stop, resume or retry the +worker. Unsetting optional variables alone is insufficient. + +### Export, verify, delete and restore + +The POSIX recipe below operates on **one frozen, owner-authorized ledger**. +Set `diagnostic_runtime` to its explicit runtime root, `diagnostic_goal` to its +exact goal id and `diagnostic_as_of` to one timezone-aware replay timestamp. +Use the same installed `loopx` revision throughout and record `loopx --version`. +If the DSH provider has a custom `LOOPX_DSH_SHADOW_OBSERVER_LEDGER_DIR`, verify +that its parent is the runtime root used here. Do not infer a ledger from the +current project or the CLI's default runtime. + +Filename normalization currently replaces `:` with `_`, and some filesystems +ignore case. Distinct goal ids can therefore share a filename. The ownership +check below refuses mixed, foreign or unparseable records before deletion; +it does not qualify multi-tenant isolation. Reserve a unique filename for the +rehearsal and investigate ambiguous ownership separately. + +```sh +set -eu +: "${diagnostic_runtime:?set the frozen ledger runtime root}" +: "${diagnostic_goal:?set the exact goal id}" +: "${diagnostic_as_of:?set a fixed timezone-aware replay timestamp}" +umask 077 +diagnostic_archive=$(mktemp -d) +loopx --version > "$diagnostic_archive/version.txt" +loopx --runtime-root "$diagnostic_runtime" --format json reliability-diagnostics \ + status --goal-id "$diagnostic_goal" --with-receipt --as-of "$diagnostic_as_of" \ + > "$diagnostic_archive/before.json" +diagnostic_ref=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["ledger_ref"])' \ + "$diagnostic_archive/before.json") +diagnostic_ledger="$diagnostic_runtime/$diagnostic_ref" +test ! -L "$diagnostic_ledger" && test -f "$diagnostic_ledger" +python3 - "$diagnostic_ledger" "$diagnostic_goal" <<'PY' +import json, sys +from pathlib import Path +rows = [json.loads(line) for line in Path(sys.argv[1]).read_text().splitlines() if line.strip()] +if not rows or any(not isinstance(row, dict) or row.get("goal_id") != sys.argv[2] for row in rows): + raise SystemExit("ownership uncertain: hold deletion and investigate privately") +PY +diagnostic_copy_runtime="$diagnostic_archive/readback-runtime" +mkdir -p "$(dirname "$diagnostic_copy_runtime/$diagnostic_ref")" +cp "$diagnostic_ledger" "$diagnostic_copy_runtime/$diagnostic_ref" +shasum -a 256 < "$diagnostic_ledger" > "$diagnostic_archive/ledger.sha256" +cmp "$diagnostic_ledger" "$diagnostic_copy_runtime/$diagnostic_ref" +loopx --runtime-root "$diagnostic_copy_runtime" --format json reliability-diagnostics \ + status --goal-id "$diagnostic_goal" --with-receipt --as-of "$diagnostic_as_of" \ + > "$diagnostic_archive/export.json" +python3 -c 'import json,sys; assert json.load(open(sys.argv[1])) == json.load(open(sys.argv[2])), "export readback changed"' \ + "$diagnostic_archive/before.json" "$diagnostic_archive/export.json" + +# Continue only after the owner's deletion/hold decision and retention deadline check. +shasum -a 256 < "$diagnostic_ledger" > "$diagnostic_archive/pre-delete.sha256" +cmp "$diagnostic_archive/ledger.sha256" "$diagnostic_archive/pre-delete.sha256" +rm -- "$diagnostic_ledger" +loopx --runtime-root "$diagnostic_runtime" --format json reliability-diagnostics \ + receipt --goal-id "$diagnostic_goal" > "$diagnostic_archive/after-delete.json" +python3 - "$diagnostic_archive/after-delete.json" <<'PY' +import json, sys +receipt = json.load(open(sys.argv[1]))["receipt"] +assert receipt["status"] == "invalid" and "no_observations" in receipt["reason_codes"] +assert receipt["persisted_event_count"] == 0 +PY + +# Optional recovery rehearsal: requires permission to retain the data again. +shasum -a 256 < "$diagnostic_copy_runtime/$diagnostic_ref" > "$diagnostic_archive/pre-restore.sha256" +cmp "$diagnostic_archive/ledger.sha256" "$diagnostic_archive/pre-restore.sha256" +python3 - "$diagnostic_copy_runtime/$diagnostic_ref" "$diagnostic_ledger" <<'PY' +import sys +from pathlib import Path +data = Path(sys.argv[1]).read_bytes() +with Path(sys.argv[2]).open("xb") as destination: + destination.write(data) # refuse any existing destination, including a restarted writer's file +PY +cmp "$diagnostic_ledger" "$diagnostic_copy_runtime/$diagnostic_ref" +loopx --runtime-root "$diagnostic_runtime" --format json reliability-diagnostics \ + status --goal-id "$diagnostic_goal" --with-receipt --as-of "$diagnostic_as_of" \ + > "$diagnostic_archive/restored.json" +python3 -c 'import json,sys; assert json.load(open(sys.argv[1])) == json.load(open(sys.argv[2])), "restored readback changed"' \ + "$diagnostic_archive/before.json" "$diagnostic_archive/restored.json" +``` + +For permanent deletion, omit recovery and expire the private archive and every +other retained copy under the owner's policy. A retained export makes this a +source-file deletion rehearsal, not complete data deletion. These commands do +not touch Goal, Todo, quota, gate or worker-session state and do not enable the +observer. Keep it disabled until a separately authorized collection resumes. + +Do not restore by appending accepted envelopes, resetting sequence numbers, +merging sessions or re-ingesting selected rows. `ingest` is validation, not a +byte-preserving restore API: it can replace invalid input with a new violation +marker. Copy the entire frozen ledger to an absent destination so stats, gaps, +failure markers and malformed bytes retain their original meaning. + +### Reproducible validation and remaining evidence + +```sh +# From the source checkout; creates and deletes only its own temporary synthetic state. +uv run --extra test python examples/reliability_diagnostics/ledger-retention-smoke.py + +# With a non-editable wheel installed into a disposable environment: +# use that environment's Python; --installed rejects checkout imports. +python examples/reliability_diagnostics/ledger-retention-smoke.py --installed +``` + +The smoke runs the real CLI against a disposable filesystem, exports and +replays a degraded fixture and a refused-control-input ledger, deletes the +source, verifies invalid missing-ledger evidence, then restores exact bytes and +receipt/projection. It also checks export tampering detection, overwrite refusal +and unchanged synthetic sibling state. This proves offline recovery mechanics; +it measures neither observer CPU/RSS/bytes/latency nor actual harness lifecycle +or live C0/C1 non-interference. Record the revision, commands, failures/skips, +operator stop evidence and policy acceptance in the owning issue before a pilot. + +## 中文 + +这是复用现有 ledger 和 CLI 的**人工执行、离线演练方案**,让 pilot 之前的导出、删除读回与 +恢复可复现。它没有新增自动过期、retention scheduler、命令或托管备份,也不构成生产验收。 +P0 exit 仍需 C0/C1 与 observer 开销实测;部署的数据 owner 须另行接受保留期限和删除范围。 + +收集前在私有操作记录里固定 goal/session/run identity、数据 owner、存储位置、带时区的有限 +保留截止时间、删除范围与恢复要求。正面、空结果、degraded、quarantined 和 invalid 运行采用 +同一规则;到期删除不能美化已报告的分母。这里的截止时间和 hold 决策是人工义务,并非已实现 +的机器配置。自动 TTL、按 session 裁剪、并发轮转、跨 host/BYOC 备份与多租户须由其 lifecycle +owner 实现并独立验收,不能从此演练推导。 + +envelope/stats allowlist 仍是采集边界。完整字节副本可能保留源文件已有的损坏或非法记录, +不能因此宣称 public-safe;ledger、读回、hash 和操作记录均保留在私有存储,只分享审核后的 +public-safe 聚合。保留全部失败标记,不筛选“成功”行。 + +离线步骤和证据与上面的 lifecycle 表及 POSIX recipe 相同: + +1. 在下一次 harness 启动前 unset 三个必需变量;这不会卸载已运行进程的 hooks。由 harness + owner 按已授权生命周期 detach/dispose observer,等待最后 flush,并确认无 observer/ingest + writer。若会干扰活跃 worker,则延期;retention 不能取得 stop/resume/retry worker 的权限。 +2. 明确 `diagnostic_runtime`、准确的 `diagnostic_goal` 和固定带时区 `diagnostic_as_of`,记录 + 同一安装版本。自定义 DSH ledger 目录须与此 runtime 对齐,不能依赖当前项目或默认路径。 +3. 使用 recipe 的归属检查;目前 `:` 会被映射为 `_`,部分文件系统忽略大小写,不同 goal + 可能共用文件名。混合、外来或不可解析行须暂停删除,另行调查;此方案没有证明租户隔离。 +4. 完整导出、记录 SHA-256 和固定时间 receipt/projection,在隔离副本里读回并比较;删除前 + 再比较源 hash。只有 owner 已授权、期限/hold 决策已核实才执行单文件删除。 +5. 删除后 receipt 必须为 `invalid`、包含 `no_observations` 且 persisted count 为 0。 +6. 如需恢复演练,先取得再次保留数据的许可,验证副本 hash,并用 exclusive creation 写入 + 不存在的目标,拒绝覆盖重新启动的 writer 文件;完整字节和 receipt/projection 必须一致。 +7. 永久删除应跳过恢复,并按 owner policy 处理原件、导出、副本 runtime、读回及外部备份。 + 留有导出只能称源文件删除演练,unlink 不能证明安全擦除。整个过程不修改 Goal/Todo/quota/ + gate/worker session,也不启用 observer;继续采集须另行授权。 + +不要用追加合法 envelope、重置 sequence、合并 session 或筛选行后 ingest 来恢复。`ingest` +不是字节保真恢复 API:它可能用新的 violation marker 替代非法输入。恢复整个冻结文件到 +不存在的目标,才能保留 stats、缺口、失败标记及损坏字节的原始意义。 + +上面的两条验证命令只在临时合成状态中运行真实 CLI。`--installed` 要求非 editable 的 wheel +安装并拒绝 checkout import;演练 degraded 和拒绝控制输入的 invalid ledger,验证导出副本、 +丢失后的 invalid 证据、恢复前后完全一致、篡改检测、拒绝覆盖和其它合成状态不变。它只证明 +离线恢复机制,没有测 observer CPU/RSS/bytes/latency,也未验真实 harness 停机或 live C0/C1。 +pilot 前须在所属 issue 记录 revision、命令、通过/失败/跳过、停写证据与 policy 接受决定。 From 422b30005b48aa723f3ca240cd16fb081000f5f0 Mon Sep 17 00:00:00 2001 From: Lihua <1017343802@qq.com> Date: Mon, 28 Sep 2026 02:44:28 -0700 Subject: [PATCH 3/4] chore(semantics): refresh contract registry read location Signed-off-by: Lihua <1017343802@qq.com> --- loopx/semantics/project_registry_io_manifest_v1.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopx/semantics/project_registry_io_manifest_v1.json b/loopx/semantics/project_registry_io_manifest_v1.json index 09c271ee70..f11501031e 100644 --- a/loopx/semantics/project_registry_io_manifest_v1.json +++ b/loopx/semantics/project_registry_io_manifest_v1.json @@ -887,7 +887,7 @@ }, { "site": "loopx/contract.py::.check_contract::codec_read:load_registry#1", - "line": 1014, + "line": 1027, "column": 20, "kind": "codec_read", "api": "load_registry", From f3ab983ef0b3c283f6043bc138c789f3afe812d8 Mon Sep 17 00:00:00 2001 From: Lihua <1017343802@qq.com> Date: Mon, 28 Sep 2026 07:31:10 -0700 Subject: [PATCH 4/4] chore(semantics): align contract read with refreshed main Signed-off-by: Lihua <1017343802@qq.com> --- loopx/semantics/project_registry_io_manifest_v1.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopx/semantics/project_registry_io_manifest_v1.json b/loopx/semantics/project_registry_io_manifest_v1.json index c55b2a07a4..6fb29e027d 100644 --- a/loopx/semantics/project_registry_io_manifest_v1.json +++ b/loopx/semantics/project_registry_io_manifest_v1.json @@ -943,7 +943,7 @@ }, { "site": "loopx/contract.py::.check_contract::codec_read:load_registry#1", - "line": 1027, + "line": 1063, "column": 20, "kind": "codec_read", "api": "load_registry",