docs(website): settle where the module state machine lives and how boot treats it
Phase 2 PR 1 of the module system records two things 2.4 left open: the states are stored in one `state` column rather than a policy flag beside a runtime one, and every boot recomputes the outcome states while leaving `disabled` alone. That second rule is the one with consequences worth writing down -- a startup_failed module is retried on every restart, so an operator who fixes the cause needs no admin-panel visit; a running module can never display a stale failure reason; and disabling, the one operator decision rather than outcome, survives restarts. Also states what the row does NOT decide: the loader scans the filesystem before the database is reachable, so the URL surface is a property of the volume, which is what keeps routes.manifest.json generatable against a dead database. BACKEND_DESIGN.md 3 gains the installed_modules columns alongside the other tables. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -665,6 +665,34 @@ JSON. `resolveMany()` returns only ids that resolved to something displayable
|
||||
`~1_val~` are stripped, since the bridge sends the id and never the property packet that carries the
|
||||
arguments — and it never throws, because a cliloc lookup is decoration on a character sheet.
|
||||
|
||||
### installed_modules — what is installed, and what happened to it (module system)
|
||||
|
||||
One row per installed module, keyed by the `id` from its `module.json` — the same id that names its
|
||||
directory on the modules volume and its URL segment.
|
||||
|
||||
| Column | Shape |
|
||||
|---|---|
|
||||
| `id` | VARCHAR(32) PK — the module id |
|
||||
| `name`, `version` | the manifest's label and semver, for the admin Modules screen |
|
||||
| `state` | ENUM `installed` / `enabled` / `disabled` / `started` / `startup_failed` |
|
||||
| `failure_stage`, `failure_reason` | the stage a failure happened at (`manifest`, `core_api`, `mounts`, `extensions`, `schema`, `require`, `register`, `boot`) and its recorded reason |
|
||||
| `source`, `sha256` | the release the bundle came from and the digest verified before unpacking; both NULL for a directory placed on the volume by hand |
|
||||
| `installed_at`, `started_at`, `updated_at` | `started_at` is the last **successful** start |
|
||||
|
||||
**This table never decides which routes exist.** The module loader scans the filesystem at require
|
||||
time, before the database is reachable, so the URL surface is a property of the volume — which is what
|
||||
lets `routes.manifest.json` be generated against a dead database. A disabled module stays mounted and
|
||||
is guarded; the row decides whether it *answers*, not whether it is there.
|
||||
|
||||
**Every boot resets each non-disabled row to `enabled`** and clears its recorded failure, then the load
|
||||
writes that boot's outcome. So a `startup_failed` module is retried on the next restart (an operator
|
||||
who fixes the cause needs no admin-panel visit), a running module can never display a stale reason,
|
||||
and `disabled` — the one operator *decision* rather than outcome — survives untouched. A re-install or
|
||||
upgrade refreshes the metadata and leaves `state` alone.
|
||||
|
||||
Design of record: [`MODULE_SYSTEM.md`](MODULE_SYSTEM.md) §2.4; the loader's obligations are
|
||||
[`MODULE_API.md`](MODULE_API.md) Part 4.
|
||||
|
||||
---
|
||||
|
||||
## 4. API contract
|
||||
|
||||
Reference in New Issue
Block a user