docs(events): Phase 0 — the eleven decisions, and the two documents they reach into #208

Merged
whitlocktech merged 1 commits from docs/events-decisions into edge 2026-09-02 02:05:32 +00:00
Member

Retargeted to edge. This opened against main and now targets edge, where the whole Event System workstream lands until the P16 cutover. No rebase was needed: edge was 0 commits ahead of main and 19 behind, so it was fast-forwarded to main (cda5325) — an ancestor advancing, not a history rewrite, and nothing on edge was discarded because there was nothing on it. The same was done across the workspace, so every repo now starts this workstream from a level edge: docs, website, module-uo, link, servuo-plugins and android-app were fast-forwarded; installer and integration-kit were already level. That discharges EVENTS_PLAN.md's "before anything" item 1, which warned that branching off edge as it stood would silently revert the engagement retention work at cutover.

What & why

Closes the second half of EVENTS_PLAN.md Phase 0. The design of record landed in #207; this is the part that was still open — the decisions. All of EVENTS.md §N1–N11 were answered by the org lead on 2026-09-01, before any code, which lifts the ⚠ gate from P11 and P12 and unblocks P1.

EVENTS.md §N is renamed "N — Decisions" and each entry keeps the recommendation it was decided against, so the reasoning survives alongside the answer.

N2 — publishing a version and starting a run are admin only. A moderator keeps live control of a run already in flight (cancel, abort) and nothing more.

The asymmetry is the point: starting commits the deployment to everything a definition contains, unattended, up to every cap it declares — it wants the narrowest gate there is. Cancelling is incident response, and the incident is "the event is doing something wrong at 2am" — it wants the widest. Gating the stop button on the same role as the start button reads consistent and behaves badly in exactly the case the moderator role exists for. This is the one place the split departs from the requireRole('admin','moderator') shape module-uo uses.

Updated: §K's role table (the normative statement), the API surface table, and P3 + P6 in the plan.

N4 — this deployment is single-instance and not planned to change, so P2 does not build the --scale app=2 test.

Every claim path in §E is built exactly as specified regardless, and the doc says so in as many words, because this decision must not be read as licence to drop a CAS: the unique index and the CAS equally protect a tick that overruns into the next one, and the lease and its reclaim recover a step whose process died mid-dispatch. Both happen with one container. What changes is the test, not the design — the multi-instance property becomes true-by-construction rather than proved, and §E now records that scaling this deployment (or adopting a rolling deploy) is the trigger to build the rig that was skipped here.

N1 was taken in full, and it reverses two lines of §8, not one

ADMIN_CONTROLS.md §8's cut list names "item/gold grants" explicitly and separately from world building. Reading the creation reopening as carrying grants along with it would be precisely the silent reversal the plan said not to make, so the new §8a amendment says both out loud — three permitted rows (event-owned creation; leased mutation; item and gold grants), and the four properties that make them a different proposition from what §8 refused: declared not typed, cap-bounded in a conditional UPDATE, ledgered before confirmation, and idempotent on the wire.

§8's bullet is left standing verbatim — it is the decision that was actually taken — with a pointer to the amendment above it, and §1's thesis paragraph gets the same pointer since it makes the same argument. Loot-table changes and arbitrary [set / [get / [add stay permanently excluded, along with the rest of the Tier-H moderation verbs; this amendment is about what an event may create and borrow, not about restoring them.

N3 gives an orphaned row an owner

ENGAGEMENT.md §7.1 Q6 read "no evaluator yet" since 2026-08-29. The Event System runner becomes the kind: 'scheduled' evaluator, built in that workstream's P2 — one scheduler rather than two that disagree. Nothing in the engagement contract changes: a scheduled declaration means today exactly what it meant then, and ctx.events.emit still refuses to fire one.

One consequence derived rather than decided — worth a look

POST /admin/events/:id/verify moves to admin, editor rather than staying with start. N2 settled that a moderator loses publish and start; it did not say where the dry run lands. A dry run dispatches nothing, and the author who wrote the definition is exactly who should be able to price it against the caps before asking an admin to publish it — but that is my inference from N2, not the answer to it. Say the word and it becomes admin only.

How it was tested

  • Every relative link and anchor in the four touched files resolves — checked with a script over EVENTS.md, EVENTS_PLAN.md, ENGAGEMENT.md and ADMIN_CONTROLS.md, including the renamed §N anchor (#n--decisions, updated at both call sites) and the new #8a-amendment--2026-09-01. The docs repo has no CI workflow at all, so the plan's "docs CI link check" line describes something that does not exist; this was run by hand instead.
  • Line endings verified — the repo checks these files out CRLF under core.autocrlf=true. Two scripted passes introduced \r\r\n and a mixed-ending full-file rewrite; both were caught by comparing git diff --numstat against the real content diff and repaired, so the diff is 274 insertions over 32 deletions rather than a 2,400-line rewrite of EVENTS.md.
  • Edge parity confirmed after the retargetedge and main are the same commit in all eight repos, and this PR still reports mergeable against edge with the same four files.
  • Docs-only change: no code, no tests, no routes, no swagger.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • AI tools were used. Tool(s): Claude Code (Opus 5). I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a Co-Authored-By trailer.

License

  • I agree that my contribution is licensed under this project's license (GNU GPL v3.0 or later), and I have the right to contribute it.
> **Retargeted to `edge`.** This opened against `main` and now targets `edge`, where the whole Event System workstream lands until the P16 cutover. No rebase was needed: `edge` was 0 commits ahead of `main` and 19 behind, so it was **fast-forwarded** to `main` (`cda5325`) — an ancestor advancing, not a history rewrite, and nothing on `edge` was discarded because there was nothing on it. The same was done across the workspace, so every repo now starts this workstream from a level `edge`: `docs`, `website`, `module-uo`, `link`, `servuo-plugins` and `android-app` were fast-forwarded; `installer` and `integration-kit` were already level. That discharges `EVENTS_PLAN.md`'s "before anything" item 1, which warned that branching off `edge` as it stood would silently revert the engagement retention work at cutover. ## What & why Closes the second half of `EVENTS_PLAN.md` **Phase 0**. The design of record landed in #207; this is the part that was still open — the decisions. **All of `EVENTS.md` §N1–N11 were answered by the org lead on 2026-09-01, before any code**, which lifts the ⚠ gate from P11 and P12 and unblocks P1. `EVENTS.md` §N is renamed **"N — Decisions"** and each entry keeps the recommendation it was decided against, so the reasoning survives alongside the answer. ### Nine went as recommended. Two did not, and each changes a phase. **N2 — publishing a version and starting a run are `admin` only.** A moderator keeps live control of a run already in flight (cancel, abort) and nothing more. The asymmetry is the point: starting commits the deployment to everything a definition contains, unattended, up to every cap it declares — it wants the narrowest gate there is. Cancelling is incident response, and the incident is *"the event is doing something wrong at 2am"* — it wants the widest. Gating the stop button on the same role as the start button reads consistent and behaves badly in exactly the case the moderator role exists for. This is the one place the split departs from the `requireRole('admin','moderator')` shape module-uo uses. Updated: §K's role table (the normative statement), the API surface table, and P3 + P6 in the plan. **N4 — this deployment is single-instance and not planned to change**, so **P2 does not build the `--scale app=2` test**. Every claim path in §E is built exactly as specified regardless, and the doc says so in as many words, because this decision must not be read as licence to drop a CAS: the unique index and the CAS equally protect a tick that overruns into the next one, and the lease and its reclaim recover a step whose process died mid-dispatch. Both happen with one container. What changes is the *test*, not the design — the multi-instance property becomes true-by-construction rather than proved, and §E now records that scaling this deployment (or adopting a rolling deploy) is the trigger to build the rig that was skipped here. ### N1 was taken in full, and it reverses two lines of §8, not one `ADMIN_CONTROLS.md` §8's cut list names **"item/gold grants" explicitly and separately** from world building. Reading the creation reopening as carrying grants along with it would be precisely the silent reversal the plan said not to make, so the new **§8a amendment says both out loud** — three permitted rows (event-owned creation; leased mutation; item and gold grants), and the four properties that make them a different proposition from what §8 refused: declared not typed, cap-bounded in a conditional `UPDATE`, ledgered before confirmation, and idempotent on the wire. §8's bullet is **left standing verbatim** — it is the decision that was actually taken — with a pointer to the amendment above it, and §1's thesis paragraph gets the same pointer since it makes the same argument. **Loot-table changes and arbitrary `[set` / `[get` / `[add` stay permanently excluded**, along with the rest of the Tier-H moderation verbs; this amendment is about what an *event* may create and borrow, not about restoring them. ### N3 gives an orphaned row an owner `ENGAGEMENT.md` §7.1 Q6 read *"no evaluator yet"* since 2026-08-29. The **Event System runner becomes the `kind: 'scheduled'` evaluator**, built in that workstream's P2 — one scheduler rather than two that disagree. Nothing in the engagement contract changes: a `scheduled` declaration means today exactly what it meant then, and `ctx.events.emit` still refuses to fire one. ### One consequence derived rather than decided — worth a look `POST /admin/events/:id/verify` moves to **`admin, editor`** rather than staying with `start`. N2 settled that a moderator loses publish and start; it did not say where the dry run lands. A dry run dispatches nothing, and the author who wrote the definition is exactly who should be able to price it against the caps before asking an admin to publish it — but that is my inference from N2, not the answer to it. Say the word and it becomes `admin` only. ## How it was tested - **Every relative link and anchor in the four touched files resolves** — checked with a script over `EVENTS.md`, `EVENTS_PLAN.md`, `ENGAGEMENT.md` and `ADMIN_CONTROLS.md`, including the renamed §N anchor (`#n--decisions`, updated at both call sites) and the new `#8a-amendment--2026-09-01`. **The `docs` repo has no CI workflow at all**, so the plan's "docs CI link check" line describes something that does not exist; this was run by hand instead. - **Line endings verified** — the repo checks these files out CRLF under `core.autocrlf=true`. Two scripted passes introduced `\r\r\n` and a mixed-ending full-file rewrite; both were caught by comparing `git diff --numstat` against the real content diff and repaired, so the diff is 274 insertions over 32 deletions rather than a 2,400-line rewrite of `EVENTS.md`. - **Edge parity confirmed after the retarget** — `edge` and `main` are the same commit in all eight repos, and this PR still reports `mergeable` against `edge` with the same four files. - Docs-only change: no code, no tests, no routes, no swagger. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [x] AI tools were used. Tool(s): `Claude Code (Opus 5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude changed target branch from main to edge 2026-09-02 02:00:32 +00:00
wtclaude added 1 commit 2026-09-02 02:00:32 +00:00
Closes the second half of EVENTS_PLAN.md Phase 0. All of EVENTS.md §N1–N11 were
answered by the org lead on 2026-09-01, before any code, which lifts the ⚠ gate
from P11 and P12 and unblocks P1.

Nine went the way §N recommended. Two did not, and each changes a phase:

- N2 — publishing a version and starting a run are `admin` only; a moderator
  keeps live control of a run already in flight (cancel, abort) and nothing
  more. Start and stop are deliberately not the same gate: starting commits the
  deployment to everything a definition contains, unattended, while cancelling
  is incident response. §K's table and the API surface table are updated, and
  P3 and P6 carry it.
- N4 — this deployment is single-instance and not planned to change, so P2 does
  not build the `--scale app=2` test. Every claim path in §E is built exactly as
  specified regardless — the unique index and the CAS equally protect a tick
  that overruns into the next one, and the lease and its reclaim recover a step
  whose process died mid-dispatch. §E records what to build first if this
  deployment is ever scaled.

N1 was taken in full, item grants included, which is a reversal of two separate
lines in ADMIN_CONTROLS.md §8 rather than one. §8's cut list names "item/gold
grants" explicitly and separately from world building, so the new §8a amendment
says both out loud rather than letting the grant ride along on the creation
reopening. §8's bullet is left standing verbatim — it is the decision that was
actually taken — with a pointer to the amendment, and §1's thesis paragraph gets
the same pointer. Loot-table changes and arbitrary [set / [get / [add stay
permanently excluded, along with the rest of the Tier-H moderation verbs.

N3 gives ENGAGEMENT.md §7.1 Q6's "no evaluator yet" an owner: the Event System
runner becomes the `kind: 'scheduled'` evaluator, built in that workstream's P2.
Nothing in the engagement contract changes.

One consequence was derived rather than decided and is flagged for review:
POST /admin/events/:id/verify moves to `admin, editor` rather than staying with
`start`. A dry run dispatches nothing, and the author who wrote the definition
is who should price it against the caps before asking an admin to publish.

Verified: every relative link and anchor in the four touched files resolves,
including the renamed §N anchor (#n--decisions) and the new #8a. The docs repo
has no CI workflow, so the plan's "docs CI link check" was run by hand.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 83309e9d09 into edge 2026-09-02 02:05:32 +00:00
whitlocktech deleted branch docs/events-decisions 2026-09-02 02:05:33 +00:00
Sign in to join this conversation.
No description provided.