docs(rust): the last fixes' docs (N1 N2 W20 W22 W23) and stage 4's core docs

Stage 5 of PLAN_LAST_FIXES (docs#366).

- OPERATING.md: a RaidableBases section. Change its config with a
  restart, never a reload (N2); switching to the free edition rewrites
  a paid pack's profiles (N1).
- PLAN_REDESIGNS 14.3.4: no manual retry for Dangerous Treasures (Q39,
  W20); 11.4: which hook rbevent setowner raises (W23); 9.1 status.
- PLAYER_WALK: rows 2.2, 2.8 and 2.9, Before you start item 8 (BetterChat
  and the four title rules), Carbon's share trimmed to 2.11 (W22, W23).
- PROTOCOL: 20.5 world.error already-out (W3), 20.12 the rollback's log
  is RaidableBases' own (W9) and setowner's two hooks (W23).
- Core, from website#219: MODULE_SYSTEM 2.5 and MODULE_API 4.2 (one
  module at boot, W19), MODULE_API and EVENTS L (a resource's until read
  at reconcile, W1), EVENTS D/I/K and BACKEND_DESIGN (a draft's dry run
  carried by fingerprint, W5), EVENTS observability (W2's words).
- PLAN_LAST_FIXES: status, Q37-Q40 answers, 7 updated, 8 what was built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-22 01:36:57 -05:00
parent 27dd1f8d80
commit 20518ca816
9 changed files with 177 additions and 39 deletions

View File

@@ -1192,6 +1192,8 @@ arrives with the calendar.
| concurrency_key | VARCHAR(190) NULL | stored as the **template** (`invasion:{region}`), rendered from a run's own params at materialisation. A flat definition-id key would wrongly stop one definition running in two regions at once |
| grace_seconds | INT NOT NULL DEFAULT 900 | a schedule that passed this long ago while the process was down is `missed`, never a late silent start. Validated 60..86 400 |
| timezone | VARCHAR(64) NOT NULL DEFAULT 'UTC' | IANA, and it belongs to the **event**: every listing this replaces is written in the shard's local zone, and a recurrence computed in UTC puts a Friday-8pm event at 7pm for half the year. Validated against the platform's own tzdata via `Intl.DateTimeFormat` |
| draft_verified_at / draft_verified_by | DATETIME NULL / INT NULL | the last dry run that **passed on the draft**, and who ran it (W5, Rust `PLAN_LAST_FIXES.md`). No foreign key on `_by`, as `event_versions.verified_by` has none |
| draft_verified_hash | CHAR(64) NULL | the sha256 of that draft's validated spec as canonical JSON (keys sorted). Publish compares it with the spec it freezes; equal, and the new version is stamped verified with the two columns above, so a pass on the draft counts for the version made from it. An edit in between is a different hash, so nothing stale carries ([`EVENTS.md`](EVENTS.md) §K) |
| created_by / updated_by | INT NULL FK→users(id) ON DELETE SET NULL | |
| created_at / updated_at | DATETIME | |
@@ -1723,7 +1725,7 @@ file a route sits in — that is the property the route manifest freezes.
| POST | `/events` | **admin, editor.** Create a draft. The slug is derived from the title once and frozen: the public event page lives at it, so a retitle must not break a posted link. A step naming an action no module registers is refused |
| PUT | `/events/:id` | **admin, editor.** Editing never touches a published version — a live run keeps the one it pinned. A step whose module has since been uninstalled is **kept and marked dormant**, not refused: the rule `engagement_rules` established for a dormant trigger, because an uninstall must not be destructive after the fact. `409` on an archived definition |
| GET | `/events/:id/versions` | the version history. Nothing edits a version; the row flagged `current` is what a new run pins |
| POST | `/events/:id/publish` | **admin only** ([`EVENTS.md`](EVENTS.md) §N2) — publishing commits a definition that a schedule will later start unattended, which is deliberately not the same gate as the live run controls. Snapshots the working spec into an immutable version. **Re-validates against the registries as they stand right now**, not from the save that wrote it: `409` naming the action when a step went dormant in between, `400` when no phase has any steps |
| POST | `/events/:id/publish` | **admin only** ([`EVENTS.md`](EVENTS.md) §N2) — publishing commits a definition that a schedule will later start unattended, which is deliberately not the same gate as the live run controls. Snapshots the working spec into an immutable version. **Re-validates against the registries as they stand right now**, not from the save that wrote it: `409` naming the action when a step went dormant in between, `400` when no phase has any steps. Answers `verified: true` when a dry run that passed on this exact draft (`draft_verified_hash`) made the new version verified, so it needs no second dry run before it starts unattended |
| DELETE | `/events/:id` | **admin only.** Archive — there is no hard delete at all, because a run pins a version and a run that could not be explained afterwards defeats the audit this system exists to provide. `409` while a run of it is still in flight |
| POST | `/events/:id/runs` | **admin only**, on the same reasoning as publish. Creates an occurrence. `INSERT IGNORE` against `UNIQUE(definition_id, scope, scheduled_for)`, so asking twice answers `200` with `created: false` and the existing row rather than creating a second. Optional `scope`, `scheduledFor`, `rehearsal`, `params` |
| GET | `/events/runs` · `/events/runs/:runId` · `/events/runs/:runId/log` | the run list, the run console (steps, their params and their idempotency keys, plus status counts) and the diagnostic log |