docs: group-encounters follow-up backlog + mark helper-tools PRD superseded

- Add follow-up-stories.md (FU-1..FU-11) for the group-encounters feature:
  deferred items extracted from the PRD non-goals + arch 'Areas for Future
  Enhancement' + 3-round party-mode decision log (durable timers, ConditionsReader
  real impl, campaignId enforcement, CAP-17 full refactor, multi-scene passive
  reveals, spectator views, OQ-8 modifiers, live-E2E gap, plus two verify items).
- Mark _bmad-output/specs/spec-encounter-builder/prd.md as superseded
  (status: final -> superseded) with a pointer to ADR-012: the helper-tools
  suite is a Claude Code skill, not the local web app + published package
  (P-1) this PRD described. Closes the drift between the doc and shipped reality.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kaysser Kayyali
2026-06-22 15:46:53 +00:00
parent 0028f96349
commit c549aaa49f
2 changed files with 143 additions and 2 deletions

View File

@@ -0,0 +1,130 @@
---
title: "Group Encounters — Follow-up Stories (deferred / ship-and-break items)"
status: backlog
source_prd: ./prd.md
source_arch: ../../arch/arch-mardonar-encounter-engine-2026-06-20/architecture.md
created: 2026-06-22
updated: 2026-06-22
---
# Group Encounters — Follow-up Stories
Backlog of items the Group Encounters PRD (`prd.md`) and architecture
(`../../arch/arch-mardonar-encounter-engine-2026-06-20/architecture.md`) explicitly
deferred, accepted as ship-and-break trade-offs, or left open. The feature set
(Features AE + FR-43) shipped in commit `0028f96`; this file tracks what was
*intentionally left for later*.
> **Confidence note.** These stories are derived from the PRD/arch *design docs*,
> not a line-by-line audit of the merged code. Each story is tagged
> `confidence: high|medium|verify`. Before pulling one into a sprint, confirm
> against the current source that it is still outstanding (some may have landed
> post-merge without updating these docs).
---
## FU-1 — Durable timed-check timers + multi-instance locking
- **status:** deferred · **confidence: high**
- **Source:** PRD §3 Non-Goals ("Durable timers… Redis-TTL-backed timers are deferred (NFR-2)"); FR-5 (restart cancels pending timed check as fail); arch line 561 "Areas for Future Enhancement: durable timers / multi-instance locking (if scale lands)"; ADR-006 (in-process mutex with documented Lua swap path).
- **Today:** Timed single-player checks use in-memory timers; a bot restart cancels the pending check as a failure. Group-check serialization uses an in-process per-threadId mutex (`sessionManager.atomicMutate`), not Redis Lua/WATCH.
- **Acceptance:**
- Timed-check timer state persists to Redis with a TTL so a restart rehydrates (not fails) an in-flight timed check.
- `atomicMutate` swaps to a cross-process-safe primitive (Redis Lua compare-and-set / `WATCH`) so the engine can run multi-instance without corrupting session/group-check state.
- Boot sweep updated for the durable-timer case; no thread hangs on restart.
- **Depends on:** a real need to run >1 instance (scale trigger) — the arch scopes this as "if scale lands."
## FU-2 — ConditionsReader real implementation (E-L2 cutover)
- **status:** deferred · **confidence: high**
- **Source:** PRD §3 Non-Goal (Foundry write-back for equipment/conditions); FR-31 (read Foundry conditions incl. advantage/disadvantage-granting, feeding FR-43); arch lines 88/118/274 (conditions relay-blocked; `StubConditionsReader` from YAML fixture + `RelayConditionsReader` behind `FOUNDRY_CONDITIONS_ENABLED`; E-L2 sole relay-dependent tier); ADR-008 (ConditionsReader stub).
- **Today:** `src/harness/conditionsReader.ts` is a stub returning canned fixture data. D + E-L1 ship independently of the relay. Foundry-granted advantage/disadvantage is not yet wired into FR-43 precedence.
- **Acceptance:**
- Foundry relay exposes a conditions read RPC against the bot-owned, contract-first schema.
- `RelayConditionsReader` implements it; `FOUNDRY_CONDITIONS_ENABLED` flips to true.
- Foundry-derived advantage/disadvantage flows into FR-43 precedence (explicit LLM emit arg > Foundry adv/dis > straight roll).
- Single Foundry-status→Mardonar-condition mapping seam file in place; build-time version coupling + CI pair-check (no runtime handshake).
- **Depends on:** relay maintainer delivering the conditions read RPC to the bot-owned schema.
## FU-3 — `campaignId` enforcement + campaign-bound encounters
- **status:** planned, not enforced · **confidence: high**
- **Source:** PRD §3 Non-Goal ("Campaign grouping (`campaignId`). Remains planned, not enforced."); arch lines 256/459 (`campaign:{campaignId}` key in registry; "Campaign-bound encounters: `maxPlayers ≤ party size`").
- **Today:** `campaignId` exists in the schema/key registry but is not enforced; encounters are not bound to a campaign party.
- **Acceptance:**
- Starting an encounter with a `campaignId` binds it to that campaign's party roster.
- Lobby `maxPlayers` reconciled against campaign party size (`maxPlayers ≤ party size`).
- Latecomer join respects campaign membership.
- **Depends on:** CAP-12/13 data-model layer for campaign party.
## FU-4 — CAP-17 full schema refactor (non-blocking epic)
- **status:** deferred (non-blocking) · **confidence: high**
- **Source:** arch line 98 ("CAP-17 conditional… scoped minimal… full refactor separate non-blocking epic"); decision-log round 3 ("CAP-17 wizard-reconciliation → non-blocking follow-up").
- **Today:** Only the scoped-minimal CAP-17 slice shipped (schema adds the group-encounter fields need + existing-spec migration). The full encounter-spec refactor is deferred.
- **Acceptance:**
- Full `EncounterSpec` refactor (the part beyond what group encounters required) lands without blocking encounter runtime.
- Encounter-wizard reconciliation completed as part of the refactor (named sub-task with its own AC).
- **Note:** This is an epic, not a single story — break into stories when prioritized.
## FU-5 — Multi-scene / staged passive reveals
- **status:** deferred (non-goal) · **confidence: high**
- **Source:** PRD §3 Non-Goal ("Multi-scene passive reveals… passive reveals apply at encounter start"); FR-7 (passive reveals fire at encounter start); `[ASSUMPTION]` "Passive reveals apply at encounter start only (no scenes/stages today)."
- **Today:** Passive reveals fire once at encounter start. The engine has no scenes/stages.
- **Acceptance:**
- A scene/stage concept exists so passive reveals can fire mid-encounter on stage transitions.
- `passiveReveals` can be scoped to a stage, not just encounter start.
- **Depends on:** a scenes/stages model (currently absent).
## FU-6 — Spectator / DM-only private views of group checks
- **status:** deferred (non-goal) · **confidence: high**
- **Source:** PRD §3 Non-Goal ("Spectator / DM-only private views of group checks").
- **Today:** Group checks have the central scoreboard + per-player ephemerals; no DM-only or spectator view.
- **Acceptance:** A DM-only (and/or spectator) view of a group check exists without leaking roll state to players.
## FU-7 — Foundry write-back for equipment/conditions
- **status:** deliberate non-goal (listed for completeness) · **confidence: high**
- **Source:** PRD §3 Non-Goal ("Foundry write-back for equipment/conditions (Foundry is read-only for these…).")
- **Today:** Foundry is read-only for equipment/conditions; only engine-tracked story status is mutable locally.
- **Note:** This was a deliberate scope cut, not an oversight. Pull in only if the DM workflow proves it's needed.
## FU-8 — OQ-8: hidden vs open modifiers on the group scoreboard
- **status:** open question · **confidence: high**
- **Source:** PRD §8 OQ-8 ("The scoreboard shows each player's modifier (`rolled 16 +3`) to the group. Open rolls (modifiers visible) is the assumed default; confirm or require hidden modifiers."); arch line 474 ("no hide flag for v1 (deferred)").
- **Today:** Open rolls — modifiers visible on the scoreboard. No hide flag.
- **Acceptance:**
- Decision recorded: keep open rolls, **or** add a spec/emit-level hide-modifiers option.
- If hidden: scoreboard shows only pass/fail (or the d20 total), not the modifier breakdown.
## FU-9 — Group-check live E2E gap (release-gate the manual playtest)
- **status:** accepted risk → formalize · **confidence: high**
- **Source:** arch line 111 ("Group checks = unit + integration coverage only; no live E2E tier… one-token constraint… mitigated by… manual pre-release multi-player playtest checklist item in the release gate"); decision-log round 3 (Murat locks group-check testing = unit+integration-only w/ documented live-E2E gap).
- **Today:** Group checks have unit + integration coverage only. Simultaneous multi-player fan-out, successRule N>1, per-user ephemeral delivery, and second-claimant rejection are **not** live-E2E covered. A manual pre-release multi-player playtest checklist is the safety net.
- **Acceptance:**
- The 7-step manual multi-player playtest checklist is checked into the repo and referenced from the release gate (not just the arch doc).
- **Optional (if the one-token constraint ever relaxes):** a second-token live E2E covering the four "unit+integration only" cases.
- **Note:** Test debt, not a feature gap.
## FU-10 — Verify: encounter-wizard reconciliation sub-skills landed
- **status:** verify · **confidence: medium**
- **Source:** arch line 114 ("Wizard: 2 new sub-skills (Players & Lobby, Passive Reveals) + edits to 2 existing, schema MUST land before wizard reconciliation").
- **Today:** The encounter-wizard skill was built 2026-06-20 with 12 nested section skill files (per project memory). Whether the two new sub-skills (Players & Lobby, Passive Reveals) and the two edits actually landed is unconfirmed against this doc.
- **Acceptance:** Confirm `.claude/skills/mardonar-encounter-wizard/sections/` contains Players & Lobby + Passive Reveals sub-skills and the two edited existing sections reflect group-encounter fields. If missing → file as a real story.
## FU-11 — Verify: `src/lib/systemStrings.ts` centralization landed
- **status:** verify · **confidence: medium**
- **Source:** arch line 114 ("In-world voice: centralize system-string templates in one module (`src/lib/systemStrings.ts`) + named registry + forbidden-word grep on rendered output"); decision-log round 3 (Paige: "systemStrings.voice = 7th harness").
- **Today:** The in-world-voice rule is enforced by convention. Whether the centralized `systemStrings.ts` module + the forbidden-word grep on **rendered** output (catches runtime concatenation, not just source literals) landed is unconfirmed.
- **Acceptance:** Confirm `src/lib/systemStrings.ts` exists, the named registry is in use, and a CI/hook grep runs on rendered output. If missing → file as a real story (it's a contract-integrity guard for new narrator paths, same family as ADR-005).
---
## Not deferred (intentionally closed — do not re-open)
- **FR-43 deprecation window / `SKILL_CHECK_SURFACE` flag (FR-49/FR-50):** RETIRED by the round-3 party-mode decision (Mary's trim). Ship-and-break in one release, no flag, plain system notice for old buttons, pinned Discord message. This is *done by design*, not a follow-up.
- **Straggler deadline as a spec field:** retracted → became a DM "resolve with current rolls" UX affordance (FR-47), not a spec field.
---
## Suggested prioritization
1. **FU-2** (ConditionsReader) — unblocks full FR-31/FR-43 fidelity; relay-dependent, so longest lead time → start the contract-first schema now.
2. **FU-8** (OQ-8) — a one-decision story; cheap to close and it affects every group-check scoreboard.
3. **FU-9** (live E2E gap) — test debt that protects the most residual risk; cheap to formalize the checklist.
4. **FU-10 / FU-11** (verify items) — quick confirmations; convert to stories only if missing.
5. **FU-1, FU-3, FU-4, FU-5, FU-6** — scope/trigger-gated; pull when the trigger lands (scale, campaign play, scenes, DM demand).
6. **FU-7** — only if DM workflow demands it.

View File

@@ -1,14 +1,25 @@
---
title: Mardonar Helper Tools — PRD
status: final
status: superseded
superseded_by: "ADR-012 — helper tools are a Claude Code skill (.claude/skills/mardonar-encounter/ + mardonar-encounter-wizard/), not a web app"
created: 2026-06-20
updated: 2026-06-20
updated: 2026-06-22
source_spec: ./SPEC.md
target_repo: separate project (TBD — see Open Questions)
---
# Mardonar Helper Tools — PRD
> **⚠ SUPERSEDED 2026-06-20.** The local-web-app form factor and the published
> engine-contract package (P-1) described below were **abandoned** in favor of a
> Claude Code skill. The shipped reality is the encounter-authoring skill at
> `.claude/skills/mardonar-encounter/` (author + refine) and
> `.claude/skills/mardonar-encounter-wizard/` (guided section-by-section
> wizard), which validate against the real `EncounterSpecSchema` via an in-process
> `loadSpec` round-trip — no published package needed. This document is retained
> for history only; do not implement the web-app/package work below. See
> `follow-up-stories.md` / ADR-012 in the engine repo.
> **Re-scoped 2026-06-20** from "encounter builder" to a **helper-tools suite**: a local web app that hosts pluggable DM helper tools, with the **Encounter Builder** as the first tool (plugin #1). The form factor was confirmed as a **local web app** the same day (no longer an assumption). Authored FROM `SPEC.md`, whose 6 capabilities describe the Encounter Builder *tool*; the suite-shell concerns (tool hosting + shared services) are PRD-originated and flagged for spec sync at **OQ-1**.
## 1. Problem & Vision