A panic inside one elaboration session used to resume-unwind out of
sweep, abort its siblings mid-inference, and end the runtime's
elaboration driver task, whose handle is dropped: elaboration stopped
silently until restart.
Now each session holds its permit inside a SessionPermit guard whose
Drop raises the sweep's stop before the permit is released, on every
exit but a clean return. A quarantine-class error disarms nothing, and a
panicking task never reaches the line that disarms it, so no session
starts after a panic, by the same path that stops sessions after a
quarantine-class error. The join loop turns a task that did not return
into ControllerError::Serialization("an elaboration session did not
return: ...") and returns it after every started sibling has finished.
The class is quarantine-class on purpose: sweep returns only
quarantine-class errors and debug-logs the rest, so this keeps that one
rule, and the driver's handling of any returned error stays exactly as
it is (debug log). Whether that error quarantines cognition is L1.f1's,
and is not decided here. Serialization is the variant the elaboration
lane already uses for its local invariants.
elaborate_world takes its interval, as drive_cover_tick does, so a test
can drive it at one millisecond; production passes
ELABORATION_SWEEP_INTERVAL unchanged.
Tests: a_panicking_session_lets_its_sibling_finish (the held sibling
commits in the panicking sweep, the error is returned, permits are
free, and a second sweep resumes and commits the panicked session);
no_session_starts_after_a_panic; and in Dungeon
the_elaboration_driver_survives_a_panicking_sweep, which waits for a
second sweep's listing and inference against the driver task ending.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>