Repository navigation
Conversation
…y one rule The developer tools saved through their own writer, which moved the old file aside as <file>.bak, and recovered before every read: a read deleted an author's own <file>.bak beside a file, a missing file got that .bak put back in its place, and every save replaced it. They now save through the launcher's writer and recover through #226's rules, moved into shared libraries: only <file>.<pid>-<micros>.bak counts. A <file>.bak left by an older CLI's interrupted save is still put back, recognised by the .tmp that save always leaves beside it. The launcher log and the game-compatibility cache, which hold no player state, are put back after a stopped save and have old leftovers swept. Every save first sweeps its own file's old temporary files: only the writer's names, only regular files, never one a save in this process is writing, and only once both its token and its last change are an hour old. Signed-off-by: Furroxide <221987073+Furroxide@users.noreply.github.com>
|
Unity PR artifacts are ready.
Workflow run: Unity Source Validation #674 Artifacts are temporary and expire according to the workflow retention policy. |
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.
Outcome
#226 gave the launcher's own files one recovery for interrupted saves and left three follow-ups. This closes all
three. Every file the launcher and the CLI save now goes through one writer, with one naming rule for what a stopped
save leaves behind, one recovery and one sweep.
1. The developer tools no longer put back or delete an author's
<file>.baktopiaforge new mod,restore,pack,mod add|remove, and the VPM and world tools save through the developerrepository. Its writer always moved the old file aside as
<file>.bak, and its recovery ran before every read ofevery file it read: project files,
.csprojfiles,README.md, Unity package manifests, templates.<file>.bakbeside it: the.bakwas deleted, on a read alone. An author's ownMyMod.csproj.bakwas gone after any command that readMyMod.csproj.<file>.bakbeside it: the.bakwas put back as the file.<file>.bak, which was then deleted.The developer tools now save through the launcher's writer, moved to
lib/src/atomic_file_writes.dart. A backup isnamed
<file>.<process id>-<microseconds>.bak, as the launcher names it, and #226's recovery, moved tolib/src/atomic_files.dartwith its rules unchanged, puts it back. A<file>.bakis never deleted.left
<file>.bakand, beside it, its new version as<file>.<process id>-<microseconds>.tmp, because it stoppedbefore moving that file in. So a missing file with a
<file>.bakand such a temporary file beside it is put back,as the old recovery did. A
<file>.bakwithout one is the author's own and is left alone. The launcher's own filesnever read a
<file>.bak, as before.only when that move fails. A developer save on Linux or macOS therefore never leaves the file missing, which fix(launcher-data): harden interrupted-save recovery for launcher files #226's
put-back relies on there.
on the way. A folder above the project that cannot be listed is passed over, as before, rather than refused.
2. The launcher log and the game-compatibility cache
Neither one holds player state.
so the old one was orphaned. The log is now put back before it is read, appended to or added to a diagnostic
bundle. Once per launcher or CLI process, old leftovers beside a log that is there are swept. A backup that another
program holds never stops logging: the log goes on in a new file, and the backup waits for a later look.
<game>/BepInEx/TopiaForge/compat-status.json) is put back the same way before it is read, and oldleftovers beside it are swept. Its verdict is still checked against the hash of
GameCode.dll.3. Temporary files are swept
A save that stopped after writing its
<file>.<token>.tmpleft that file forever. Every save now first sweeps theold temporary files of its own file, under these limits:
modification time, so a save still running in another process keeps its own. That is the same bound as the
multiplayer store's sweep (feat(launcher-data): add the multiplayer network clients and store #214);
docs/Troubleshooting.mdgains a section, "Files beside a saved file".Deviations from the plan
Directory.list, and the developer tools call it from synchronous code. It now lists withlistSync, and anasync wrapper keeps the launcher's call sites as they were. Its rules, messages and tests are unchanged. fix(launcher-data): harden interrupted-save recovery for launcher files #226's
race tests pass, since their overrides also hook
listSync.profiles, package sources, manager state, the repair journal and the developer files. Such a backup is put back
when its file is missing, as fix(launcher-data): harden interrupted-save recovery for launcher files #226 decided. Only the log's backups and the cache's are swept.
package_helpers.dart), the manifestmigration writer's
.migration-*.tmp, and the launcher update's transaction. Each has its own names andlifetime, and none uses this writer.
Compatibility and security
atomic_files.dartandatomic_file_writes.dart, andlocal_launcher_repository/atomic_backup_recovery.darthas moved into them. Developer backups are now named
<file>.<token>.bak. No file format changes.files, and only after an hour.
<file>.bak.<file name> could not be read just now, so nothing was changed., withfix(launcher-data): harden interrupted-save recovery for launcher files #226's cause and next step. Before, an unreadable backup gave an error naming its full path.
restores the old behaviour, including the deletion of
<file>.bak.Verification
On a Windows 11 x64 machine, on
devat 22d68d1 and then rebased onto d89f295 (its #248 changes no Dart file), with the pinned Flutter 3.44.6 and its Dart 3.12.2:test/atomic_write_sweep_test.dart, 7:.bakand.tmpalike;test/atomic_write_leftovers_test.dart, 11. Developer files: an author's<file>.bakkept through reads andsaves, and never put back; the newest of several backups put back; a held backup refused with nothing changed;
the project search passing over a folder it cannot list (POSIX); a save that leaves no leftovers. The log: never
reading the launcher's own
<file>.bak; a stopped rotation put back; old leftovers swept and recent ones kept;a held backup never stopping logging (Windows). The cache: put back and swept.
developer_persistence_hardening_test.dart's recovery test now builds what an older CLI's interrupted savereally leaves, the
.tmpincluded.dev's code: withdev'slib, 8 of the 10 integration tests that ran on Windows fail. The othertwo are guards.
devnever touched the log's backup, and never read a<file>.bakfor the launcher's own files;both must stay that way now that the log is put back and the developer files read an older CLI's backup.
nobodyaccount so folder modes hold: the new files,developer_persistence_hardening_test.dart, and fix(launcher-data): harden interrupted-save recovery for launcher files #226's recovery, race, manager-state and persistence tests:45 pass, and 3 skipped (the Windows-only held-file tests).
nobody:a temporary file and the other way round; a
<file>.bakcounts without the temporary file beside it; thelauncher's own files read a
<file>.bak;began recently loses its leftover; a link followed and deleted;
list;
packages/launcher_data: 1,064 pass, 10 skipped.dart analyze --fatal-infosanddart format --set-exit-if-changed: clean. Other programs kept this machine heavily loaded. Under that load, twoearlier full runs timed out at 30 s on the known flaky doctor test, "doctor reports an exact-SDK resolution
failure as blocking". That test takes 14 to 19 s alone, on this branch and on
devalike; fix(launcher-data): stop losing LAN queries, and make the LAN and doctor tests deterministic #250 makes itindependent of the machine's speed.
apps/topiaforge_cli: 514 pass, 4 skipped. The Release build is in place (dotnet build TopiaForge.slnx -c Release -warnaserror, 0 warnings, on the same C# tree). Under the same load, the default 30 s limit timed out55 tests, nearly all of them release tests that never touch
launcher_data. With--timeout 4x, 511 passed. Thelast three passed in a rerun without a time limit, 10 of 10 in their files. One of the three is the template
lifecycle test, which takes every template through
new,restoreandpack.python -I .github/scripts/check_topiaforge_residue.pyandcheck_readme_counts.py: pass. Line-count audit: nonon-generated Dart file over 500 lines; the largest new file has 320.
Checklist
AGENTS.mdand preserved CLEAN/Bloc/Unity/TopiaForge UI boundaries.