feat(demo): refuse an event step at save with demoRefuses (MODULE_API 1.19.0) #224

Merged
whitlocktech merged 1 commits from feature/demo-step-refusal into main 2026-10-26 05:52:10 -05:00
Member

Core half of the public demo's step 2 (#222, docs/website/DEMO_MODE.md §3.4 and §10). Decision DM18 (org lead, 2026-10-24): a new core hook, because core's event save never asked a module about a step's params. Without it, the console-command deny list could not refuse at save.

What it does

  • demoRefuses(params): a new, optional event-action member.
    • It returns a sentence, or null.
    • With DEMO_MODE=true, POST /admin/events, PUT /admin/events/:id and POST /admin/events/:id/publish ask it for every step.
    • The first sentence refuses the write: 403 { code: "DEMO_LOCKED", message, errors: [message] }.
    • A hook that throws refuses too, with core's own sentence (fails closed).
    • Publish asks again, so a draft saved before the module's list grew never becomes a version.
  • Off the demo it is validated (it must be a function) and never called. The admin catalog strips it with the other callables.
  • Controller. The three handlers pass code and message through, so the client's one DEMO_LOCKED toast fires for a step refusal, as it does for a route lock.
  • Version. MODULE_API_VERSION is 1.19.0 in both halves, and the OpenAPI DemoLocked schema documents errors.

The first user is Module-Rust's console-command deny list (its PR follows, pinned to this branch).

Verified

  • npm test (server): 2213 pass, 0 fail, 99 skipped (the live-DB suites), with MODULES_DIR pointed away from a local modules/ checkout.
  • npm test (client): 435 pass.
  • New test/demoStepRefusal.test.js covers:
    • shape validation and the catalog strip;
    • off the demo, never asked;
    • create, save and publish each refused with nothing written;
    • an allowed command saving;
    • a throwing hook failing closed;
    • the controller's response body.
  • Live smoke on a scratch DB, with DEMO_MODE=true and Module-Rust feat/demo-mode installed:
    • an event running quit is refused at create ("quit" is turned off on the demo site.);
    • a reward running global.restart is refused;
    • say hi saves;
    • editing it to a teardown of o.unload RunicGateway is refused.
  • Swagger regenerated. routes.manifest.json: no change. engagement-triggers.json regenerated (it embeds the API version).

Docs

RunicGateway/docs PR on docs/demo-mode-module: MODULE_API.md 1.19.0, DEMO_MODE.md DM18, BACKEND_DESIGN.md §5.1.

  • AI-assisted: written with Claude Code (Claude Opus 5.5).

🤖 Generated with Claude Code

https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY

Core half of the public demo's step 2 (#222, `docs/website/DEMO_MODE.md` §3.4 and §10). Decision **DM18** (org lead, 2026-10-24): a new core hook, because core's event save never asked a module about a step's params. Without it, the console-command deny list could not refuse at **save**. ## What it does - **`demoRefuses(params)`**: a new, optional event-action member. - It returns a sentence, or `null`. - With `DEMO_MODE=true`, `POST /admin/events`, `PUT /admin/events/:id` and `POST /admin/events/:id/publish` ask it for every step. - The first sentence refuses the write: `403 { code: "DEMO_LOCKED", message, errors: [message] }`. - A hook that throws refuses too, with core's own sentence (fails closed). - Publish asks again, so a draft saved before the module's list grew never becomes a version. - **Off the demo** it is validated (it must be a function) and never called. The admin catalog strips it with the other callables. - **Controller.** The three handlers pass `code` and `message` through, so the client's one `DEMO_LOCKED` toast fires for a step refusal, as it does for a route lock. - **Version.** `MODULE_API_VERSION` is **1.19.0** in both halves, and the OpenAPI `DemoLocked` schema documents `errors`. The first user is Module-Rust's console-command deny list (its PR follows, pinned to this branch). ## Verified - `npm test` (server): **2213 pass, 0 fail**, 99 skipped (the live-DB suites), with `MODULES_DIR` pointed away from a local `modules/` checkout. - `npm test` (client): **435 pass**. - New `test/demoStepRefusal.test.js` covers: - shape validation and the catalog strip; - off the demo, never asked; - create, save and publish each refused with nothing written; - an allowed command saving; - a throwing hook failing closed; - the controller's response body. - **Live smoke** on a scratch DB, with `DEMO_MODE=true` and Module-Rust `feat/demo-mode` installed: - an event running `quit` is refused at create (`"quit" is turned off on the demo site.`); - a reward running `global.restart` is refused; - `say hi` saves; - editing it to a teardown of `o.unload RunicGateway` is refused. - Swagger regenerated. `routes.manifest.json`: no change. `engagement-triggers.json` regenerated (it embeds the API version). ## Docs RunicGateway/docs PR on `docs/demo-mode-module`: MODULE_API.md 1.19.0, DEMO_MODE.md DM18, BACKEND_DESIGN.md §5.1. - [x] AI-assisted: written with Claude Code (Claude Opus 5.5). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
wtclaude added 1 commit 2026-10-26 03:40:05 -05:00
feat(demo): refuse an event step at save with demoRefuses (MODULE_API 1.19.0)
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 46s
PR Checks / server-tests (pull_request) Successful in 7m0s
PR Checks / client-build (pull_request) Successful in 7m29s
cee4ab8aea
DEMO_MODE.md §3.4 refuses a denied console command when the event is
saved and when it runs. Saving is core's route, and core never asked a
module about a step's params, so the save-time half had no seam (DM18).

An event action may now declare demoRefuses(params), returning a
sentence or null. With DEMO_MODE on, create, save and publish ask it
for every step; the first sentence refuses the write 403 DEMO_LOCKED
with that sentence as the message (and in errors). A hook that throws
refuses too. Off the demo it is validated and never called, and the
catalog strips it with the other callables.

The events controller passes code and message through on create,
update and publish, so the client's one DEMO_LOCKED toast fires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
whitlocktech approved these changes 2026-10-26 05:52:02 -05:00
whitlocktech merged commit 69998ec548 into main 2026-10-26 05:52:10 -05:00
whitlocktech deleted branch feature/demo-step-refusal 2026-10-26 05:52:11 -05:00
Sign in to join this conversation.
No description provided.