Uninstall-with-purge ran purge.sql while the module was still started: the
tables went, and the module kept serving and ingesting against a schema that no
longer existed until lifecycle.stop() finished — up to the five-second hook
budget. For module-uo that is the uo-link WebSocket writing shard events into
dropped tables, and requests in flight answering 500 where a stopped module
answers 404.
Nothing required the old order. The comment justified it as "purge while the SQL
is still readable", but removeDir is the only step that touches the filesystem,
so purge.sql stays readable until after the stop. The 400 for a module that
ships no purge.sql is now resolved before anything is stopped, so a refused
request leaves the module exactly as it found it.
Found while proving Phase 4's acceptance criterion 2 against the real
module-uo v0.3.0 release on an empty database (MODULE_SYSTEM.md §2.7.2).
742 server tests (+1); routes.manifest.json and swagger-output.json byte-identical.
AI disclosure: this contribution was AI-assisted (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>