Repository navigation
Backups: stable Theme Bridge ownership, isolated damaged targets, reconciled interrupted writes (D2–D4) - #535
Draft
raiseCatError wants to merge 4 commits into
Conversation
…errupted writes reconciled - Theme Bridge: re-applying unchanged colors no longer rewrites ledger.json; every real record change is journaled; a restore reconciles the record per tool so an older backup never forgets files NMSh manages for other tools. - A damaged backup target (directory replaced by a file, symlink, wrong type, inaccessible parent) blocks only its own restore, with the exact entry, path and reason. Unreadable entries are kept, counted, never pruned, and block writes only to the files they name. - Unfinished entries are classified from on-disk hashes (not applied, partially applied, applied but unfinalized, conflicted, reverted, ...), shown in /changes, and can be rolled back with an undo checkpoint or finalized only with proof. In-process failures record reverted/rollback-incomplete; unresolved entries are never pruned. Older builds still read every manifest.
…rites From independent review: - An edit that lands while the backup is written now settles the entry as reverted (the recheck runs inside the transaction), so it never lingers as an unprunable 'prepared' entry. - /changes: D sets an unfinished entry aside as reviewed without touching files; it then no longer needs review and can be pruned. Rollback-incomplete entries stay protected. - A restore of an entry another live NMSh process is writing is refused; a 'live' writer of an entry older than 10 minutes is treated as a reused PID. - A damaged older copy of NMSh's own JSON records no longer blocks writes that re-capture them; user files named by a damaged entry still fail closed. - Record-only Theme Bridge entries restore their record (only where it still describes the same file bytes); restoring the first record removes it. - The unjournaled saveLedger is gone.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #534. Fixes D2–D4 from #534's follow-up list. Design notes:
docs/development/native-appearance-welcome/BACKUPS_AND_RESET.md→ "Integrity follow-ups".D2 — Theme Bridge ledger rewritten every launch. Cause:
writeArtifact(src/themeBridge/artifacts.ts) called the unjournaledsaveLedgerwith a freshgeneratedAteven when the artifact was unchanged, so every launch replacedledger.jsonand older entries read "edited since". Restoring an older entry wrote its whole ledger before-image and forgot tools managed later (e.g. Vim).generatedAt;commitLedgerwrites nothing when the record is the same and journals every real record change.saveLedgeris removed.D3 — one damaged target blocked every write. Cause:
Journal.readran the filesystem guard on every recorded target path, and every write listed the journal strictly; a directory replaced by a file threw "A configuration parent is not a directory" for all writes./changesshowsunsafe: <reason>.D4 — interrupted writes.
outcomestaysprepared|applied(older builds still read every manifest); aresolutionfield records reverted / rollback-incomplete / finalized / reviewed.Journal.transactionStateclassifies from on-disk hashes: not applied, partially applied, applied but unfinalized, conflicted, in progress (another live writer, < 10 min), indeterminate./changescounts and marks them; Enter reviews a rollback (normal restore, own undo checkpoint), F finalizes only with proof, D sets aside as reviewed. In-process failures (including an edit racing the backup) settle as reverted. Unresolved entries are never pruned.Tests (isolated HOME via scripts/test.mjs runTestFiles):
tests/backupsIntegrity.test.ts(17): all original 13 fail on Backups: never prune a file's original backup before anything else #534's source, pass here. RealSIGKILLof a writer process after record / after file 1 of 2 / before finalize.tscclean.themeBridgeLivefish case fails locally on Backups: never prune a file's original backup before anything else #534's source too (fish 4.9.3, this Mac); left to CI.Review: independent Sonnet review, no blockers; should-fix items fixed in the second commit.
Limits: per-host appearance/shader records cover one file group and restore together, so they are not reconciled per tool. Each journaled write still lists and verifies the whole history (~0.4 s at 200 entries). Physical terminal QA NOT RUN.
Exact-head CI: run 40808808548 on b0b473b: success. Earlier heads failed only on a wrap-sensitive assertion in the new test (fixed in the last two commits) plus known live-zsh/browser timing flakes.