v0.9.1
Fixed
-
JoinPlayerno longer hands the world back to the scenario while the engine's background
server-assets build can still be enumerating live game content (issue #84, from the
StratumParity field report: a scenario that joined a player and immediately ran a
2048-SetBlock burst, under a staged source mod that lengthens the build, hit "Collection was
modified" insideBuildServerAssetsPacketon a TyronThreadPool thread, and an unhandled
pool-thread exception kills the whole testhost process, twice in a row on a 4-core CI
runner). After the join reaches the Playing state,JoinPlayernow waits for the exact
completion signal the issue #46 dispose-time guard already reads from the other end of the
host lifecycle (the privateServerMain.serverAssetsPacketbox:packetassigned by
non-dedicated builds, Atlas's case, orLengthbumped by dedicated ones), awaited on the
game-thread tick scheduler so the pump keeps processing while the build finishes, and
bounded at 1800 ticks (~60 s at the engine's nominal tick pace, mirroring the dispose-side
bound) with an engine-driftAtlasSetupExceptionon expiry. On the supported engines
(verified by decompile on 1.20.12, 1.21.7 and 1.22.3) the build is queued at boot by
ServerMain.Launch()andHandleRequestJoinitself blocks on the same signal, so a
completed join normally settles the check instantly: the guard costs two cached-reflection
reads per join and only actually waits when a mod kicked the player mid-join before the
join's own wait ran (or on engine forks that defer the build to the first join, the field
report's case). The probe reflection now has a single owner (ServerAssetsBuildProbe, its
pure signal shape inAssetsBuildSignal) shared by both guards, and an engine whose signal
layout drifted degrades exactly like the dispose side: skip the wait behind a one-time
warning. The faulty enumeration itself is vanilla engine code (reported upstream at
StratumServer/Stratum#151); Atlas closes the window scenarios could race it from. -
Scratch directories no longer accumulate until they exhaust the temp filesystem (issue
#83, from the StratumParity field report: a day of repeated local runs piled up 722
directories, 1.7 GB, under /tmp/atlas on a 16 GB tmpfs, at which point the ENGINE's own
disk guard ("Disk space is below 400 megabytes... Will kill server now") failed every
subsequent boot with a message that never mentions Atlas). The registry now sweeps a
disposed host's scratch directory (world save, logs, staged mods), but only when nothing
argues for keeping it: no scenario of the owning class has failed so far, the host did
not crash, its game thread joined within the teardown bound, andATLAS_KEEP_SCRATCHis
not set (set it to 1 to keep everything while debugging). Anything red keeps its scratch
untouched, because server-main.log in there is the documented post-mortem artifact the
0.9.0 engine-crash fail-fast points users at; an abnormal process death keeps everything
too (the sweep only runs on orderly teardowns). Multi-host classes sweep per host under
the same green-so-far rule (a FreshWorld recycle mid-class, a completed RestartWorld
restart once its save is harvested), theatlas fixtureharvest path never sweeps (the
fixture is copied out of the scratch after disposal), and deletion is best-effort by
design: a short bounded retry covers the engine releasing file handles a beat after
stop, and a delete that still fails logs one stderr line instead of failing any test.
Applies todotnet testand the atlas CLI (sequential, worker and parallel modes)
alike: they share the registry. The keep-or-delete decision and the retry loop live in
pure cores (ScratchRetention, ScratchCleanup, the AssetsBuildSettle pattern) with unit
coverage; the E2E regressions run guinea pig classes through the full pipeline and
assert a green class's scratch is gone after hand-off while a failing class's survives
with its server-main.log.