docs(website): phase 4 decisions 5-6, slices 1-2, and a rule main currently gets wrong #142
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/module-phase4-slices"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
docs#141 merged at its first commit, so three commits pushed to that branch afterwards never landed. This is them. Same thing happened to Phase 3 slice 1's docs — worth noting that a push to an already-merged PR's branch is silent.
One of them matters more than a write-up:
maincurrently documents a rule the code does not implement.The correction
§2.7.2's threat-model list on
mainsays the extractor rejects "a top-level directory whose name is not the manifest'sid". It does not, and must not —module-uo's release workflow packsmodule-uo-<version>/, so that rule would refuse every bundle that exists. The extractor requires exactly one top-level entry and strips it, and checks the unpackedmodule.jsonagainst the install manifest instead, which is a stronger check.Also corrected there:
tarhas to be pinned forward (^7.5.22), not merely depended on — the default^6is npm-audit critical, and the advisory list is this feature's own threat model.What else is in here
Decisions 5 and 6 (settled during slice 1, already implemented in the merged code):
purge.sqllives inside the directory uninstall deletes and there is no later. §2.5 is amended — "never bundled into uninstall" becomes "never implied by uninstall".MODULE_SOURCE_HOSTSinto a settings row and is admin-owned thereafter.Slice 1's record (website#142), including the measurement behind the two-pass unpack: node-tar does reject an escaping member, but late — an archive whose fourth member escapes throws and leaves the first three on disk.
Slice 2's record (website#143), and the three defects standing the screen up against a live server exposed. Two are older than Phase 4 and none was reachable from a test:
startup_failedrow rendered the old failure — "module directory not present on the volume", one second after writing the files there — and suppressed the restart banner the install had just asked for.process.kill(pid, 'SIGTERM')kills outright on Windows, where POSIX signals do not exist — noonShutdown, no pool close, no log flush.process.emit('SIGTERM')reaches the same listener everywhere. Deployment is Linux containers and would never have shown it.Plus
BACKEND_DESIGN.md: themodule_source_hostsseeded key, theCOALESCEoninstalled_modules' provenance, the refreshed route count (166), andapi-route-inventory.jsonre-mirrored.Docs only.
AI disclosure
🤖 Generated with Claude Code
The Modules screen as built (website#143), and the three things standing it up against a live server exposed. Two of them are older than this phase and neither was reachable from a test. - A fresh install over a row the previous boot left `startup_failed` rendered the old failure - "module directory not present on the volume", one second after the files were written there - and, because that branch is not pending, suppressed the restart banner the install had just told the operator to use. Fixed by a derivation rather than a special case: the loader scans once at require time, so a module on the volume with no live record arrived after that scan and anything the row says predates it. - The boot refresh had been nulling every install's provenance. source and sha256 exist for this screen and never survived a restart, because lifecycle.boot() re-records with neither and the upsert assigned both unconditionally. It could not have been found before Phase 4 wrote the first non-null value those columns ever had - and the model's test fake reproduced the defect faithfully, assigning exactly like the SQL. - The restart killed the server outright on Windows. process.kill(pid, 'SIGTERM') reaches the graceful handler on Linux and is unconditional termination where POSIX signals do not exist, so a Windows host got no module onShutdown, no pool close and no log flush. process.emit('SIGTERM') reaches the same listener everywhere. The test had stubbed process.kill and asserted the call - precisely the call whose meaning differs by platform. That last one generalises: deployment is Linux containers and would never have shown it. A smoke that only runs where the code ships cannot find a class of defect that only bites the people developing it. Also documents the COALESCE in BACKEND_DESIGN's installed_modules section. Co-Authored-By: Claude <noreply@anthropic.com>