openclaw/docs/cli
Ayaan Zaidi 5e209925e4
fix(doctor): retained session-source warning never clears after deferred plugin migrations complete (#160755)
Closes #160689

## What Problem This Solves

Fixes: `openclaw doctor --session-sqlite inspect` keeps reporting `plugin_migration_source_retained` after deferred plugin migrations complete, and repeated `openclaw doctor --fix` never clears it, when the import receipt includes unindexed session history with `.trajectory-path.json` pointer sidecars.

## User Impact

User impact: after upgrading with deferred plugin migrations (for example Codex or Brave), `doctor --fix` archives each unindexed transcript together with its trajectory pointer, and installs already left with stranded pointers get them archived on the next `doctor --fix`, so the warning clears.

## Why This Change Was Made

A deferred import receipt captures each discovered transcript together with its trajectory and pointer sidecar. When the plugin later completes, settlement no longer rediscovers that history, so its transcripts are moved by the unreferenced-JSONL sweep, which moved only `.jsonl` files. The pointer (a `.json` file) stayed live. The retained check fires while any receipt source is live, so the warning never cleared.

Doctor's archive sweep now moves a transcript's pointer sidecar with it. For installs an earlier release already left in that state, the same sweep also archives a receipt-captured pointer whose receipt-verified transcript is no longer live. Both paths use the existing archive move: identity and byte checks, a migration-manifest entry, and `doctor --session-sqlite restore` recovery. Nothing is deleted. Pointers still referenced by a live index, retained for another owner, in conflict with the receipt, or (during settlement) outside the receipt are left alone.

Update behavior: no schema, receipt or stored-field changes. The installed updater runs first, unchanged. The candidate's Doctor keys on the deferred-plugin session receipt and migration manifests that 2026.9.5/2026.9.6 already write, so the first `doctor --fix` after updating repairs existing stranded installs. Agent/state DB `user_version` and schema are identical to `main` after the same migration.

Related: introduced when deferred-import settlement began archiving receipt-captured unindexed history (#150015, first shipped in 2026.9.5).

No overlap with Pash/Sarah changes.

Thanks @spikewillcocks for the detailed report and receipt analysis.

## Evidence

Real CLI, isolated `--profile p160689base` / `p160689cand` with task-owned `OPENCLAW_HOME`, `OPENCLAW_STATE_DIR` and `OPENCLAW_CONFIG_PATH`; every Doctor run first printed the resolved state dir, config path and session DB path from the same binary. State: a file-era `sessions.json` (1 indexed session) plus 3 unindexed transcripts, each with `.trajectory.jsonl` and `.trajectory-path.json` (pointer format from v2026.9.5), plus unrelated `notes.txt` and `custom-settings.json`. The **published 2026.9.5** package ran `doctor --fix` with `brave` configured but its package unreachable, which deferred the migration and wrote the import receipt. The source checkout then completed the `brave` migration, as in the report.

- **Base** (`origin/main` 9366fd94e1): settlement archived the transcripts and left `history-{1,2,3}.trajectory-path.json` live. `inspect` → `1 issue(s)` `[plugin_migration_source_retained] … await archival. Run openclaw doctor --fix to finish.` A second `doctor --fix` changed nothing and `inspect` still reported it.
- **Candidate, same 2026.9.5 state**: `doctor --fix` archived all 4 pointers with their transcripts into `agents/main/session-sqlite-import-archive/` (for example `archive-tier.history-1.trajectory-path.json.imported-…`, manifest kind `trajectory`, reason `unreferenced-history`). Each archive's SHA-256 matches the receipt. `inspect` → `0 issue(s)`. A second `doctor --fix` wrote a run manifest with `completedMoves=0`, and no other file changed.
- **Candidate on the stranded base state** (the reporter's situation): `doctor --fix` → `Archived 3 legacy transcript artifact(s)`, the three stranded pointers now in the archive with receipt-matching SHA-256. `inspect` → `0 issue(s)`. A second run → `completedMoves=0`.
- **Controls**: `notes.txt` and `custom-settings.json` in the same sessions folder were byte-identical in every run. The regression test covers the explicit settlement path (`settleRetainedDoctorSessionSources`). There, a transcript and pointer written after the receipt (live, not covered by it) stay byte-identical, and so does an unrelated file. When the plugin completes during config preflight instead, Doctor's existing sweep archives every unreferenced JSONL in the folder, including ones written after the receipt. `main` does the same with `late.jsonl`, but leaves `late.trajectory-path.json` orphaned; the candidate moves that pointer with its transcript. A pointer still referenced by a live index or retained for another owner is skipped by the same guards that protect transcripts.
- Schema: after the same migration, base and candidate agent DB `user_version=23`, state DB `user_version=19`, with identical `sqlite_master` hashes.
- Regression test `doctor-session-sqlite.shared-orphan.test.ts` covers both paths. First, settlement of a deferred receipt with unindexed history and a pointer. Second, repair of a pointer an earlier settlement left behind; that half requires a distinct second archive move with receipt-matching bytes. The test fails on `main` because the pointer is still live after settlement. With only the stranded-pointer pass disabled, it fails at the repair step because the pointer stays live. It passes with the fix. Related suites (`deferred-plugin`, `manifests`, `retained-source-verification`, `active-settlement`, `indexless`, `archive-safety`, `recovery-shared-owners`, `discovery`, `recovery`, `receipt-recovery`, `doctor-session-sqlite`) pass: 12 files, 139 tests.
- Test cost: the new test is 1.7s locally and 1.8s in CI (`checks-node-changed-compact-large-19-1`, shard `agentic-commands-doctor-sessions-cron-hosted-1`, run 36491519850). `pnpm test src/commands/doctor-session-sqlite.shared-orphan.test.ts --maxWorkers=1` takes 34.4s wall for the whole file, which is mostly transform; its three tests run in about 6s. It uses no timers, sleeps, polling or process boots, and reuses the file's existing fixture and imports.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-09-29 05:40:51 +05:30
..
doctor fix(doctor): retained session-source warning never clears after deferred plugin migrations complete (#160755) 2026-09-29 05:40:51 +05:30
gateway fix(daemon): forced reinstall moves an unpinned Bun Gateway service to Node (#160189) 2026-09-28 12:26:32 -07:00
mcp feat(plugins): show installed accounts and credential status (#160092) 2026-09-28 15:18:42 -07:00
plugins fix: preserve listener settings when plugins update (#160682) 2026-09-28 14:07:32 -07:00
policy fix: skip official setup approvals and default to Astra (#145646) 2026-09-12 00:34:25 -07:00
update fix(doctor): reclaim legacy pnpm runtimes and TMP/TEMP service scratch (#160164) 2026-09-28 13:48:32 -07:00
acp.md fix: stop ACP client when terminal input closes (#148611) 2026-09-14 19:20:13 -07:00
agent.md fix(agents): session-ID lookup loses partition ownership (#155741) 2026-09-22 14:03:52 -07:00
agents.md fix(cli): never fall back to local state when a remote Gateway is unreachable (#159223) 2026-09-26 17:22:51 -07:00
approvals.md feat(tools): explain terminal access restrictions (#157014) 2026-09-24 02:53:23 -05:00
attach.md
audit.md refactor: remove Tasks and TaskFlow runtime (#159179) 2026-09-27 10:40:29 -07:00
backup.md fix(update): back up every database before migrations and restore them on rollback (#158163) 2026-09-26 02:30:17 +00:00
browser.md feat(browser): unify local Chrome setup across desktop and terminal (#152057) 2026-09-22 06:28:29 -07:00
channels.md fix(channels): include runtime namespaces in channel logs (#159244) 2026-09-26 17:47:31 -07:00
clawbot.md docs: correct verified accuracy defects in CLI, tools, and automation pages (#143179) 2026-09-09 23:57:06 +09:00
claws.md fix(claws): preserve user files when a workspace scan is incomplete (#154797) 2026-09-22 02:06:28 -07:00
completion.md fix(cli): load plugin commands once when building completion (#160546) 2026-09-28 09:55:10 -07:00
config.md fix(cli): emit JSON errors for invalid config output flags (#159760) 2026-09-27 09:18:06 -07:00
configure.md docs: STE structural cleanup for gateway, cli and concepts (46 audit findings) (#143931) 2026-09-10 18:50:32 +08:00
connect.md fix(cli): explain how to reconnect when openclaw connect has no target on a paired node (#159810) 2026-09-27 15:14:09 -07:00
cron.md fix(cron): report unknown delivery when webhook responses time out (#159840) 2026-09-27 15:36:15 -05:00
daemon.md fix(gateway): support pinned daemon runtime paths (#82290) 2026-09-16 21:20:21 -06:00
dashboard.md fix: preserve dashboard HTTP errors when diagnostics fail (#145227) 2026-09-11 13:46:03 -07:00
devices.md fix(pairing): device join codes ignore gateway.publicOrigin behind public ingress (#159465) 2026-09-27 12:07:50 -07:00
directory.md fix(directory): reject explicitly blank channel selectors (#153731) 2026-09-20 21:40:05 +05:30
dns.md docs: fix 20 link defects confirmed live in the verified backlog (#144133) 2026-09-11 03:48:10 +08:00
docs.md fix(docs): reject malformed search result collections (#145613) 2026-09-12 00:20:46 -07:00
doctor.md fix(usage): prevent refresh OOMs on large SQLite sessions (#156937) 2026-09-24 02:50:28 +00:00
file-transfer.md docs: close the small audit categories (generated, governance, link, split) (#144029) 2026-09-10 21:52:03 +08:00
fleet.md feat(fleet): show the recorded container runtime in status (#144691) 2026-09-19 17:54:21 +01:00
gateway.md docs(gateway): warn that installation starts the service (#139562) 2026-09-10 17:23:20 +05:30
health.md fix(cli): show configured plugin failures in health reports (#118013) 2026-09-27 18:22:09 -07:00
hooks.md docs: STE pass on terminology consistency and run-on sentences (#143770) 2026-09-10 15:51:49 +09:00
index.md feat(users): merge duplicate user profiles (#159889) 2026-09-27 16:18:08 -07:00
infer.md fix(cli): defer inference runtimes until command execution (#158624) 2026-09-26 03:50:34 +00:00
logs.md
mcp.md docs: fix one-way and absolute links across cli, tools, gateway, and channels (#143157) 2026-09-10 07:40:16 +09:00
memory.md fix(memory): retain forget lineage through writer admission (#152902) 2026-09-19 07:43:49 -07:00
message.md perf(cli): skip migration preflight for Gateway message actions (#157448) 2026-09-24 11:10:08 -07:00
migrate.md fix: clarify Codex onboarding migration scope (#151383) 2026-09-21 00:57:52 -07:00
models.md improve(openai): mark Sign in with ChatGPT as Beta (#160011) 2026-09-28 01:39:33 +00:00
node.md fix(node): reconnect after fallback pairing code expires (#159360) 2026-09-26 20:39:25 -07:00
nodes.md fix(cli): reject empty node invocation keys before lookup (#145032) 2026-09-20 15:50:30 +05:30
onboard.md fix(onboarding): reject impossible workspaces and name the failing setup step (#160373) 2026-09-28 04:28:29 -07:00
openclaw.md refactor(runtime): deslop daemon, node host, TUI and runtime hosts (#160454) 2026-09-28 09:20:48 -07:00
pairing.md docs: STE structural cleanup for gateway, cli and concepts (46 audit findings) (#143931) 2026-09-10 18:50:32 +08:00
path.md refactor(channels): deslop smaller channel plugins (#157825) 2026-09-24 22:52:40 -07:00
plugins.md fix(plugins): allow reloads to wait for long-running work (#158688) 2026-09-26 08:08:14 +00:00
policy.md docs: close remaining one-way link findings in cli, plugins, tools, providers (#143855) 2026-09-10 16:15:08 +08:00
promos.md docs: fix one-way and absolute links across cli, tools, gateway, and channels (#143157) 2026-09-10 07:40:16 +09:00
proxy.md fix(proxy): keep capture persistence off the main thread (#158848) 2026-09-26 13:45:36 -07:00
qr.md fix(pairing): device join codes ignore gateway.publicOrigin behind public ingress (#159465) 2026-09-27 12:07:50 -07:00
reset.md fix(reset): remove canonical SQLite session history (#159419) 2026-09-27 17:36:43 -07:00
resume.md
sandbox.md refactor(commands): deslop commands (#158487) 2026-09-26 00:33:06 -07:00
secrets.md fix(doctor): agree with secrets audit on non-secret API-key markers (#156216) 2026-09-23 06:24:20 +00:00
security.md fix: bound filesystem reads and keep sandbox reads responsive (#146654) 2026-09-12 19:41:19 -07:00
sessions.md refactor: remove Tasks and TaskFlow runtime (#159179) 2026-09-27 10:40:29 -07:00
setup.md fix(setup): honor baseline skip-bootstrap (#115945) 2026-09-26 18:15:06 +08:00
skills.md fix(skills): restore usage counts and current Workshop inventory (#151048) 2026-09-18 12:17:09 +05:30
status.md fix(status): warn when the running Gateway Node path is gone (#157190) 2026-09-28 21:19:12 +05:30
system.md docs(cli): document system Gateway port and password options (#139071) 2026-09-10 16:01:11 +05:30
transcripts.md fix(gateway): apply settings without unnecessary restarts (#154792) 2026-09-21 11:50:57 -07:00
triage.md fix(triage): stop reporting failed updates as resolved (#153443) 2026-09-20 02:38:30 -07:00
tui.md docs: close remaining one-way link findings in cli, plugins, tools, providers (#143855) 2026-09-10 16:15:08 +08:00
uninstall.md docs: fix one-way and absolute links across cli, tools, gateway, and channels (#143157) 2026-09-10 07:40:16 +09:00
update.md fix: updates report plugin failures as database errors (#160436) 2026-09-28 11:04:23 -07:00
users.md feat(users): merge duplicate user profiles (#159889) 2026-09-27 16:18:08 -07:00
voicecall.md docs(plugins): remove obsolete Gateway restart guidance (#146516) 2026-09-12 16:48:13 -07:00
webhooks.md refactor: retire the TaskFlow Webhooks plugin (#158225) 2026-09-25 20:29:15 -07:00
wiki.md
workboard.md refactor: remove Tasks and TaskFlow runtime (#159179) 2026-09-27 10:40:29 -07:00
worker.md perf(nodes): keep prompt caching effective for sessions on nodes (#160179) 2026-09-28 10:31:33 -07:00