Files
website/server/engagement-triggers.json
wtclaude 1667e636bd feat(events): the public calendar, event pages and participation history (Phase 14a)
The anonymous surface an event was always for: GET /public/events,
/public/events/:slug and /public/events/series/:slug, plus
GET /player/events/history, and the four screens over them.

Four org-lead decisions taken up front: split Phase 14 into 14a (website)
and 14b (the app); add a `listed` flag rather than letting `state` mean both
schedulable and announced; put the `events` capability string in the version
block rather than publishing core as a pseudo-module; and drop "venue" from
the spec rather than adding a field nothing had ever built.

`listed` is announcement, not permission. Publishing is what makes a
definition runnable, so without a separate flag a surprise event would have
to be advertised in order to be allowed to happen. It is a column, a switch
in Phase 13's editor, and three SQL predicates -- never a filter applied
after a read, which works exactly as well until the first caller that forgets.

The public shapes are a projection, and the projection is the security
boundary: nothing is spread, so a column added to event_runs next year does
not ride out through it. The spec, health, cleanup, claims, errors and
member_key are all absent by construction.

The six public event triggers gained `eventUrl` (version 1 -> 2), carrying
?run= because the page lives at the definition's slug while every trigger is
about one occurrence. notify.event-started gained the button, at seedVersion 2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
2026-09-08 06:18:38 -05:00

590 lines
18 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"_comment": "Generated event-trigger inventory - the authoritative freeze of CORE's engagement contract (docs/website/ENGAGEMENT.md 4.3). Regenerate with `npm run engagement:manifest` in website/server. A renamed variable, a changed type or a widened ceiling breaks stored templates and rules, so the diff here is the review signal. A module ships its own copy in its bundle; this file never contains one.",
"moduleApiVersion": "1.10.0",
"triggers": [
{
"id": "event.phase.changed",
"owner": "core",
"label": "Event — a new phase",
"description": "An event that is under way has moved on to its next stage.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "phase",
"type": "string",
"required": true,
"example": "assault",
"description": "The phase key just entered, as authored in the spec."
},
{
"name": "phaseLabel",
"type": "string",
"required": false,
"example": "The assault",
"description": "The phase label, when the spec gave it one. Falls back to the key."
},
{
"name": "phaseIndex",
"type": "int",
"required": true,
"example": 2,
"description": "Which phase this is, counting from 1."
},
{
"name": "phaseCount",
"type": "int",
"required": true,
"example": 4,
"description": "How many phases the pinned version has in total."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "event.run.cancelled",
"owner": "core",
"label": "Event — cancelled",
"description": "A scheduled event was cancelled by a member of staff.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "reason",
"type": "string",
"required": false,
"example": "The shard is down for an emergency patch.",
"description": "What the staff member gave as the reason, when they gave one."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "event.run.completed",
"owner": "core",
"label": "Event — finished",
"description": "An event has finished.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "summary",
"type": "string",
"required": false,
"example": "Orcish warbands are massing north of Yew.",
"description": "The event summary, as authored."
},
{
"name": "participantCount",
"type": "int",
"required": true,
"example": 47,
"description": "How many participants the run recorded. Zero when nothing collected any."
},
{
"name": "durationMinutes",
"type": "int",
"required": true,
"example": 95,
"description": "How long the run took, start to end, in whole minutes."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "event.run.ending",
"owner": "core",
"label": "Event — winding down",
"description": "An event is drawing to a close.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "event.run.failed",
"owner": "core",
"label": "Event — run failed",
"description": "An event stopped before it finished.",
"kind": "event",
"subjectKey": "runId",
"audience": "admin",
"ceiling": "admin",
"version": 1,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "phase",
"type": "string",
"required": false,
"example": "assault",
"description": "The phase it failed in, when it had entered one."
},
{
"name": "error",
"type": "string",
"required": false,
"example": "sidecar responded 503",
"description": "The runs last error, verbatim from the run row."
},
{
"name": "runUrl",
"type": "url",
"required": true,
"example": "/admin/events/runs/3692",
"description": "Site-relative path to the run console."
}
]
},
{
"id": "event.run.scheduled",
"owner": "core",
"label": "Event — scheduled",
"description": "A new event has been added to the calendar.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "summary",
"type": "string",
"required": false,
"example": "Orcish warbands are massing north of Yew.",
"description": "The event summary, as authored."
},
{
"name": "seriesName",
"type": "string",
"required": false,
"example": "The Yew Campaign",
"description": "The arc this event belongs to, when it belongs to one."
},
{
"name": "startsAt",
"type": "datetime",
"required": true,
"example": "2026-09-12T20:00:00.000Z",
"description": "When the occurrence is due to start, UTC."
},
{
"name": "timezone",
"type": "string",
"required": false,
"example": "America/New_York",
"description": "The shard-local zone the schedule was authored in."
},
{
"name": "startsAtLabel",
"type": "string",
"required": false,
"example": "Saturday 12 September at 8:00 pm (America/New_York)",
"description": "The start time written out in the shard-local zone, for a mail to read."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "event.run.started",
"owner": "core",
"label": "Event — starting now",
"description": "A scheduled event has begun.",
"kind": "event",
"subjectKey": "runId",
"audience": "subscribers",
"ceiling": "authenticated",
"version": 2,
"variables": [
{
"name": "runId",
"type": "string",
"required": true,
"example": "3692",
"description": "The run this is about. Also the cooldown subject."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "The Yew Invasion",
"description": "The event title."
},
{
"name": "summary",
"type": "string",
"required": false,
"example": "Orcish warbands are massing north of Yew.",
"description": "The event summary, as authored."
},
{
"name": "seriesName",
"type": "string",
"required": false,
"example": "The Yew Campaign",
"description": "The arc this event belongs to, when it belongs to one."
},
{
"name": "startsAt",
"type": "datetime",
"required": true,
"example": "2026-09-12T20:00:00.000Z",
"description": "When it actually started, UTC."
},
{
"name": "timezone",
"type": "string",
"required": false,
"example": "America/New_York",
"description": "The shard-local zone the schedule was authored in."
},
{
"name": "startsAtLabel",
"type": "string",
"required": false,
"example": "Saturday 12 September at 8:00 pm (America/New_York)",
"description": "The start time written out in the shard-local zone, for a mail to read."
},
{
"name": "eventUrl",
"type": "url",
"required": false,
"example": "/site/events/the-yew-invasion?run=3692",
"description": "The public page for this occurrence."
}
]
},
{
"id": "news.post",
"owner": "core",
"label": "News post published",
"description": "A news / Five-on-Friday / newsletter post was published.",
"kind": "event",
"subjectKey": null,
"audience": "subscribers",
"ceiling": "authenticated",
"version": 1,
"variables": [
{
"name": "title",
"type": "string",
"required": true,
"example": "Five on Friday — the Yew invasion",
"description": "The post title."
},
{
"name": "excerpt",
"type": "string",
"required": false,
"example": "Four new champion spawns, and the fate of the Yew moongate…",
"description": "A plain-text summary, already stripped of markup."
},
{
"name": "category",
"type": "string",
"required": false,
"example": "Five on Friday",
"description": "The post category, when it has one."
},
{
"name": "postUrl",
"type": "url",
"required": true,
"example": "/site/news",
"description": "Site-relative path to the post. The news list today — the site has no per-post route."
}
]
},
{
"id": "team.announcement",
"owner": "core",
"label": "Team — announcement",
"description": "A leader posted an announcement in a Team.",
"kind": "event",
"subjectKey": "teamName",
"audience": "members",
"ceiling": "members",
"version": 1,
"variables": [
{
"name": "teamName",
"type": "string",
"required": true,
"example": "The Silver Anvil",
"description": "The Team the event is about. Also the cooldown subject."
},
{
"name": "authorName",
"type": "string",
"required": true,
"example": "Marisol",
"description": "Display name of the leader who posted."
},
{
"name": "title",
"type": "string",
"required": true,
"example": "Siege practice moved to Sunday",
"description": "The announcement title."
},
{
"name": "excerpt",
"type": "string",
"required": false,
"example": "We are moving practice to Sunday 8pm…",
"description": "Plain-text excerpt of the announcement body."
},
{
"name": "postUrl",
"type": "url",
"required": false,
"example": "/guilds/the-silver-anvil/forum/419",
"description": "Site-relative path to the announcement."
}
]
},
{
"id": "team.forum.post",
"owner": "core",
"label": "Team — new forum post",
"description": "A new thread or reply in a Team forum.",
"kind": "event",
"subjectKey": "teamName",
"audience": "members",
"ceiling": "members",
"version": 1,
"variables": [
{
"name": "teamName",
"type": "string",
"required": true,
"example": "The Silver Anvil",
"description": "The Team the event is about. Also the cooldown subject."
},
{
"name": "authorName",
"type": "string",
"required": true,
"example": "Darrow",
"description": "Display name of the poster."
},
{
"name": "threadTitle",
"type": "string",
"required": true,
"example": "Tuesday champ rotation",
"description": "Title of the thread the post belongs to."
},
{
"name": "excerpt",
"type": "string",
"required": false,
"example": "Moving the Tuesday run an hour later…",
"description": "Plain-text excerpt of the post body, already stripped of markup."
},
{
"name": "postUrl",
"type": "url",
"required": false,
"example": "/guilds/the-silver-anvil/forum/412",
"description": "Site-relative path to the post."
}
]
},
{
"id": "team.leadership.changed",
"owner": "core",
"label": "Team — leadership change",
"description": "Leadership changed in a Team.",
"kind": "event",
"subjectKey": "teamName",
"audience": "members",
"ceiling": "members",
"version": 1,
"variables": [
{
"name": "teamName",
"type": "string",
"required": true,
"example": "The Silver Anvil",
"description": "The Team the event is about. Also the cooldown subject."
},
{
"name": "leaderName",
"type": "string",
"required": true,
"example": "Marisol",
"description": "Display name of the new leader."
},
{
"name": "teamUrl",
"type": "url",
"required": false,
"example": "/guilds/the-silver-anvil",
"description": "Site-relative path to the Team page."
}
]
},
{
"id": "team.member.joined",
"owner": "core",
"label": "Team — new member",
"description": "Someone joined a Team.",
"kind": "event",
"subjectKey": "teamName",
"audience": "members",
"ceiling": "members",
"version": 1,
"variables": [
{
"name": "teamName",
"type": "string",
"required": true,
"example": "The Silver Anvil",
"description": "The Team the event is about. Also the cooldown subject."
},
{
"name": "memberName",
"type": "string",
"required": true,
"example": "Darrow",
"description": "Display name of the member who joined."
},
{
"name": "teamUrl",
"type": "url",
"required": false,
"example": "/guilds/the-silver-anvil",
"description": "Site-relative path to the Team page. Absent when no module supplies a pageUrlTemplate."
}
]
}
]
}