Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .importlinter
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ modules =
services.metadata
services.migration
services.playtime
services.prune
services.relaunch_options_resolver
services.rom_removal
services.saves
Expand Down
34 changes: 34 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,40 @@ Format: **invariant** — tier — enforced by.
is never mutated while the stash is pending (box IDLE) — every run-entry path passes `try_begin_run`, which clears the
stash before any staging write (#1367)** — prompt-only — verified closed in #1367 review; mechanize via a
staging-writer call-site audit
- **A prune claim excludes library sync, downloads/resumes, migrations, version switches, core/disc/controller writes,
launch evaluation, save mutations, session writes, uninstalls, connection identity changes, and affected cache
cleanup; each conflicting callable registers before its first await, detached work retains that claim for the task
lifetime, and frontend-owned multi-call work holds and heartbeats a globally registered, bounded tokenized lease
through every sibling Steam continuation's final write (including each paced `sync_stale` removal and terminal repoint
publication); every continuation checks its abort signal before each later Steam mutation; failed event delivery
releases an unreachable token; owner/plugin generation is captured before each backend wait, teardown tombstones it so
late lease-bearing responses are released without work, and only a genuine remount opens a new generation; teardown
stops renewal and future writes but defers explicit release until already-started Steam promises settle; run admission
atomically refuses those registrations before reserving the prune claim and refreshing the preview** — test
- prompt-only — prune service/gate race tests + contract callable-entry matrix; new conflicting entry points are
prompt-only
- **A prune frontend action mutates Steam only after atomically claiming its exact run/token/discriminant/binding;
identical repeat claims are idempotent, action delivery is serialized/deduplicated, completion retries never repeat
the Steam operation, and a claimed outcome lost in transit is reported as ambiguous until live Steam absence is
reconciled** — test + prompt-only — prune service claim tests + `src/utils/pruneActions.test.ts`; new action kinds are
prompt-only
- **Every prune source carries a no-follow claim (root `(device, inode, mount-id, mode, size, mtime, ctime)` plus every
descendant identity and regular-file hash) through descriptor-relative mutation; mount transitions are refused,
regular-file and controller-claim deletion holds kernel writer exclusion from final validation through unlink,
selected sources consume claims decoded from the same held and digest-bound sealed bundle, unselected/recovery-off
sources take a final presence-or-absence claim, every exclusive save is expected absent after quarantine and the whole
set is collectively rechecked immediately before aggregate cascade, quarantine publication is atomic no-replace,
writer-exclusion teardown faults are ambiguity, controller claim branches revalidate and preserve newer held-inode
edits at a surfaced path, and path re-lookup alone never authorizes delete/quarantine; unsafe recovery-failure cleanup
preserves and reports the anchored staging path** — test + prompt-only — descriptor-path, recovery-adapter, real
RomRemovalService, and prune contract tests; new mutation adapters are prompt-only
- **Every prune action/progress/completion frame carries its originating preview ID; a pending frontend preview may
adopt only a matching run, including when the successful start response is lost, and foreign frames never trigger
state or side effects; an accepted contiguous terminal result seals the run against every later frame** — test +
prompt-only — prune service frame tests + `src/utils/pruneStore.test.ts`; new prune frame types are prompt-only
- **Every destructive RomM proof is bound to one canonical server-origin/token-origin/user namespace from preview
through every exact-ID request; a namespace change is uncertainty, never a 404 deletion authority** — test +
prompt-only — prune service namespace-race tests; new destructive RomM proof paths are prompt-only

When a change applies a guard / sanitize / backup / grouping pattern, sweep for sibling sites of the same pattern — the
register is what that sweep checks against.
Expand Down
15 changes: 14 additions & 1 deletion CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,20 @@ Three deliberately-distinct ROM-removal notions (see [ADR-0007](docs/adr/0007-ro
delete: a stale signal may be a transient server blip or a reversible RomM change, and local playtime/saves must
survive.
- **Prune** — an explicit, opt-in purge that `DELETE`s the `roms` row, cascading every per-ROM child away atomically.
The **only** thing that deletes rows; not built yet (the cascade FKs exist for it).
The **only** thing that deletes rows. **Clean Up Removed RomM Games** performs it only after fresh exact-ID 404s,
explicit options, and any enabled recovery bundle have passed their final guards.

### Recovery bundle

A checksum-verified, atomically sealed pre-mutation snapshot created by explicit Prune. It records the affected local
aggregate state and selected/mandatory recoverable files for manual recovery; it is not a database export or an
automatic restore point. Finalization revalidates both the sealed bytes and their source state before deleting anything.

### Action token

A one-run, one-action lease for a frontend-owned Steam operation during Prune. The frontend must claim the exact token
before touching Steam and complete that same token afterward. Duplicate, stale, unknown, and late unclaimed tokens are
non-authoritative and cannot mutate Steam.

### Collection kind (Standard / Smart / Virtual)

Expand Down
Loading
Loading