feat(events): the step editor reworked, and event templates (MODULE_API 1.13.0) #212

Merged
whitlocktech merged 2 commits from feat/event-step-editor into main 2026-10-12 09:53:45 +00:00
Member

What & why

This is the core half of Rust PLAN_REDESIGNS.md §2 (U-3–U-6, F11; D192, D334). The first Rust player walk found the event step editor honest but hard to use. This PR reworks it, staying game-agnostic. Module-uo's steps get the new controls and nothing else.

Contract: MODULE_API 1.12.0 → 1.13.0. Four optional additions, so a minor bump:

  • api.registerEventTemplates([{ id, label, description, inputs, build }])
    • inputs are params (at most 8). Core checks them, calls build() (with a 10 s limit), validates the result as a spec, and answers an unsaved draft.
    • The new route is POST /admin/events/catalog/templates/:templateId (admin, editor).
    • Nothing about the template is stored.
  • A param's duration: 'minutes' (int or float only). core.lease's minutes declares it.
  • A lease's example for its value.
  • An option row's note (at most 300 characters), shown under the field while that option is chosen.

Editor

  • No · type tags and no bare *. A required field says so in words, but only once a save has been tried with it empty. The save then stops before the round trip.
  • Booleans: a toggle when the param is required, and [Not set] [Yes] [No] when it is optional (D334).
  • A choice of two or three (a lease's values, or a small source) is a row of buttons.
  • core.lease is drawn as the chosen lease:
    • the lease is picked by its label;
    • the value uses the lease's type, range, values and example;
    • the target is a picker over the lease's target.source (F11);
    • the minutes show the lease's longest hold.
  • A timed step keeps its run open (U-6). When a timed step is added to a phase with no advance rule, the phase gets after: <longest hold>. Under any phase whose run can end before its longest hold, a sentence says when the hold is given back. Teardown happens at run end, so later phases count toward the time.
  • Start asks when the draft is ahead (U-5): "Publish and start" or "Start version N". This uses a new draftAhead field on GET, PUT and publish, which compares the working spec with the published one as data.
  • A new event can start from a module's template.
  • Core's own examples no longer name a game (§0.9).

Regenerated: swagger-output.json (+ the new path only), routes.manifest.json and routes.guards.json (+ the new route only), and engagement-triggers.json (the moduleApiVersion line).

The spec is in docs PR (docs/event-step-editor): MODULE_API.md, EVENTS.md and PLAN_REDESIGNS.md §2.8. Decisions are in docs#334 (merged).

How it was tested

  • Server, new tests: test/eventStepEditor.test.js has 10 tests:
    • template registration and its refusals;
    • inputs checked before build();
    • every failure shape of build();
    • the duration rule;
    • the lease example;
    • option notes;
    • draftAhead.
  • Server, full TAP run: 2088 passed and 3 failed before the regeneration, all three generated-manifest checks.
    • After regenerating, the engagement-manifest test passes.
    • The two route-manifest tests pass with MODULES_DIR empty (7/7, which is how CI runs). With this machine's git-ignored modules/uo and modules/rust installed they fail, because module routes get mounted. I proved that by running both ways.
  • Client: 413/413, including the new test/eventStepEditor.test.js (12 tests: the phase guard, the shortfall sentence, missing params, segmenting and notes). npm run build is clean.
  • Module-uo proof, against this branch:
    • Module-uo's own frozen-manifest job: routes.manifest.json is current — 76 routes, all documented, and uo registers its 12 actions.
    • Module-uo server suite (npm test): 723/723.
    • Module-uo client suite: 45/45.
    • These are the same numbers the 1.11.0 proof had.
  • Not walked in a browser yet: D331 defers every walk to one pass at the end of the plan. §2.7 lists the rows.

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)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Claude Opus 5.5). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-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.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

## What & why This is the core half of Rust `PLAN_REDESIGNS.md` §2 (U-3–U-6, F11; D192, D334). The first Rust player walk found the event step editor honest but hard to use. This PR reworks it, staying game-agnostic. Module-uo's steps get the new controls and nothing else. **Contract: MODULE_API 1.12.0 → 1.13.0.** Four optional additions, so a minor bump: - `api.registerEventTemplates([{ id, label, description, inputs, build }])` - `inputs` are params (at most 8). Core checks them, calls `build()` (with a 10 s limit), validates the result as a spec, and answers an **unsaved draft**. - The new route is `POST /admin/events/catalog/templates/:templateId` (admin, editor). - Nothing about the template is stored. - A param's `duration: 'minutes'` (int or float only). `core.lease`'s `minutes` declares it. - A lease's `example` for its value. - An option row's `note` (at most 300 characters), shown under the field while that option is chosen. **Editor** - No ` · type` tags and no bare `*`. A required field says so in words, but only once a save has been tried with it empty. The save then stops before the round trip. - Booleans: a toggle when the param is required, and **[Not set] [Yes] [No]** when it is optional (D334). - A choice of two or three (a lease's `values`, or a small source) is a row of buttons. - **`core.lease` is drawn as the chosen lease:** - the lease is picked by its label; - the value uses the lease's type, range, `values` and example; - the target is a picker over the lease's `target.source` (F11); - the minutes show the lease's longest hold. - **A timed step keeps its run open (U-6).** When a timed step is added to a phase with no advance rule, the phase gets `after: <longest hold>`. Under any phase whose *run* can end before its longest hold, a sentence says when the hold is given back. Teardown happens at run end, so later phases count toward the time. - **Start asks when the draft is ahead (U-5):** "Publish and start" or "Start version N". This uses a new `draftAhead` field on GET, PUT and publish, which compares the working spec with the published one as data. - A new event can start from a module's template. - Core's own examples no longer name a game (§0.9). Regenerated: `swagger-output.json` (+ the new path only), `routes.manifest.json` and `routes.guards.json` (+ the new route only), and `engagement-triggers.json` (the `moduleApiVersion` line). The spec is in **docs PR** (`docs/event-step-editor`): `MODULE_API.md`, `EVENTS.md` and `PLAN_REDESIGNS.md` §2.8. Decisions are in docs#334 (merged). ## How it was tested - **Server, new tests:** `test/eventStepEditor.test.js` has 10 tests: - template registration and its refusals; - inputs checked before `build()`; - every failure shape of `build()`; - the duration rule; - the lease example; - option notes; - `draftAhead`. - **Server, full TAP run:** 2088 passed and 3 failed before the regeneration, all three generated-manifest checks. - After regenerating, the engagement-manifest test passes. - The two route-manifest tests pass with `MODULES_DIR` empty (7/7, which is how CI runs). With this machine's git-ignored `modules/uo` and `modules/rust` installed they fail, because module routes get mounted. I proved that by running both ways. - **Client:** 413/413, including the new `test/eventStepEditor.test.js` (12 tests: the phase guard, the shortfall sentence, missing params, segmenting and notes). `npm run build` is clean. - **Module-uo proof, against this branch:** - Module-uo's own frozen-manifest job: `routes.manifest.json is current — 76 routes, all documented`, and `uo` registers its 12 actions. - Module-uo server suite (`npm test`): 723/723. - Module-uo client suite: 45/45. - These are the same numbers the 1.11.0 proof had. - **Not walked in a browser yet:** D331 defers every walk to one pass at the end of the plan. §2.7 lists the rows. ## 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) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Claude Opus 5.5)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-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. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-10-12 07:10:20 +00:00
feat(events): the step editor reworked, and event templates (MODULE_API 1.13.0)
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 2m26s
PR Checks / client-build (pull_request) Successful in 2m44s
PR Checks / server-tests (pull_request) Successful in 20m38s
3e243ce772
Rust PLAN_REDESIGNS §2 (U-3-U-6, F11; D192, D334), core half. Game-agnostic:
Module-uo's steps get the new controls and nothing else.

Contract (MODULE_API 1.12.0 -> 1.13.0, four optional additions):
- api.registerEventTemplates([{ id, label, description, inputs, build }]):
  inputs are params (<= 8); core checks them, calls build() (10 s), validates
  the result as a spec and answers an unsaved draft.
  POST /admin/events/catalog/templates/:templateId (admin, editor).
- a param's duration: 'minutes' (int/float only); core.lease's minutes has it.
- a lease's example for its value.
- an option row's note (<= 300 chars), shown under the chosen field.

Editor:
- no type tags or bare asterisks; a required field says so in words once a
  save has been tried with it empty (and the save stops before the round trip).
- boolean: toggle when required, [Not set] [Yes] [No] when optional (D334).
- a choice of two or three is a row of buttons (lease values, small sources).
- core.lease drawn as the chosen lease: picked by label; value by the lease's
  type, range, values and example; target picker over target.source (F11);
  minutes with the lease's longest hold.
- a timed step keeps its run open: a phase with no advance rule gets
  after: <longest hold> when a timed step is added; a sentence under any phase
  whose run can end sooner (U-6).
- Start asks "Publish and start" or "Start version N" when the working copy is
  ahead of the published version (draftAhead on GET/PUT/publish; U-5).
- New event can start from a module's template.
- core's own examples name no game (§0.9).

Swagger, routes.manifest/guards and engagement-triggers.json regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-10-12 07:23:30 +00:00
feat(events): a searchable source's chosen note is found when the page lacks it
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 1m47s
PR Checks / client-build (pull_request) Successful in 1m58s
PR Checks / server-tests (pull_request) Successful in 14m58s
e58857c133
A searchable source answers the editor a bounded first page, so the value an
author picked (or a template filled in) may not be on it, and its note with it.
useChosenNote asks the source for that value as a search term, once per value,
and shows the exact match's note. Found building the Rust kit warning
(PLAN_REDESIGNS §2.6), whose source - rust.options.grouppermissions - is
searchable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Author
Member

One follow-up commit, e58857c: a searchable source's chosen note is found when the page lacks it.

A searchable source answers the editor a bounded first page. The value an author picked, or one a template filled in, may not be on that page, and its note goes missing with it. useChosenNote asks the source for that value as a search term, once per value, and shows the exact match's note.

I found this while building the Rust kit warning (PLAN_REDESIGNS §2.6), because its source, rust.options.grouppermissions, is searchable. The client build is clean and 413/413 tests pass.

Module-Rust's ci/core-ref.json is pinned to this head while the PR is open, the same as during website#209. It moves to the merge sha after the merge.

One follow-up commit, `e58857c`: **a searchable source's chosen note is found when the page lacks it.** A searchable source answers the editor a bounded first page. The value an author picked, or one a template filled in, may not be on that page, and its note goes missing with it. `useChosenNote` asks the source for that value as a search term, once per value, and shows the exact match's note. I found this while building the Rust kit warning (PLAN_REDESIGNS §2.6), because its source, `rust.options.grouppermissions`, is searchable. The client build is clean and 413/413 tests pass. Module-Rust's `ci/core-ref.json` is pinned to this head while the PR is open, the same as during website#209. It moves to the merge sha after the merge.
whitlocktech approved these changes 2026-10-12 09:53:36 +00:00
whitlocktech merged commit ca7ec53b14 into main 2026-10-12 09:53:45 +00:00
whitlocktech deleted branch feat/event-step-editor 2026-10-12 09:53:46 +00:00
Sign in to join this conversation.
No description provided.