Initial public ModelForge release

This commit is contained in:
Jens
2026-09-01 21:30:16 +02:00
commit 7082ab955a
490 changed files with 104252 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
# Restart and crash recovery
## What each restart reconciles
The control plane reconciles on every start. Reconciliation is idempotent by design, so a restart
storm converges rather than accumulating.
```text
lifecycle incomplete operations roll back from their immutable snapshot, exactly once
migration interrupted cutovers are reported, never auto-resolved
recovery interrupted backups fail closed; interrupted restores need operator review
serving stale leases and residency are reconciled against live node state
observability current alert state is re-derived; history is retained
```
Migration is deliberately the exception. External alias truth cannot be inferred after a crash, so
an interrupted cutover stays in its intermediate stage and is reported as requiring reconciliation
through the typed adapter. Guessing here is how a platform ends up serving two embedding spaces.
## Restart storms
Four consecutive control-plane restarts under load produced no authoritative drift: models,
revisions, artifacts, artifact sets, projects, bindings, capability deployments, lifecycle
operations, migration plans and cutovers, compute nodes, node credentials, service clients and
backup sets were all identical before and after, and the registry answered on every start.
Audit events are expected to grow — reconciliation is itself an audited action — so the drift check
excludes them and the `audit_chain_intact` invariant covers their integrity instead.
## Node Agent restarts
A restarting agent keeps its persisted identity file, so it re-attaches to the same node with the
same accelerators, storage roots and history. It does not re-enrol unless it has lost its
credential, and enrolment revokes the previous credential rather than adding a second.
The publication and artifact loops share an enrolment lock. Without it they could enrol
concurrently from separate threads and burn a single-use token on two identities for the same
hardware.
## Database restarts
The control plane fails safely while PostgreSQL is unavailable: liveness stays up because it does
not touch the database, and any route that needs persistence returns an error rather than inventing
state. The connection pool recovers on its own — no control-plane restart is required — and no
duplicate audit sequence appears.
An error raised while the database is down carries no DSN, driver name, SQL or traceback. That is
verified directly, because a dependency failure is when a framework is most likely to leak
internals.
## Redis restarts
Redis holds queues and transient payloads, never authoritative state. An outage leaves the control
plane serving, and the return produces no duplicate serving job: idempotency keys are unique in the
database, not in the queue.
## Runtime Worker crashes
A worker crash during load, inference or unload produces a typed failure for the request, fences the
worker generation so a late result from a dead generation cannot be committed, and reconciles the
lease and residency. A crash loop raises `RUNTIME_CRASH_LOOP`.
## Interrupted backups and restores
A backup interrupted mid-write is moved to `FAILED` with `MANIFEST_INCOMPLETE` on the next start and
can never become restore eligible. A restore interrupted mid-phase becomes
`MANUAL_INTERVENTION_REQUIRED` rather than resuming silently; its journal records the phase it
reached.
A backup also cannot contain a record of itself as complete, since the dump is taken while its own
`BackupSet` row is still `CREATING`. A restored control plane therefore consistently reports the
backup it came from as not restore eligible.
## Checking after a restart
```sh
python scripts/m16_invariants.py --label "after restart"
curl -s localhost:8000/api/v1/health/ready
```
Fifteen invariants holding, readiness healthy, and no orphaned lease or queued job is what "the
restart reconciled" means. See `docs/operations/CHAOS_TESTING.md` for the fault matrix.