docs(events): Phase 8 as built — the resource ledger, leases and cleanup #216
Reference in New Issue
Block a user
No description provided.
Delete Branch "docs/events-phase-8"
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?
The docs half of Event System Phase 8. Code: RunicGateway/website#190.
EVENTS.md§D's ledger row is corrected in two places, and §L's two rules gain a new subsection recording what the build settled:
refdoes not exist until the module answers. What goes in before the dispatch is a PLACEHOLDER keyed by the step's idempotency key — and that is why §F'sreverttakes the key at all. It is written after the permission check and before the module is reached: a refused step created nothing and must ledger nothing.core.leasewrites the real row first — which is also the only moment the two-events-one-target refusal can happen before the world has been written to.driftedandorphanedhold a target for ever, so one bad night would disable a lease permanently with no control able to clear it. Both stay LOUD by the other mechanism —cleanup_statusand a row on the console — which is what rule 2 actually asks for.statusalone —TEAMS.md§2.5's correction, because MariaDB refusesON DELETE SET NULLon a foreign key whose column is a base column of one, andstep_idmust stay SET NULL.orphanedis only ever reached through reconcile — a revert that finds nothing there is a success, whereas a resource the module reports missing is a thing that vanished while nobody was looking. Two different sentences to the operator reading the console the morning after.§F gains the lease's verb — core's, with the reason — and the
reconcilebullet, including the sentence that governs it: core has no concept of the game being up, so the module says when. §I's "cancel takes{ reason }and not{ cleanup }" becomes what shipped, and names the eighth control. §K's role table puts re-running cleanup in theadmin-only row. §L's cancel row and cleanup-fails row are updated. Observability names the six new log kinds. § API surface: thecleanuprow is filled in with why it is narrower than the seven controls beside it,cancelgains its flag, and the absent-routes list is now empty — nothing in that table is missing any more. The phase table: P8 ticked.EVENTS_PLAN.mdPhase 8 marked complete, in the shape Phases 0–7 use: the four org-lead decisions, the four things the build settled, the throwaway-module proof, the verified numbers, and the live walk.
Including the findings worth reading before the diff:
EVENT_REVERT_MAX_ATTEMPTSasserted<= 3, which the defect's value of 1 satisfied. Both halves — it retried, and it stopped — are asserted now.orphanedrather thanreverted.eventRunnerSql.test.js, found on the way: its model-backed tests were reaching the developer's real schema while asserting against fixtures written into the throwaway database next door.MODULE_API.md1.10.0 gains
reconcile()andctx.events.reconcile()IN PLACE rather than a new version (org lead, 2026-09-03). A protocol owes a bump once it has landed onmain; while it is onedgeit is amended in place — the rule the Teams workstream arrived at, applied to a module API for the first time. That is stated in the entry itself, so nobody later reads the missing 1.11.0 as an oversight.The rule list grows from six to ten, and each is a rule rather than a field: the lease's verb is core's and why;
untilgoes down the wire and a module that treats it as advisory has produced a lease that outlives an outage;revertmust be idempotent and reverting something that does not exist is a success;revertis also called with the key and an empty list, which is the lost-answer case and the whole reason it takes the key; andreconcileis optional whererevertis required, with the asymmetry explained.§2.4 grows from four contract items to six: core records before it dispatches, and core owns cleanup — derived, never authored, with no
on_teardownon an action and no cleanup phase in a spec.Checked by hand
docshas no CI, so: every anchor inEVENTS.mdresolves — checked by generating the heading slugs and diffing the link targets against them, not by eye — and every route, identifier, env var and file path named here exists on website#190:core.lease,core.options.leases,ctx.events.reconcile,EVENT_REVERT_MAX_ATTEMPTS,EVENT_CLEANUP_RUN_BATCH,event_run_resources,live_marker,uq_evres_target, the six log kinds,unresolvedResources, and the route in bothroutes.manifest.jsonand the OpenAPI spec.Diffs are 144/21, 139/16 and 67/9 with no CRLF artefact, verified by comparing
--numstatagainst the real content diff rather than trusting it.The docs half of Event System Phase 8. Code: RunicGateway/website#NNN. EVENTS.md Section D's ledger row is corrected in two places and section L gains a new subsection recording what the build settled: - Rule 1 needed a mechanism, because a spawn's ref does not exist until the module answers. What goes in before the dispatch is a PLACEHOLDER keyed by the step's idempotency key, and that is why revert() takes the key at all. - A LEASE does not use it and gets rule 1 in a stronger form: its target is the lease id the step already names, so `core.lease` writes the real row first -- the only moment the two-events-one-target refusal can happen before the world has been written to. - The unique key is held by three statuses and released by three (amended 2026-09-03). "Among non-reverted rows" was written before the six statuses had their meanings; taken literally it makes `drifted` and `orphaned` hold a target for ever, so one bad night would disable a lease permanently with no control able to clear it. - MariaDB has no partial index, so the encoding is a STORED generated column reading `status` ALONE -- TEAMS.md 2.5's correction, because MariaDB refuses ON DELETE SET NULL on a foreign key whose column is a base column of one. - Cleanup is one sweep, not synthetic step rows, and it runs from one place. - What that sweep SELECTS cost two live-walk defects in opposite directions, and the pair is the finding worth keeping: deriving "is there anything to do" from a summary column instead of from the rows stranded a lease outright, and then made the retry bound mean one attempt. Both are recorded with the reasoning. Section F gains the lease's verb and the reconcile bullet; section I's "cancel takes { reason } and not { cleanup }" becomes what shipped; section K's role table puts re-running cleanup in the admin-only row; section L's cancel and cleanup-fails rows are updated; Observability names the six new log kinds; and the API surface table's absent-routes list is now empty. EVENTS_PLAN.md Phase 8 marked complete in the shape Phases 0-7 use: the four org-lead decisions, the four things the build settled, the verified numbers, and the live walk -- including the three defects only it could find and the two properties that needed the process to die. MODULE_API.md 1.10.0 gains `reconcile()` and `ctx.events.reconcile()` IN PLACE rather than a new version. A protocol owes a bump once it has landed on `main`; while it is on `edge` it is amended in place, which is the rule the Teams workstream arrived at, applied to a module API for the first time. The rule list grows from six to ten: the lease's verb is core's, `until` goes down the wire, revert is idempotent and reverting something that does not exist is a success, revert is also called with the key and an empty list, and reconcile is optional where revert is required. Checked by hand `docs` has no CI, so: every anchor in EVENTS.md resolves (checked by generating the heading slugs and diffing), and every route, identifier, env var and file path named here exists on the website branch -- `core.lease`, `core.options.leases`, `ctx.events.reconcile`, `EVENT_REVERT_MAX_ATTEMPTS`, `event_run_resources`, `live_marker`, `uq_evres_target`, the six log kinds, and the route in both routes.manifest.json and the OpenAPI spec. Diffs are 144/21, 139/16 and 67/9 with NO CRLF artefact, verified by comparing --numstat against the real content diff rather than trusting it. Co-Authored-By: Claude <noreply@anthropic.com>