Skip to content

feat(M023): storage lifecycle, disk reclamation, and orphan cleanup - #40

Open
hiepau1231 wants to merge 60 commits into
mainfrom
feat/m023-storage-lifecycle-disk-reclamation
Open

feat(M023): storage lifecycle, disk reclamation, and orphan cleanup#40
hiepau1231 wants to merge 60 commits into
mainfrom
feat/m023-storage-lifecycle-disk-reclamation

Conversation

@hiepau1231

@hiepau1231 hiepau1231 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

M023 makes Muster account for its own disk footprint and actually give bytes back — without deleting a single row of conversation history and without bumping the schema version.

The milestone is ordered so the measurement instrument lands first, and every later byte claim is forced through it. The storage report and the reclamation therefore cannot disagree.

  • Measurement first (S01). A storageReport request kind on the SQLite worker protocol returns file/WAL/shm bytes, page and freelist counts, page size, live auto_vacuum mode, and a descending per-table breakdown — plus a four-bucket orphan classifier separating the live SQLite trio from dead legacy stores, active leases, and stale leases. Both tracked ledgers report tableBytesSource: dbstat from a real Extension Host, so dbstat availability under Electron is proven rather than assumed.
  • Freed pages actually leave the file (S02). New stores open auto_vacuum = INCREMENTAL with journal_size_limit = 16777216; reclamation runs in bounded page batches with checked WAL checkpoints. Legacy NONE stores need roughly twice the file size in free space, so an fs.statfsSync precheck refuses up front reporting required vs available bytes instead of dying mid-VACUUM. A legacy fixture reopens unmutated and SQLITE_SCHEMA_VERSION stays 2.
  • Recurring retention that keeps history (S03). The single activation-time retention call becomes a recurring scheduler on the existing single-flight guard. Heavy tool_calls.payload_json diff text is stripped on aged turns while path and change summaries survive behind an explicit retentionTruncated flag, so the webview can distinguish truncation from an empty change set.
  • R044 repaired structurally. The terminal-task DELETE FROM turns / DELETE FROM messages path was removed, not gated behind a flag, so retention cannot be reconfigured into deleting history.
  • Orphan cleanup and uninstall (S04, S06). Classification now precedes the confirmation prompt, an empty removable set never prompts, and removal is pinned to the exact snapshot the prompt rendered — prompt/mutation divergence is impossible by construction rather than by assertion. The vscode:uninstall hook is profile-aware: activation registers the actual context.globalStorageUri; uninstall reclaims only an exact registered extension-id path (or the explicit test override), never guesses Stable/Insiders/portable locations. Concurrent Extension Hosts tolerate Windows registry-write contention without blocking activation.
  • One liveness predicate (S09). Terminal workflow metadata reclamation and payload retention could each weaken the other's guarantee, so the predicate is extracted to exactly one definition consumed by both the schema trigger and the reclamation command, with a pinned normalized trigger fingerprint proving the extraction is token-preserving.

Composition detail worth knowing: truncation alone only moves bytes to the freelist. The byte tests assert on-disk shrink only after the reclaim call, so S03 cannot report savings that never materialise.

Observed in one continuous packaged two-window run: fileBytes 6,811,648 → 1,507,328 with freelistCount: 0; tool_calls bytes 6,127,616 → 819,200 while durable counts stay identical at tasks 8 / turns 12 / messages 14. Uninstall emits reclaimed_bytes: 2448 / absent / refused, exit 0 each, no paths in stdout.

52 commits, 78 files changed. No .gsd/ planning artifacts in the diff.

Merge resolution — please read, it touches the M022 security boundary

This branch was cut from 168b39c (the M021 merge), before M022 landed the UAT surface tiering, so main was 35 commits ahead and the conflict fell directly on the boundary M022 introduced.

M022 redefined isUatModeEnabled as resolveUatSurface(...) !== 'none', which now returns true for a Production VSIX with MUSTER_UAT_MODE=1 — that is the redacted packaging tier the real-install gate needs. M023 had gated its store-mutating harness commands on that same boolean. Taking either side verbatim would have reopened exactly the marketplace exposure M022 closed in its review round 2.

Conflict Resolution
registerLiveUatCommands signature — M022 added tier, M023 added storage args Kept both: (context, uatSurface, storageDirectory, reclaimOrphanedFilesForUat). All six M023 command ids register after the tier !== 'full' early return, so a packaging host cannot reach them
M023's two non-command affordances were gated on liveUatEnabled, which is now true at the packaging tier Introduced fullUatSurface (uatSurface === 'full'). The path-bearing DOM render probe (D079) and the retention-interval override are both keyed off it, keeping them Development-only
uat-commands.test.ts Both sides only appended tests — kept both
uat-surface-tier.invariant.test.ts requires every declared command to be bucketed deliberately Classified the six M023 ids as mutable/stateful, and added a case asserting the probe and retention override stay behind the stronger full check
sqlite-only-activation.test.ts pinned the old call signature Updated the regex to the merged four-argument form

liveUatEnabled deliberately stays uatSurface !== 'none' — narrowing it to full would have broken M022's packaging gate, which needs bridgeHealth / runDeactivate from a Production install.

Verification

CI is green on 1ec4b47 (run 30683259259) — all six jobs pass: compile, Packaging gate (Extension Host), Packaging install gate (real install), and SQLite Extension Host on 1.100.0 / 1.101.0 / stable.

Local gates, run against the merge commit:

Gate Result
npx tsc -p . --noEmit exit 0
npm test -- --run 201 files / 2598 passed / 4 skipped
npm run compile exit 0
npm run check:svelte 0 errors, 0 warnings
npm run test:webview 82 passed
npm run test:m023-evidence-gate pass (six static verifiers, one CI invocation)
test:source-boundary, test:source-boundary:fixtures, test:evidence pass
test:settings-docs, test:settings-live-evidence pass
test:m022-s02test:m022-s05 pass — M022's gates still hold post-merge

The current 2598/201 figure includes the post-review storage lifecycle coverage; no test was dropped or newly skipped. The later flake fix touches only an e2e/ spec, which is outside vitest's include.

Post-review live UAT rerun (2026-08-02): all packaged Electron runners were re-executed after the storage fixes: test:m023-s05-storage-lifecycle-live-uat passed scenarios A–I; test:m023-s07-truncated-render-live-uat passed; and the S08 orphan ledger was emitted by the same two-window lifecycle run. The three tracked ledgers are schema-validated, ok: true, and pin their commitSha to 03e6e84fad4faf44d2874214efa5fb3e51ed6151, the exact source candidate packaged for those runs. npm run test:m023-evidence-gate passes.

The one CI failure, and why the fix is a test fix

The first CI run on the merge commit failed on exactly one test — M020 S03 collapse — where expect(expandedBox!.height).toBeGreaterThan(1) received 0. Every assertion around it passed: aria-expanded was true, data-collapsed was false, and the added diff line was visible. That combination rules out a rendering regression and points at timing.

The panel expands through a grid-template-rows: 0fr → 1fr transition. Playwright's attribute and visibility assertions auto-retry, so they settle the moment the class flips — but boundingBox() is a single sample with no retry, so it can be taken while the row is still animating. A loaded Linux runner is simply likelier to land inside that window than a local machine.

Established by controlled experiment rather than inference:

  • Temporarily raising the transition to 5s reproduced the failure locally at height 0.046875 — mid-animation.
  • The polled assertion passed with the transition still at 1s, five times slower than production.
  • Production CSS is unchanged at 0.2s; only the assertion changed.
  • Negative control: with the threshold temporarily set to 999999 the test fails and reports the real settled height of 21.33px, so the assertion still has teeth rather than passing vacuously.

Backend / area

  • Claude adapter
  • Grok adapter
  • Kiro adapter
  • Codex adapter
  • OpenCode adapter
  • agy adapter
  • Muster Bridge (MCP ask_user)
  • Webview / extension host
  • Docs only
  • Other: SQLite storage lifecycle, retention scheduler, uninstall hook

Checklist

  • npm run compile passes locally
  • Tested in Extension Development Host (F5) — packaged two-window live runs per slice; see the caveat above about post-merge re-execution
  • Updated relevant doc under docs/ (docs/SQLITE-STORAGE.md, plus three tracked evidence ledgers and the requirement-evidence map)

Known limitations and follow-ups

Blocking before the first published release (pre-existing, not introduced here)

  • R035 — migration framework. Per K001, storage is clean-break reset-only at SQLITE_SCHEMA_VERSION = 2; connection.ts rejects every other user_version. Free today at v0.1.0 with no published users, but after the first release any schema bump silently erases task and chat history. M023 shipped zero schema change and did not worsen this.

Verifier hardening

  • scripts/verify-m023-requirement-evidence.test.mjs pins requiredMappings to R040–R045 — its own test name reads maps R040 through R045. That is precisely why R046 sat active for days after shipping in S04: no gate ever observed it. Extending the range would close the blind spot.
  • The narrative figures in docs/plans/m023-requirement-evidence.md are not gated, so quoted ordinals can drift from a regenerated ledger without failing CI.
  • Pre-existing, unrelated to this PR: npm run test:file-drop-docs fails on docs/WEBVIEW.md missing contract marker: ## 12. Workspace file-drop mentions. It fails identically with this branch stashed, none of the files it checks differ from origin/main, and it is not wired into ci.yml — which is why it has gone unnoticed. Worth either fixing or wiring in, but out of scope here.

Needs a human at a real host (5 items, none touching data safety)

Command Palette read-throughs for the S01 storage report and S02 compaction output; a genuine partial-removal failure (chmod 0444 does not prevent unlink on Windows — use an exclusive lock or icacls deny-delete); visual confirmation of the native modal copy for S06/S08; and the real marketplace uninstall flow, which is unexercised by design since VS Code itself invokes the hook.

Cosmetic

  • S04 renders removed: .muster-tasks.json (54 bytes) rather than the UAT spec's literal removed: <basename> bytes: <n>. Content matches intent; either the line or the spec should be aligned.

- src/task/sqlite/client.ts
- src/task/sqlite/protocol.ts
- src/task/sqlite/worker.ts
- src/task/sqlite/rpc.ts
- src/task/sqlite/storage-report.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S01 - Storage accounting and report surface
- Task: T01 - Wired the path-redacted SQLite storage report through DbClient, strict RPC validation, and worker-side page and table accounting.

GSD-Task: S01/T01
- src/host/storage-orphans.ts
- src/host/storage-orphans.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S01 - Storage accounting and report surface
- Task: T02 - Added a path-redacted storage orphan classifier that distinguishes the live SQLite trio, legacy JSON store, active leases, and stale leases.

GSD-Task: S01/T02
- package.json
- src/extension.ts
- src/task/sqlite/sqlite-only-activation.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S01 - Storage accounting and report surface
- Task: T03 - Registered Muster’s storage report command with a path-redacted output channel and store-unavailable diagnostic.

GSD-Task: S01/T03
- scripts/sqlite-extension-host-smoke.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S01 - Storage accounting and report surface
- Task: T04 - Added live Extension Development Host assertions for the packaged SQLite storage report and recorded Electron’s dbstat provenance.

GSD-Task: S01/T04
- src/task/sqlite/connection.ts
- src/task/sqlite/rpc.ts
- src/task/sqlite/storage-pragmas.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T01 - Fresh SQLite stores now claim `auto_vacuum = INCREMENTAL`, owned connections bound residual WAL to 16 MiB, and both measured pragmas are readable through the safe RPC.

GSD-Task: S02/T01
- src/task/sqlite/reclaim.ts
- src/task/sqlite/reclaim.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T02 - Added a worker-local SQLite reclamation module that checkpoint-baselines, boundedly incrementally vacuums fresh stores, and preflight-gates legacy full compaction.

GSD-Task: S02/T02
- src/task/sqlite/rpc.ts
- src/task/sqlite/worker.ts
- src/task/sqlite/protocol.ts
- src/task/sqlite/client.ts
- src/task/sqlite/reclaim-rpc.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T03 - Wired path-redacted SQLite page reclamation through the typed worker RPC and exposed DbClient.reclaimStorage().

GSD-Task: S02/T03
- src/host/sqlite-maintenance-commands.ts
- src/host/sqlite-maintenance-commands.test.ts
- src/extension.ts
- package.json
- docs/SQLITE-STORAGE.md
- src/task/sqlite/sqlite-only-activation.test.ts
- scripts/verify-sqlite-storage-docs.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T04 - Added the user-invocable `muster.compactStorage` command, which dispatches reclamation from measured `auto_vacuum` and writes safe measurements to Muster Storage Report.

GSD-Task: S02/T04
- scripts/sqlite-extension-host-smoke.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T05 - Extended the packaged Extension Host smoke with live storage-pragma and seed/delete/incremental-reclaim assertions.

GSD-Task: S02/T05
- scripts/sqlite-extension-host-smoke.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S02 - Page reclamation for new and legacy databases
- Task: T06 - Extended the packaged Extension Host smoke to reopen a schema-current legacy SQLite store in persistent auto_vacuum NONE mode without mutation.

GSD-Task: S02/T06
- src/shared/tool-file-change-contract.ts
- src/types.ts
- src/shared/tool-file-change-retention.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T01 - Added a fail-closed retention evidence marker and pure transform that removes file diff bytes while retaining safe paths and logical line summaries.

GSD-Task: S03/T01
- src/task/repository.ts
- src/task/retention-row-invariance.test.ts
- src/task/repository.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T02 - Removed terminal retention row deletion so retention preserves task, turn, message, and operation history.

GSD-Task: S03/T02
- src/task/repository.ts
- src/task/retention-file-evidence.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T03 - Wired terminal retention to persist fail-closed, line-summary file-change stripping for turns outside the retained window.

GSD-Task: S03/T03
- src/host/retention-scheduler.ts
- src/host/retention-scheduler.test.ts
- src/extension.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T04 - Replaced one-shot activation retention with a disposable, injectable recurring scheduler.

GSD-Task: S03/T04
- src/host/retention-scheduler.ts
- src/host/sqlite-maintenance-commands.ts
- src/host/retention-report.test.ts
- src/extension.ts
- src/task/repository.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T05 - Added path-free retention pass blocks to Muster Storage Report with completed and failed schedule counts.

GSD-Task: S03/T05
- webview/src/lib/types.ts
- webview/src/lib/tool-diff-view.ts
- webview/src/components/ToolCard.svelte
- webview/src/lib/tool-diff-view.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T06 - Rendered retention-stripped file changes as static line-count summaries without diff disclosure bodies.

GSD-Task: S03/T06
- src/task/m023-s03-retention-bytes.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S03 - File change evidence truncation on a recurring schedule
- Task: T07 - Added an end-to-end retention invariant test proving payload byte reduction, reclaimable file-size reduction, durable-row preservation, and schema stability.

GSD-Task: S03/T07
- src/host/storage-orphans.ts
- src/host/storage-orphans.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S04 - Orphan and uninstall reclamation
- Task: T01 - Added path-safe, best-effort removal of classifier-selected legacy stores and stale leases with reclaimed-byte accounting.

GSD-Task: S04/T01
- src/host/sqlite-maintenance-commands.ts
- src/host/sqlite-maintenance-commands.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S04 - Orphan and uninstall reclamation
- Task: T02 - Added a confirmation-gated, single-flight orphan-reclamation command handler with bounded Storage Report diagnostics.

GSD-Task: S04/T02
- src/extension.ts
- src/task/sqlite/sqlite-only-activation.test.ts
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S04 - Orphan and uninstall reclamation
- Task: T03 - Registered the confirmation-gated orphan reclamation command and declared its VS Code command and uninstall hook.

GSD-Task: S04/T03
- src/uninstall.ts
- scripts/verify-uninstall-entrypoint.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S04 - Orphan and uninstall reclamation
- Task: T04 - Added an extension-id-guarded compiled VS Code uninstall hook that best-effort clears Muster global storage and emits one exit-zero diagnostic.

GSD-Task: S04/T04
- docs/SQLITE-STORAGE.md
- scripts/verify-sqlite-storage-docs.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S04 - Orphan and uninstall reclamation
- Task: T05 - Documented safe orphan reclamation and VS Code uninstall cleanup, with verifier-enforced command and lifecycle markers.

GSD-Task: S04/T05
- src/host/retention-scheduler.ts
- src/host/retention-scheduler.test.ts
- src/extension.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T01 - Added a UAT-only, fail-closed retention interval override while preserving the 30-minute production cadence.

GSD-Task: S05/T01
- src/host/uat-commands.ts
- src/host/uat-commands.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T02 - Added dependency-injected UAT helpers that seed a retention-eligible workload and expose numeric-only storage lifecycle state from the activated production surfaces.

GSD-Task: S05/T02
- src/extension.ts
- src/task/sqlite/sqlite-only-activation.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T03 - Wired UAT-only storage lifecycle commands to the activated repository, SQLite client, and retention-report singletons.

GSD-Task: S05/T03
- scripts/m023-s05-storage-lifecycle-evidence-schema.mjs
- scripts/m023-s05-storage-lifecycle-evidence-schema.test.mjs
- scripts/verify-m023-s05-storage-lifecycle-evidence.test.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T04 - Added a pure, allowlisted storage lifecycle evidence validator with invariant and privacy negative coverage.

GSD-Task: S05/T04
- scripts/m023-s05-storage-lifecycle-evidence-schema.mjs
- scripts/m023-s05-storage-lifecycle-evidence-schema.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T07 - Corrected storage lifecycle row preservation validation to compare seeded and retained snapshots.

GSD-Task: S05/T07
- scripts/sqlite-two-window-live-uat.ts
- scripts/run-sqlite-two-window-live-uat.mjs
- scripts/sqlite-two-window-live-uat.test.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T08 - Added a storage lifecycle scenario to the existing two-window packaged Electron UAT runner.

GSD-Task: S05/T08
- scripts/sqlite-two-window-live-uat.ts
- scripts/sqlite-two-window-live-uat.test.mjs
- docs/plans/m023-s05-storage-lifecycle-evidence.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T10 - Stabilized scenario-H peer mailbox ordering and added privacy-safe restart diagnostics, but the packaged B2 durable-surface readback still times out and no lifecycle evidence was written.

GSD-Task: S05/T10
- scripts/sqlite-two-window-live-uat.ts
- scripts/sqlite-two-window-live-uat.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T11 - Repaired fresh-host Scenario H to prove durable outbox and presentation restoration through legitimate pending-send recovery, with privacy-safe diagnostics; the later scheduled-retention live assertion remains unresolved.

GSD-Task: S05/T11
- src/host/uat-commands.ts
- src/host/uat-commands.test.ts
- scripts/run-sqlite-two-window-live-uat.mjs
- scripts/sqlite-two-window-live-uat.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T12 - Corrected the storage-lifecycle UAT seed to exercise SQLite’s real open-task file-change truncation path and isolated the accelerated timer to orchestrator A.

GSD-Task: S05/T12
- src/task/repository.ts
- src/task/retention-file-evidence.test.ts
- src/host/uat-commands.ts
- src/host/uat-commands.test.ts
- docs/plans/m023-s05-storage-lifecycle-evidence.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S05 - End to end storage lifecycle proof
- Task: T14 - Repaired open-task retention so bounded aged file changes and oversized tool output are atomically truncated, then captured validated two-host lifecycle evidence.

GSD-Task: S05/T14
- src/host/sqlite-maintenance-commands.ts
- src/host/sqlite-maintenance-commands.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S06 - Orphan cleanup command confirmation correctness
- Task: T01 - Made orphan-reclamation confirmation derive its count and byte total from the exact classifier snapshot and skip prompting for an empty set.

GSD-Task: S06/T01
- src/task/sqlite/sqlite-only-activation.test.ts
- docs/SQLITE-STORAGE.md
- scripts/verify-sqlite-storage-docs.test.mjs

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S06 - Orphan cleanup command confirmation correctness
- Task: T02 - Pinned orphan reclamation to its explicit Command Palette entrypoint and documented zero-result and cancellation lifecycle guarantees.

GSD-Task: S06/T02
- webview/src/components/ToolCard.svelte
- webview/src/lib/render-probe.ts
- webview/src/lib/render-probe.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T01 - Added stable ToolCard render markers and a pure DOM collector for retention-summary UAT observations.

GSD-Task: S07/T01
- src/host/webview-render-probe.ts
- src/host/webview-render-probe.test.ts
- src/host/uat-commands.ts
- src/host/uat-commands.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T02 - Added a correlated single-flight host coordinator and UAT-only render-probe command identifier for live webview DOM observations.

GSD-Task: S07/T02
- src/extension.ts
- webview/src/App.svelte
- src/host/uat-commands.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T03 - Wired the UAT-gated host-to-webview render probe round trip for live DOM observations.

GSD-Task: S07/T03
- scripts/m023-s07-truncated-render-evidence-schema.mjs
- scripts/m023-s07-truncated-render-evidence-schema.test.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T04 - Added a fixture-tested M023/S07 evidence schema that accepts only live Extension Development Host DOM provenance for pass verdicts.

GSD-Task: S07/T04
- scripts/m023-s07-render-evidence-assembly.mjs
- scripts/m023-s07-render-evidence-assembly.test.mjs
- scripts/m023-s07-truncated-render-host.ts
- scripts/run-m023-s07-truncated-render-uat.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T05 - Added a packaged single-window Extension Development Host runner and fail-closed pure assembly for truncated-render UAT evidence.

GSD-Task: S07/T05
- docs/plans/m023-s07-truncated-render-evidence.json
- scripts/verify-m023-s07-truncated-render-evidence.test.mjs
- scripts/run-m023-s07-truncated-render-uat.mjs
- scripts/m023-s07-truncated-render-host.ts
- src/shared/tool-file-changes.ts
- src/host/snapshot.ts
- src/host/repository-snapshot.test.ts
- docs/SQLITE-STORAGE.md

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S07 - Live host proof that truncated file change history renders
- Task: T06 - Recorded a schema-validated live Extension Development Host DOM ledger proving retention-truncated file rows render paths and summaries without diff bodies.

GSD-Task: S07/T06
- src/host/uat-orphan-lifecycle.ts
- src/host/uat-orphan-lifecycle.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S08 - Orphan reclamation composed into end to end lifecycle
- Task: T01 - Added path-free orphan lifecycle observations that validate classified cleanup totals and protected live-storage survival.

GSD-Task: S08/T01
- src/host/uat-commands.ts
- src/extension.ts
- src/task/sqlite/sqlite-only-activation.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S08 - Orphan reclamation composed into end to end lifecycle
- Task: T02 - Registered live-UAT-only orphan fixture and production reclamation delegates while preserving the single explicit production handler invocation.

GSD-Task: S08/T02
- scripts/m023-s08-orphan-lifecycle-evidence-schema.mjs
- scripts/m023-s08-orphan-lifecycle-evidence-schema.test.mjs
- scripts/verify-m023-s08-orphan-lifecycle-evidence.test.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S08 - Orphan reclamation composed into end to end lifecycle
- Task: T03 - Added a pure, anti-vacuity S08 orphan lifecycle evidence schema and tracked-artifact verifier command.

GSD-Task: S08/T03
- src/extension.ts
- src/task/sqlite/sqlite-only-activation.test.ts
- scripts/sqlite-two-window-live-uat.ts
- scripts/sqlite-two-window-live-uat.test.mjs
- scripts/run-sqlite-two-window-live-uat.mjs
- package.json
- docs/plans/m023-s08-orphan-lifecycle-evidence.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S08 - Orphan reclamation composed into end to end lifecycle
- Task: T04 - Composed classified orphan reclamation into the packaged two-host lifecycle UAT and emitted validated S08 evidence.

GSD-Task: S08/T04
- docs/plans/m023-requirement-evidence.md
- scripts/verify-m023-requirement-evidence.test.mjs
- package.json

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S08 - Orphan reclamation composed into end to end lifecycle
- Task: T05 - Mapped R040 through R045 to validated S05 and S08 tracked lifecycle evidence with a fail-closed artifact verifier.

GSD-Task: S08/T05
- src/task/repository.ts
- src/task/workflow-metadata-reclamation.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S09 - Terminal workflow metadata reclamation
- Task: T02 - Added a workspace-scoped guarded command that reclaims only safely terminal workflow metadata and reports its removed-run count.

GSD-Task: S09/T02
- src/extension.ts
- src/host/sqlite-maintenance-commands.ts
- src/host/retention-report.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S09 - Terminal workflow metadata reclamation
- Task: T03 - Scheduled payload retention now reclaims safely terminal workflow metadata and reports the removed-run count.

GSD-Task: S09/T03
- src/task/m018-s07-workflow-status-projection.test.ts

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S09 - Terminal workflow metadata reclamation
- Task: T04 - Realigned M018 terminal workflow coverage so payload retention preserves transcript turns while guarded metadata reclamation deletes only safe terminal workflow runs.

GSD-Task: S09/T04
- package.json
- .github/workflows/ci.yml
- docs/plans/m023-requirement-evidence.md

GSD context:
- Milestone: M023 - Storage Lifecycle and Disk Reclamation
- Slice: S09 - Terminal workflow metadata reclamation
- Task: T05 - Added a CI-enforced aggregate for all six M023 static evidence verifiers and corrected R042’s retained-pass citation to the tracked ledger.

GSD-Task: S09/T05
M023 branched from 168b39c (the M021 merge), before M022 landed the UAT
surface tiering, so main was 35 commits ahead and the conflict fell
directly on the security boundary M022 introduced.

M022 redefined isUatModeEnabled as resolveUatSurface(...) !== 'none',
which now returns true for a Production VSIX with MUSTER_UAT_MODE=1 --
the redacted 'packaging' tier the real-install gate needs. M023 had
gated its store-mutating harness commands on that same boolean, so
taking either side verbatim would have reopened the marketplace
exposure M022 closed in its review round 2.

Resolution:
- registerLiveUatCommands keeps M022's tier parameter and gains M023's
  storage args: (context, uatSurface, storageDirectory, reclaim...).
  All six M023 command ids are registered after the `tier !== 'full'`
  early return, so a packaging host cannot reach them.
- The two M023 affordances that are not commands -- the path-bearing
  DOM render probe (D079) and the retention-interval override -- now
  key off a new `fullUatSurface` (uatSurface === 'full') instead of
  liveUatEnabled, keeping both Development-only.
- uat-commands.test.ts: both sides only appended tests; kept both.
- Updated the two source-scanning guards for the new signature and
  classified the six M023 command ids in the tiering invariant, which
  requires every declared command to be bucketed deliberately.

Verified after merge: tsc --noEmit, full vitest (201 files / 2591
passed / 4 skipped), compile, check:svelte, test:webview (82 passed),
test:m023-evidence-gate, test:source-boundary(+:fixtures),
test:evidence, test:settings-docs, test:settings-live-evidence, and
test:m022-s02..s05 -- all exit 0.
CI failed on exactly one test -- "M020 S03 collapse" -- with
expect(expandedBox!.height).toBeGreaterThan(1) receiving 0, while every
assertion around it passed: aria-expanded was 'true', data-collapsed was
'false', and the added diff line was visible.

That combination rules out a rendering regression and points at timing.
The panel expands through a `grid-template-rows: 0fr -> 1fr` transition
(0.2s). Playwright's attribute and visibility assertions auto-retry, so
they settle as soon as the class flips, but boundingBox() is a single
sample with no retry -- it can be taken while the row is still animating.
A loaded Linux runner is simply more likely to land inside that window
than a local machine.

Confirmed by controlled experiment rather than inference: temporarily
raising the transition to 5s reproduced the failure locally with
height 0.046875 (mid-animation), and the polled assertion passed with
the transition still at 1s. Production CSS is unchanged at 0.2s.

Negative control: with the threshold temporarily set to 999999 the test
fails and reports the real settled height of 21.33px, so the assertion
still has teeth and is not vacuously passing.

Verified: npm run test:webview -- 82 passed. Also re-ran the six
verifiers that reference this spec file; all pass except
test:file-drop-docs, which fails identically without this change and is
not wired into CI (pre-existing, unrelated).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant