Skip to content

feat(storage): restore quarantined archived sessions (phase 2.1 of #42) - #558

Merged
Wibias merged 21 commits into
lidge-jun:devfrom
Wibias:feat/storage-phase2.1-restore
Jul 27, 2026
Merged

feat(storage): restore quarantined archived sessions (phase 2.1 of #42)#558
Wibias merged 21 commits into
lidge-jun:devfrom
Wibias:feat/storage-phase2.1-restore

Conversation

@Wibias

@Wibias Wibias commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add GET /api/storage/trash and POST /api/storage/trash/restore to list and restore Phase 2 quarantine entries under CODEX_HOME/.trash/<epoch>/ (relative paths only).
  • Restore moves JSONL files back to archived paths, re-inserts threads (+ satellites when satellite-backup.json is present), removes the trash entry on success, and returns 409 when Codex DBs are busy.
  • Storage page Quarantine panel with Restore + confirm, i18n for all locales that already had storage keys, and docs note that quarantine is restorable from the dashboard.

Closes part of #42 (Phase 2.1 only — no Phase 3 auto-policy/purge).

Test plan

  • bun test --isolate for storage-cleanup, api-storage-cleanup, api-storage, storage-scanner
  • bun run typecheck
  • Manual: quarantine an archived session on Storage, confirm it appears under Quarantine, Restore, verify JSONL + thread return
  • Manual: with Codex holding state_*.sqlite, confirm restore returns busy / 409

Summary by CodeRabbit

  • New Features
    • Added an in-app Quarantine section on the Storage page to list quarantined entries and restore selected items (including associated threads) with confirmation and progress/status feedback.
  • Bug Fixes
    • Improved restore/cleanup behavior and messaging when the storage state is locked, plus clearer handling for invalid, missing, or overwrite (destination exists) restore targets.
  • Documentation
    • Updated web dashboard Storage guidance (all supported languages) to state quarantined entries are restorable from the Storage page; clarified read-only active sessions and refusal during locking.
  • Tests
    • Added API and end-to-end coverage for trash listing and restore success/failure, including lock contention and restore job responsiveness.

…dge-jun#42)

Add trash list/restore APIs, Storage GUI quarantine panel, and round-trip tests so default cleanup can be undone without Phase 3 purge.
@github-actions github-actions Bot added the enhancement New feature or request label Jul 27, 2026
@coderabbitai

This comment was marked as outdated.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Wibias added 6 commits July 27, 2026 18:02
… races

Keep satellite backups for quarantine restore, snapshot full thread rows and state dependents, remap satellite DB paths, and make satellite failures retryable. Drop duplicate trash probing so Storage abort/generation ownership stays correct.
Use link+unlink no-replace for trash restore so a raced dest cannot be overwritten, and raise timeouts for multi-satellite cleanup tests that overrun 5s on Windows CI.
Reject malformed manifests wholesale, gate stage deletion on restore completeness, and reconstruct production thread rows from rollout session_meta when satellite snapshots are missing.
Holding BEGIN IMMEDIATE across writeFileSync let Windows CI disk/AV latency stall the watermark concurrent-restore test past bun's 5s default. Persist consolidatePostImage after COMMIT and raise the two concurrent restore test budgets to match the other multi-satellite cases.
Restage files then delete rows this restore committed so satellite/leftover failures leave a clean retryable trash entry.
…xisting rows

Track exact conflict-ignored inserts, require compensating DB txs to commit before restaging, and leave accurate partial counts when compensation is busy.
coderabbitai[bot]

This comment was marked as resolved.

…ation

Late failures after file moves now persist restore-pending.json and keep restored files in place, so retries accept destinations and finish only missing metadata without deleting rows before a guaranteed restage.
coderabbitai[bot]

This comment was marked as resolved.

Persist the resume marker with stage-local temp+fsync+rename before any rollout leaves quarantine, distinguish missing/valid/invalid markers, and fail closed when a resume still owes satellite work but satellite-backup.json is gone.
coderabbitai[bot]

This comment was marked as outdated.

Wibias added 2 commits July 27, 2026 20:37
Once restore-pending is durable, a later rename failure must not reverse successful moves or drop the planned acceptedDestRels marker so resume can finish staged files.
…sume, tombstone finalize, worker job)

Fail closed per owed satellite section on resume, finalize successful restores via non-listable tombstone rename, and run restoreTrashEntry in a serialized Bun Worker so the event loop stays responsive.
coderabbitai[bot]

This comment was marked as resolved.

Wibias added 9 commits July 27, 2026 21:07
Route manual cleanup and trash restore through one per-CODEX_HOME coordinator that returns 409 storage_mutation_busy instead of queuing. Stub runPolicyStorageMutation for Phase 3 policy worker integration.
Map worker rejections to distinct restore error codes end-to-end (API, GUI, i18n) instead of generic restore_failed, and register the restore test-stream endpoint only when OPENCODEX_CLEANUP_TEST_HOOKS=1.
Keep only restore worker error types in cleanup.ts; remove calls to undefined pending-restore guard helpers introduced in the prior commit.
Reject cleanup when selected archives overlap acceptedDestRels from valid restore-pending markers, fail closed on unfinished satellite sections, and address tip CodeRabbit nits (healthz flake, preview status).
Resolve conflicts keeping Phase 3 auto-cleanup policy alongside trash restore UX, overlap guards, and mutation coordinator integration.
Raise injected satellite rollback test timeout for slow Windows SQLite reconcile, and delay concurrent policy PUT until the worker has loaded the enabled snapshot inside holdAfterLoadMs.
…g-safe selection

Acquire the shared CODEX_HOME mutation slot in the policy job controller before spawning the worker and release it on success, failure, timeout, and abort. Pending-restore destinations no longer consume percent or reduceToBytes selection budget; cleanup backfills with the next oldest safe archives. Adds API regressions for policy, restore, and manual cleanup contention in both orderings.
The request handler assignment overwrote executeJob's inflight=null on mutation-busy returns, leaving a settled Promise latched forever. Clear inflight in a finally on the assigned job promise instead.
Resolve api-storage-policy.test.ts conflict: keep Windows CI worker spawn timing (blockMs 1500, sawRunning gate, 800ms hold margin).
@Wibias
Wibias merged commit 40fdc3d into lidge-jun:dev Jul 27, 2026
9 checks passed
Wibias added a commit to Wibias/opencodex that referenced this pull request Jul 27, 2026
…follow-up

Loop short writes to completion and rename via renameAtomicFile so Windows
sharing violations cannot replace a durable temp with a truncated backup.
Wibias added a commit that referenced this pull request Jul 27, 2026
* fix(storage): harden #558 satellite backup writes and zst restore

Make every satellite-backup.json update crash-safe (tmp + fsync + rename +
best-effort dir fsync) so a failed post-memories rewrite cannot truncate the
last valid snapshot. Restore legacy compressed-only quarantine entries by
decompressing a lone .jsonl.zst in memory and reconstructing the thread row.

* fix(storage): harden satellite-backup write retries for #558 follow-up

Loop short writes to completion and rename via renameAtomicFile so Windows
sharing violations cannot replace a durable temp with a truncated backup.
@Wibias
Wibias deleted the feat/storage-phase2.1-restore branch July 28, 2026 00:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant