Problem
Current rollback handles ordinary command/script failures well, but an ERR/EXIT trap cannot run after events such as kill -9, power loss, kernel/system crash, or abrupt machine reset.
A lifecycle operation interrupted between plugin/config mutations can therefore leave a partially applied state even though normal failures roll back correctly.
Goal
Add durable transaction metadata so the next mutating Ruixen lifecycle command can detect and safely recover an unfinished operation before doing new work.
Suggested design
Before exposing live mutations, create a transaction directory such as:
~/.local/state/ruixen/transactions/<token>/
journal.json
shell.json.before
...
The journal should record schema version, operation type, transaction token, phase, exact managed targets, whether each target existed before, backup/snapshot locations, config snapshot metadata, and whether live mutation/restart began.
On startup of any mutating lifecycle command:
- acquire the lifecycle lock
- detect unfinished transactions
- validate journal/snapshot paths and schema
- recover or finish the prior transaction safely
- only then begin the new command
Critical safety requirements
- Never trust arbitrary paths from a journal without validating they are under expected Ruixen/Omarchy roots.
- Refuse symlinked/malformed transaction roots.
- Do not delete the journal if recovery itself fails.
- Recovery should be idempotent.
- Existing normal rollback remains useful; the journal covers crash/interruption durability.
- Do not stop or mutate the shell until all required recovery data has been validated.
Acceptance tests
Simulate termination after first plugin replacement, after all plugins before shell.json, after shell.json before looknfeel, after looknfeel before restart, after restart begins before success commit, and during uninstall.
For each case, terminate without executing shell traps, run a new lifecycle command, verify the previous working installation/config is recovered, verify no mixed old/new plugin set remains, and remove the transaction directory only after successful recovery.
Also corrupt a journal/snapshot and confirm Ruixen refuses unsafe recovery instead of guessing.
Problem
Current rollback handles ordinary command/script failures well, but an ERR/EXIT trap cannot run after events such as
kill -9, power loss, kernel/system crash, or abrupt machine reset.A lifecycle operation interrupted between plugin/config mutations can therefore leave a partially applied state even though normal failures roll back correctly.
Goal
Add durable transaction metadata so the next mutating Ruixen lifecycle command can detect and safely recover an unfinished operation before doing new work.
Suggested design
Before exposing live mutations, create a transaction directory such as:
The journal should record schema version, operation type, transaction token, phase, exact managed targets, whether each target existed before, backup/snapshot locations, config snapshot metadata, and whether live mutation/restart began.
On startup of any mutating lifecycle command:
Critical safety requirements
Acceptance tests
Simulate termination after first plugin replacement, after all plugins before
shell.json, aftershell.jsonbefore looknfeel, after looknfeel before restart, after restart begins before success commit, and during uninstall.For each case, terminate without executing shell traps, run a new lifecycle command, verify the previous working installation/config is recovered, verify no mixed old/new plugin set remains, and remove the transaction directory only after successful recovery.
Also corrupt a journal/snapshot and confirm Ruixen refuses unsafe recovery instead of guessing.