Approve MVP technical and acceptance plans
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Instructions for Labyricorn publishing content
|
||||
|
||||
These instructions apply to the entire `.labyricorn/` directory. More specific
|
||||
instructions in `project/AGENTS.md` and `devlog/AGENTS.md` also apply within
|
||||
those directories.
|
||||
|
||||
## Purpose and ownership
|
||||
|
||||
- This directory is the repository-owned source for the project's exhibition
|
||||
page and development log on Labyricorn.
|
||||
- This project repository is authoritative for the content. The Labyricorn site
|
||||
imports it as read-only content.
|
||||
- Read `.labyricorn/README.md` and the nearest scoped `AGENTS.md` before editing
|
||||
a publishing record.
|
||||
- Keep publishing changes focused. Do not alter application code merely to
|
||||
support an exhibition or devlog edit unless the user separately requests it.
|
||||
|
||||
## Authorization and content contract
|
||||
|
||||
- Preserve unrelated and uncommitted work. Never discard changes to obtain a
|
||||
clean working tree.
|
||||
- Do not commit or push unless the user explicitly requests publication.
|
||||
- Use native Lektor records named `contents.lr` and preserve `schema_version: 1`
|
||||
until a coordinated schema migration is approved.
|
||||
- Keep attachments inside the record subtree that owns them.
|
||||
- Use UTF-8 text, `YYYY-MM-DD` dates, and stable lowercase hyphenated slugs.
|
||||
- Do not add templates, models, plugins, workflows, executable files, builds,
|
||||
application state, credentials, raw HTML, scripts, or active third-party
|
||||
content below `.labyricorn/`.
|
||||
- Treat published URLs as durable. Ask before renaming or removing a published
|
||||
record; redirects or archival behavior may be required first.
|
||||
|
||||
## Security, synchronization, and review
|
||||
|
||||
- Never store or print passwords, API tokens, refresh credentials, private keys,
|
||||
`.netrc` contents, or other secrets in this directory.
|
||||
- Do not claim content is public merely because a push succeeded. Report push
|
||||
status and Labyricorn synchronization status separately.
|
||||
- Parse changed records, confirm referenced source commits exist, run
|
||||
`git diff --check`, and review the exact publishing diff before committing.
|
||||
- At handoff, report changed publishing records, validation performed, commit
|
||||
and push status, and synchronization status if known.
|
||||
@@ -6,6 +6,9 @@ This repository owns the public project page and development log for Twungeon.
|
||||
- `.labyricorn/devlog/contents.lr` is the development-log index.
|
||||
- Each directory below `.labyricorn/devlog/` is one chronological entry.
|
||||
|
||||
The project is currently in pre-development. The PRD and MVP definition are
|
||||
complete; future work should add dated devlog entries as the project moves
|
||||
through planning, implementation, testing, release, and maintenance.
|
||||
The project is currently in pre-implementation planning. The PRD and MVP
|
||||
definition are complete, the technical specification is approved, and a
|
||||
traceable acceptance-test/build checklist now defines the route into
|
||||
implementation. Runtime behavior and live Twitch integration are not yet
|
||||
claimed complete. Future work should add dated devlog entries as the project
|
||||
moves through implementation, testing, release, and maintenance.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Instructions for the Labyricorn development log
|
||||
|
||||
These instructions apply to `.labyricorn/devlog/` and help coding assistants
|
||||
maintain the project's public development narrative safely.
|
||||
|
||||
## Format and ownership
|
||||
|
||||
- Keep the devlog index at `devlog/contents.lr` using `_model: devlog` and
|
||||
`schema_version: 1`.
|
||||
- Store each entry at `devlog/<stable-slug>/contents.lr` using
|
||||
`_model: devlog-entry` and `schema_version: 1`.
|
||||
- Use lowercase hyphenated entry slugs. Published slugs are durable public URLs;
|
||||
do not rename or delete them without explicit approval and a redirect or
|
||||
archival decision.
|
||||
- Every entry must contain `title`, `date`, `author`, `summary`, `tags`,
|
||||
`source_commit`, and Markdown `body` fields.
|
||||
- Keep entry attachments in that entry's directory. Only PNG, JPEG, and WebP
|
||||
images are accepted by the Labyricorn importer.
|
||||
- Do not add templates, models, plugins, executable code, builds, application
|
||||
state, credentials, or active third-party content below this directory.
|
||||
|
||||
## Content guidance
|
||||
|
||||
- Base entries on verifiable repository history, project documentation, and
|
||||
implemented behavior. Do not invent motivations, results, release status,
|
||||
user feedback, or completion claims.
|
||||
- Explain the milestone, why it mattered, and what changed. Keep one main
|
||||
milestone per entry and write a summary that works in a chronological list.
|
||||
Do not merely expand a commit message or enumerate every changed file.
|
||||
- Distinguish design and schema contracts from completed runtime behavior.
|
||||
- Link to the relevant canonical commit using the repository's HTTPS web URL.
|
||||
- Use the referenced commit's actual `YYYY-MM-DD` calendar date for retrospective
|
||||
entries, not the date on which the prose was drafted.
|
||||
- Set `source_commit` to the full lowercase 40-character commit ID most directly
|
||||
associated with the milestone. It must be an ancestor of the published branch.
|
||||
- Topics are comma-separated display labels. Unknown topics are allowed: the
|
||||
site keeps them visible but unlinked. Do not create or edit the site's tracked
|
||||
tag registry from this project repository.
|
||||
- Use Markdown without raw HTML, scripts, embedded credentials, or active
|
||||
external content.
|
||||
- Multiple entries may share a date. The site resolves ties from source history;
|
||||
do not invent timestamps or manual next/previous links.
|
||||
- Do not rewrite older entries merely because the implementation later changed.
|
||||
Add a new entry or a clearly labelled correction when historical context is
|
||||
needed.
|
||||
|
||||
## Safety and review
|
||||
|
||||
- Preserve unrelated project files and uncommitted work. The devlog owns only
|
||||
`.labyricorn/devlog/`.
|
||||
- Do not commit or push unless the user explicitly requests publication.
|
||||
- Before publication, verify claims against the referenced commit, validate all
|
||||
records, check that the source-commit link uses the same full commit ID, review
|
||||
the exact devlog diff, and confirm unrelated files are not staged in the
|
||||
publishing commit.
|
||||
- Prefer the repository-root `devlog_editor.py` for routine validation and safe
|
||||
publication when it is available.
|
||||
@@ -51,3 +51,6 @@ This entry marks the end of product definition, not the beginning of
|
||||
implementation. Future devlog entries will record technical planning, build
|
||||
phases, validation evidence, scope changes, and what is learned from real
|
||||
viewers.
|
||||
|
||||
The canonical source for this product-definition milestone is
|
||||
[commit `d67d9fc5230985895de9dd8232525ea8ca474e05`](https://git.labyricorn.com/Labyricorn/Twungeon/commit/d67d9fc5230985895de9dd8232525ea8ca474e05).
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Instructions for the Labyricorn project record
|
||||
|
||||
These instructions supplement `.labyricorn/AGENTS.md` and apply to the
|
||||
`project/` directory.
|
||||
|
||||
## Record structure
|
||||
|
||||
- Maintain exactly one project record at `project/contents.lr` using
|
||||
`_model: project` and `schema_version: 1`.
|
||||
- Keep `project_id` stable. It is the durable identity used by the importer and
|
||||
public URL.
|
||||
- Ask before changing the repository URL, default branch, project status,
|
||||
author, start date, or project identity.
|
||||
- Store project-owned images in this directory and reference them by filename
|
||||
from `contents.lr`. Only PNG, JPEG, and WebP images are accepted.
|
||||
|
||||
## Editorial guidance
|
||||
|
||||
- Write the exhibition page as a concise project narrative, not as a copy of
|
||||
the repository README or as release documentation.
|
||||
- Verify technical and status claims against the repository before editing.
|
||||
- Distinguish completed work, formal design work, experiments, and future work.
|
||||
- Do not manually add repository-derived commit, license, language, release,
|
||||
issue, star, or fork metadata. The Labyricorn importer owns those values.
|
||||
- Keep the summary suitable for listings and social previews.
|
||||
|
||||
## Review requirements
|
||||
|
||||
- Confirm all required project fields are present and any image reference stays
|
||||
inside `project/`.
|
||||
- Check Markdown links are intentional HTTPS links and prose makes no unsupported
|
||||
claims.
|
||||
- Validate the record and run `git diff --check` before committing.
|
||||
@@ -18,7 +18,7 @@ repository_url: https://git.labyricorn.com/Labyricorn/Twungeon
|
||||
---
|
||||
default_branch: main
|
||||
---
|
||||
tags: Twitch, Twitch Extension, RPGJS, Twurple, TypeScript, game design, pre-development, PRD, MVP, planning, architecture, documentation
|
||||
tags: Twitch, Twitch Extension, RPGJS, Twurple, TypeScript, game design, pre-development, PRD, MVP, planning, architecture, acceptance testing, documentation
|
||||
---
|
||||
body:
|
||||
|
||||
@@ -45,8 +45,15 @@ Twurple for Twitch integration, and a Twitch Extension for player controls.
|
||||
The design keeps Twungeon's game rules separate from RPGJS where practical so
|
||||
the prototype can be replaced without discarding the validated concept.
|
||||
|
||||
The current source of truth is the
|
||||
The product source of truth is the
|
||||
[Twungeon MVP Product Requirements Document](https://git.labyricorn.com/Labyricorn/Twungeon/blob/main/Twungeon_MVP_PRD_Current.md).
|
||||
The project is in pre-development: the PRD and MVP definition are complete,
|
||||
and this repository will document the transition through technical planning,
|
||||
implementation, testing, release preparation, and maintenance.
|
||||
The approved
|
||||
[technical specification](https://git.labyricorn.com/Labyricorn/Twungeon/blob/main/Twungeon_MVP_Technical_Specification.md)
|
||||
defines the authoritative architecture and game behavior. The
|
||||
[acceptance-test and build checklist](https://git.labyricorn.com/Labyricorn/Twungeon/blob/main/Twungeon_MVP_Acceptance_Test_and_Build_Checklist.md)
|
||||
sequences implementation and maps evidence to all 33 MVP success criteria.
|
||||
|
||||
The project remains in pre-implementation planning. These documents establish
|
||||
the build baseline, but they do not claim that runtime behavior, Twitch
|
||||
integration, or viewer validation is complete. Future records will document
|
||||
implementation, testing, release preparation, and maintenance as they occur.
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
# Twungeon
|
||||
|
||||
Twungeon as a Twitch-controlled cooperative dungeon game.
|
||||
Twungeon is a Twitch-controlled cooperative dungeon game in which viewers watch
|
||||
a shared world on stream, join through Twitch chat, and control individual
|
||||
characters with a Twitch Extension.
|
||||
|
||||
## Project status
|
||||
|
||||
Twungeon is in pre-implementation planning. The MVP product requirements and
|
||||
technical specification are approved, and the acceptance-test/build checklist
|
||||
is ready to guide implementation. No runtime MVP behavior or live Twitch
|
||||
integration is claimed complete yet.
|
||||
|
||||
## Planning documents
|
||||
|
||||
- [MVP Product Requirements Document](Twungeon_MVP_PRD_Current.md) — defines the
|
||||
product boundary and 33 success criteria.
|
||||
- [MVP Technical Specification](Twungeon_MVP_Technical_Specification.md) —
|
||||
defines the approved architecture, authoritative state, rules, contracts, and
|
||||
failure behavior.
|
||||
- [MVP Acceptance-Test and Build Checklist](Twungeon_MVP_Acceptance_Test_and_Build_Checklist.md)
|
||||
— sequences implementation and defines the evidence required for each success
|
||||
criterion.
|
||||
|
||||
The PRD is authoritative for product scope. The specification and checklist
|
||||
must be updated alongside any approved requirement change.
|
||||
|
||||
## Initial technical direction
|
||||
|
||||
The MVP is planned around TypeScript, RPGJS, Twurple, and a Twitch Extension,
|
||||
with Twungeon's game rules isolated from framework and service adapters where
|
||||
practical.
|
||||
|
||||
Public project and development-log records are maintained under `.labyricorn/`.
|
||||
|
||||
@@ -0,0 +1,740 @@
|
||||
# Twungeon MVP Acceptance-Test and Build Checklist
|
||||
|
||||
**Status:** Approved execution plan
|
||||
|
||||
**Date:** 2026-08-17
|
||||
|
||||
**Product baseline:** [Twungeon MVP PRD](Twungeon_MVP_PRD_Current.md)
|
||||
|
||||
**Technical baseline:** [Twungeon MVP Technical Specification](Twungeon_MVP_Technical_Specification.md)
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This document converts the approved Twungeon MVP product requirements and
|
||||
technical specification into a sequenced implementation plan with verification
|
||||
checkpoints. It is both the build checklist and the acceptance-test plan.
|
||||
|
||||
The checklist is complete as a planning artifact. Runtime items remain unchecked
|
||||
until implementation and evidence satisfy their stated exit criteria.
|
||||
|
||||
## 2. Execution Rules
|
||||
|
||||
- Work through build phases in order unless a dependency is explicitly mocked.
|
||||
- Keep the backend domain core authoritative for every game-state transition.
|
||||
- Do not move Twitch, RPGJS, browser, or transport logic into the domain package.
|
||||
- Add or update tests in the same change as the behavior they verify.
|
||||
- Do not mark a phase complete while any required test or review is failing.
|
||||
- Do not mark a live Twitch criterion complete using only a mock or unit test.
|
||||
- Record evidence for every acceptance-test ID.
|
||||
- Treat a PRD behavior change as a requirements change, not an implementation
|
||||
shortcut; update the PRD, specification, checklist, and affected tests
|
||||
together.
|
||||
- Preserve the MVP non-goals. New features require an explicit scope decision.
|
||||
|
||||
## 3. Status and Evidence Conventions
|
||||
|
||||
Checklist status:
|
||||
|
||||
- `[ ]` not started or not yet proven
|
||||
- `[x]` completed and supported by evidence
|
||||
- `[!]` blocked; include the blocker and owner beside the item
|
||||
|
||||
Acceptance evidence should be stored under:
|
||||
|
||||
```text
|
||||
evidence/acceptance/AT-###/
|
||||
```
|
||||
|
||||
Each acceptance evidence record must contain:
|
||||
|
||||
- build or commit identifier;
|
||||
- date and tester;
|
||||
- environment and relevant non-secret configuration;
|
||||
- exact procedure or automated test name;
|
||||
- expected and actual result;
|
||||
- pass/fail status;
|
||||
- relevant logs, screenshots, or video; and
|
||||
- linked defect IDs for any failure.
|
||||
|
||||
Secrets, full authentication payloads, and private viewer information must not
|
||||
be included in evidence.
|
||||
|
||||
## 4. Standard Quality Gates
|
||||
|
||||
Project scaffolding must expose equivalent commands for these gates:
|
||||
|
||||
```text
|
||||
npm run lint
|
||||
npm run typecheck
|
||||
npm test
|
||||
npm run test:integration
|
||||
npm run build
|
||||
```
|
||||
|
||||
Live Twitch and first-time-viewer tests are separate manual gates. Exact command
|
||||
names may change with the selected workspace tooling, but the capabilities may
|
||||
not be removed.
|
||||
|
||||
Every implementation phase closes with:
|
||||
|
||||
- [ ] lint passes;
|
||||
- [ ] type checking passes;
|
||||
- [ ] affected unit tests pass;
|
||||
- [ ] affected integration tests pass;
|
||||
- [ ] production build passes;
|
||||
- [ ] no secrets or generated credentials appear in the diff;
|
||||
- [ ] documentation matches implemented behavior; and
|
||||
- [ ] evidence is recorded for any acceptance criterion claimed complete.
|
||||
|
||||
## 5. Build Sequence
|
||||
|
||||
### Phase 0: Planning baseline
|
||||
|
||||
**Goal:** Establish the approved source documents and prevent scope drift.
|
||||
|
||||
- [x] Record the current MVP behavior and 33 success criteria in the PRD.
|
||||
- [x] Approve the technical specification as the implementation baseline.
|
||||
- [x] Resolve tile occupancy, attack range, command ordering, timer-boundary,
|
||||
restart, resurrection, presentation, and authority decisions.
|
||||
- [x] Create this traceable acceptance-test and build checklist.
|
||||
- [ ] Confirm the repository package manager and TypeScript workspace tooling.
|
||||
- [ ] Confirm access to a Twitch development channel, developer application,
|
||||
Extension configuration, and test viewer identities.
|
||||
- [ ] Select a configurable Bits resurrection price for live testing.
|
||||
- [ ] Record implementation-time Twitch/Twurple versions and verify their exact
|
||||
scopes, event types, authentication requirements, and transport setup against
|
||||
official documentation.
|
||||
|
||||
**Checkpoint P0:** The team can identify the PRD, specification, checklist, open
|
||||
integration configuration, and the rule for changing each baseline.
|
||||
|
||||
### Phase 1: Repository and process scaffold
|
||||
|
||||
**Goal:** Produce a clean, repeatable build with safe configuration boundaries.
|
||||
|
||||
- [ ] Create the workspace structure described in specification section 18.
|
||||
- [ ] Configure TypeScript, linting, formatting, unit tests, integration tests,
|
||||
and production builds.
|
||||
- [ ] Create backend, Extension, stream-view, domain, contracts,
|
||||
dungeon-generator, Twitch-adapter, RPGJS-adapter, and shared-UI boundaries.
|
||||
- [ ] Enforce dependency direction so the domain package cannot import adapter
|
||||
or framework packages.
|
||||
- [ ] Implement typed configuration loading and startup validation.
|
||||
- [ ] Add `.env.example` containing variable names and safe descriptions only.
|
||||
- [ ] Ensure real environment and credential files are ignored.
|
||||
- [ ] Add `GET /health` with startup/readiness reporting that exposes no secrets.
|
||||
- [ ] Draft installation and startup documentation as soon as commands exist.
|
||||
- [ ] Verify a clean checkout can install dependencies, type-check, test, and
|
||||
build without undocumented local files.
|
||||
|
||||
**Checkpoint P1:** Standard quality gates run from a clean checkout, missing
|
||||
configuration fails clearly, and no secret is present in source or client
|
||||
artifacts.
|
||||
|
||||
### Phase 2: Shared contracts and authoritative domain foundation
|
||||
|
||||
**Goal:** Establish deterministic, framework-independent state transitions.
|
||||
|
||||
- [ ] Define validated IDs, positions, commands, command envelopes, snapshots,
|
||||
domain events, rejection reasons, and Twitch message contracts.
|
||||
- [ ] Implement RunState, FloorState, PhaseState, PlayerState, GoblinState, and
|
||||
ActionLogEntry invariants from specification section 6.
|
||||
- [ ] Implement serialized command processing and atomic state commits.
|
||||
- [ ] Implement request idempotency and stale run/floor/phase rejection.
|
||||
- [ ] Inject monotonic clock, scheduler, ID generator, and random provider.
|
||||
- [ ] Generate ordered structured action-log entries only from domain events.
|
||||
- [ ] Add invariant tests that reject invalid HP, AP, Guard, identity, phase,
|
||||
entity, and sequence states.
|
||||
- [ ] Add concurrency tests proving two commands cannot spend the same AP or
|
||||
apply after a floor transition.
|
||||
|
||||
**Checkpoint P2:** The domain package can process deterministic commands and
|
||||
events without importing Twitch, RPGJS, HTTP, WebSocket, or browser code.
|
||||
|
||||
### Phase 3: Dungeon generation and read-only rendering
|
||||
|
||||
**Goal:** Repeatedly generate and display valid two-room floors.
|
||||
|
||||
- [ ] Implement seeded spawn-room and exit-room generation.
|
||||
- [ ] Implement varied room sizes, positions, and corridor shapes.
|
||||
- [ ] Place exactly one exit and one valid Goblin guard position.
|
||||
- [ ] Validate orthogonal connectivity from spawn to exit.
|
||||
- [ ] Bound invalid-generation retries and expose terminal generation failure.
|
||||
- [ ] Test same-seed determinism and multi-seed variation.
|
||||
- [ ] Test hundreds of generated seeds for required entities and connectivity.
|
||||
- [ ] Implement the broadcast-mode three-section layout.
|
||||
- [ ] Render players, Goblin, walls, paths, exit, shared status, and action log
|
||||
with temporary but distinguishable visuals.
|
||||
- [ ] Render the exact dormant banner text.
|
||||
|
||||
**Checkpoint P3:** A local read-only stream view can cycle through many valid,
|
||||
visibly varied floors without a Twitch connection.
|
||||
|
||||
### Phase 4: Player actions, phases, combat, and AutoGuard
|
||||
|
||||
**Goal:** Complete the local turn-based player/enemy loop.
|
||||
|
||||
- [ ] Implement dormant, Player Phase, Enemy Phase, and transition states.
|
||||
- [ ] Start Player Phase with 2 AP and zero Guard for each living participant.
|
||||
- [ ] Implement 25 seconds per living player with a 120-second cap.
|
||||
- [ ] End Player Phase early when its initial eligible set is finished or dead.
|
||||
- [ ] Decide deadline acceptance using gateway arrival before the monotonic
|
||||
deadline; reject arrivals at or after the deadline.
|
||||
- [ ] Implement orthogonal movement, wall/Goblin blocking, shared player tiles,
|
||||
and exit entry.
|
||||
- [ ] Implement adjacent selected-target player attacks with 65% hit chance and
|
||||
1 damage.
|
||||
- [ ] Implement self-heal to 3 HP, once per floor, for 1 AP.
|
||||
- [ ] Implement pass as exactly 1 AP.
|
||||
- [ ] Reject invalid commands without consuming AP.
|
||||
- [ ] Convert remaining AP to Guard when Player Phase ends.
|
||||
- [ ] Block one successful hit per Guard; do not consume Guard on misses.
|
||||
- [ ] Reset Guard at the next Player Phase.
|
||||
- [ ] Emit every required movement, combat, heal, Guard, and phase log event.
|
||||
|
||||
**Checkpoint P4:** Local deterministic tests can run complete rounds, including
|
||||
early completion, expiry, AFK AutoGuard, hits, misses, healing, and rejection.
|
||||
|
||||
### Phase 5: Goblin Guard state machine
|
||||
|
||||
**Goal:** Implement the complete one-enemy behavior without adding advanced AI.
|
||||
|
||||
- [ ] Spawn one passive Goblin with 2 HP at its guard position.
|
||||
- [ ] Aggro on a valid attack whether it hits or misses.
|
||||
- [ ] Retain the original attacker as target while that player lives.
|
||||
- [ ] Implement two Enemy Phase AP for move and attack combinations.
|
||||
- [ ] Implement 50% hit chance and 1 damage.
|
||||
- [ ] Implement deterministic shortest-path pursuit with the approved tie order.
|
||||
- [ ] On target death, clear the target and return toward guard position.
|
||||
- [ ] Prevent attacks while returning and restore passive guarding on arrival.
|
||||
- [ ] Remove blocking and actions when the Goblin dies.
|
||||
- [ ] Allow floor completion while the Goblin remains alive.
|
||||
- [ ] Log aggro, movement/return where useful, attacks, hits, misses, damage,
|
||||
Guard blocks, and death.
|
||||
|
||||
**Checkpoint P5:** Automated scenarios cover guarding, aggro, pursuit, attacks,
|
||||
target death, return, death, and escape with the Goblin alive.
|
||||
|
||||
### Phase 6: Player lifecycle, floor lifecycle, and run lifecycle
|
||||
|
||||
**Goal:** Complete the local gameplay loop before adding live Twitch input.
|
||||
|
||||
- [ ] Create one player record per stable synthetic Twitch user ID.
|
||||
- [ ] Prevent duplicate characters and same-floor death bypass.
|
||||
- [ ] Implement full death state, control disablement, and death markers.
|
||||
- [ ] Implement late spawn with 0 AP until the next Player Phase.
|
||||
- [ ] Implement resurrection at spawn with 3 HP, unchanged heal availability,
|
||||
and 0 AP until the next Player Phase.
|
||||
- [ ] Advance immediately when a living player enters the exit.
|
||||
- [ ] Reject queued commands for the previous floor.
|
||||
- [ ] Generate the next floor and Goblin.
|
||||
- [ ] Revive, heal, reposition, and refresh self-heal for all participants on
|
||||
floor advancement.
|
||||
- [ ] Reset to a new Floor 1 run immediately after the last participant dies.
|
||||
- [ ] Distinguish zero participants from a total-party wipe.
|
||||
- [ ] Preserve character identity and state across simulated client reconnects.
|
||||
- [ ] Verify expected new-run behavior after a simulated backend restart.
|
||||
- [ ] Run a deterministic multi-floor soak test.
|
||||
|
||||
**Checkpoint P6:** A local driver can repeat the entire gameplay loop through
|
||||
spawn, action, death, resurrection or advancement, new floors, and wipe reset.
|
||||
|
||||
### Phase 7: Backend API, state stream, and UIs
|
||||
|
||||
**Goal:** Make the authoritative local game usable through production-shaped
|
||||
transport and presentation boundaries.
|
||||
|
||||
- [ ] Implement Extension session establishment without character creation.
|
||||
- [ ] Implement authenticated command submission with stable rejection reasons.
|
||||
- [ ] Implement read-only and personalized WebSocket connections.
|
||||
- [ ] Send a complete snapshot on connection and ordered updates afterward.
|
||||
- [ ] Detect sequence gaps and replace client state with a fresh snapshot.
|
||||
- [ ] Reconnect without creating a player or replaying commands.
|
||||
- [ ] Implement broadcast and Extension modes from shared UI components.
|
||||
- [ ] Implement Up, Down, Left, Right, Attack, target selection, self-heal, and
|
||||
pass controls.
|
||||
- [ ] Display personalized HP, AP, Guard, heal, life, phase, binding, and disabled
|
||||
reason state.
|
||||
- [ ] Keep the three-section broadcast layout and chronological log readable.
|
||||
- [ ] Verify two synthetic authenticated clients independently control two
|
||||
characters in one dungeon.
|
||||
|
||||
**Checkpoint P7:** Two local clients can reconnect, receive ordered state, issue
|
||||
independent controls, and observe the same authoritative dungeon and log.
|
||||
|
||||
### Phase 8: Twitch chat, follower eligibility, and identity binding
|
||||
|
||||
**Goal:** Replace synthetic identities with verified Twitch viewer identities.
|
||||
|
||||
- [ ] Configure Twurple through external environment values.
|
||||
- [ ] Connect to the configured broadcaster/channel and expose connection state.
|
||||
- [ ] Receive and normalize chat activity required for `!spawn`.
|
||||
- [ ] Extract stable Twitch user ID rather than trusting display name.
|
||||
- [ ] Verify follower eligibility against the configured broadcaster.
|
||||
- [ ] Accept eligible `!spawn`; explain follower, duplicate, or death rejection.
|
||||
- [ ] Verify the Twitch Extension credential server-side.
|
||||
- [ ] Bind Extension controls only when its stable user ID equals the chat-spawn
|
||||
owner ID.
|
||||
- [ ] Reject unauthenticated, opaque, mismatched, and cross-player controls.
|
||||
- [ ] Reconnect Twitch integrations with bounded backoff and event deduplication.
|
||||
- [ ] Fail closed for new spawn/binding when Twitch verification is unavailable.
|
||||
- [ ] Test two real Twitch viewers with distinct characters.
|
||||
|
||||
**Checkpoint P8:** A follower can spawn and control only their own character;
|
||||
non-followers and identity mismatches cannot acquire control.
|
||||
|
||||
### Phase 9: Bits resurrection
|
||||
|
||||
**Goal:** Complete the Twitch-backed death recovery branch.
|
||||
|
||||
- [ ] Configure the approved positive Bits price outside domain code.
|
||||
- [ ] Subscribe to and normalize the selected Twitch Bits event.
|
||||
- [ ] Deduplicate by stable external event ID.
|
||||
- [ ] Map the event's stable Twitch user ID to the correct dead character.
|
||||
- [ ] Apply resurrection only when the configured amount/rule is satisfied.
|
||||
- [ ] Reject duplicate, anonymous, insufficient, living-user, and unknown-user
|
||||
events without mutating game state.
|
||||
- [ ] Confirm resurrection position, HP, AP timing, and heal preservation.
|
||||
- [ ] Log a successful resurrection and safe diagnostics for rejection.
|
||||
|
||||
**Checkpoint P9:** A real Bits event resurrects exactly the intended dead player
|
||||
once, without permitting cross-user or duplicate resurrection.
|
||||
|
||||
### Phase 10: Operator documentation and acceptance campaign
|
||||
|
||||
**Goal:** Prove a clean checkout and real viewers can complete the MVP loop
|
||||
without undocumented developer intervention.
|
||||
|
||||
- [ ] Complete `docs/twitch-setup.md` for every topic in PRD section 20.
|
||||
- [ ] Complete `docs/testing.md` for local, integration, live-channel, and
|
||||
troubleshooting verification.
|
||||
- [ ] Verify all required software, dependencies, credentials, identifiers,
|
||||
scopes, environment values, URLs, HTTPS/public endpoints, and startup order.
|
||||
- [ ] Document safe secret separation and rotation.
|
||||
- [ ] Document event-flow verification and common authentication, EventSub,
|
||||
Extension, identity-binding, follower-check, and Bits failures.
|
||||
- [ ] Have a second operator connect a clean checkout using only documentation.
|
||||
- [ ] Run all automated quality gates from that clean checkout.
|
||||
- [ ] Execute AT-001 through AT-030 and capture evidence.
|
||||
- [ ] Run the first-time-viewer usability session for AT-031.
|
||||
- [ ] Run the documentation troubleshooting review for AT-032.
|
||||
- [ ] Conduct the real-viewer concept-validation session for AT-033.
|
||||
- [ ] Triage failures; fix or explicitly reject them before MVP acceptance.
|
||||
|
||||
**Checkpoint P10:** Every PRD criterion has passing evidence, known failures are
|
||||
resolved, and a real viewer can complete the loop without developer assistance.
|
||||
|
||||
## 6. Acceptance-Test Matrix
|
||||
|
||||
### AT-001 — Clean installation
|
||||
|
||||
**PRD criterion:** 1
|
||||
|
||||
- [ ] From a clean checkout on a supported machine, follow only repository
|
||||
documentation to install dependencies and start all required components.
|
||||
- [ ] Confirm no undocumented global tool, local file, or developer knowledge is
|
||||
needed.
|
||||
|
||||
**Level:** Clean-environment manual test plus build automation
|
||||
**Pass evidence:** Full command transcript, environment description, health
|
||||
response, and screenshots of running backend, Extension, and stream view.
|
||||
|
||||
### AT-002 — External configuration and secret safety
|
||||
|
||||
**PRD criterion:** 2
|
||||
|
||||
- [ ] Run secret scanning and inspect built client artifacts.
|
||||
- [ ] Confirm credentials, identifiers, and environment-specific URLs are
|
||||
externally configured and no secret is hard-coded or returned to clients.
|
||||
|
||||
**Level:** Automated scan plus review
|
||||
**Pass evidence:** Scan output, configuration test results, and reviewer signoff.
|
||||
|
||||
### AT-003 — Documented channel connection
|
||||
|
||||
**PRD criterion:** 3
|
||||
|
||||
- [ ] Have a second operator configure a Twitch channel from a clean checkout
|
||||
using only `docs/twitch-setup.md`.
|
||||
- [ ] Confirm application, Extension, authentication, event transport, URLs, and
|
||||
broadcaster identifiers are correct.
|
||||
|
||||
**Level:** Independent operator test
|
||||
**Pass evidence:** Operator checklist, redacted configuration inventory, and
|
||||
successful connection logs.
|
||||
|
||||
### AT-004 — Required Twitch events and chat
|
||||
|
||||
**PRD criterion:** 4
|
||||
|
||||
- [ ] Generate the live chat and Twitch events used by the MVP.
|
||||
- [ ] Confirm Twungeon receives each once, normalizes it, and reports connection
|
||||
health without exposing credentials.
|
||||
|
||||
**Level:** Live integration
|
||||
**Pass evidence:** Correlated redacted Twitch-adapter and backend logs.
|
||||
|
||||
### AT-005 — Extension-to-backend communication
|
||||
|
||||
**PRD criterion:** 5
|
||||
|
||||
- [ ] Load the configured Extension, establish an authenticated session, receive
|
||||
a snapshot, submit a command, and observe an ordered result.
|
||||
|
||||
**Level:** Live integration
|
||||
**Pass evidence:** Browser capture and correlated gateway/backend logs.
|
||||
|
||||
### AT-006 — Three-section presentation
|
||||
|
||||
**PRD criterion:** 6
|
||||
|
||||
- [ ] Confirm the stream view contains a compact upper-left control/status area,
|
||||
the largest upper-right game area, and a full-width bottom action log.
|
||||
- [ ] Confirm required entities and state are understandable with temporary art.
|
||||
|
||||
**Level:** Visual review
|
||||
**Pass evidence:** Representative stream screenshot and reviewer signoff.
|
||||
|
||||
### AT-007 — Dormant behavior
|
||||
|
||||
**PRD criterion:** 7
|
||||
|
||||
- [ ] Start with zero participants and wait longer than a maximum Player Phase.
|
||||
- [ ] Confirm the floor remains loaded, no timer or Enemy Phase runs, the Goblin
|
||||
does not act, and the exact `Type !spawn to spawn in the Twungeon!` banner is
|
||||
shown.
|
||||
|
||||
**Level:** Automated domain/integration plus visual review
|
||||
**Pass evidence:** State assertions, elapsed-time logs, and screenshot.
|
||||
|
||||
### AT-008 — Follower spawn
|
||||
|
||||
**PRD criterion:** 8
|
||||
|
||||
- [ ] As a verified follower with no character or same-floor death, issue
|
||||
`!spawn` and confirm one character appears in the current spawn room.
|
||||
|
||||
**Level:** Live integration
|
||||
**Pass evidence:** Chat capture, follower result, spawn event, and stream capture.
|
||||
|
||||
### AT-009 — Non-follower rejection
|
||||
|
||||
**PRD criterion:** 9
|
||||
|
||||
- [ ] As a verified non-follower, issue `!spawn` and confirm no character or
|
||||
identity binding is created.
|
||||
|
||||
**Level:** Live integration
|
||||
**Pass evidence:** Chat capture, rejection result, and unchanged snapshot.
|
||||
|
||||
### AT-010 — Duplicate spawn prevention
|
||||
|
||||
**PRD criterion:** 10
|
||||
|
||||
- [ ] Issue repeated and concurrent `!spawn` requests for one Twitch user.
|
||||
- [ ] Confirm exactly one character exists and duplicate events are harmless.
|
||||
|
||||
**Level:** Automated integration plus live spot check
|
||||
**Pass evidence:** Concurrency test output and player-state snapshot.
|
||||
|
||||
### AT-011 — Chat-to-Extension identity binding
|
||||
|
||||
**PRD criterion:** 11
|
||||
|
||||
- [ ] Spawn through chat, authenticate the same viewer in the Extension, and
|
||||
confirm both resolve to the same stable Twitch user ID before controls enable.
|
||||
|
||||
**Level:** Live integration
|
||||
**Pass evidence:** Redacted identity-correlation logs and enabled controller.
|
||||
|
||||
### AT-012 — Cross-player control rejection
|
||||
|
||||
**PRD criterion:** 12
|
||||
|
||||
- [ ] Attempt to control viewer A's character from viewer B's authenticated
|
||||
Extension and through client-tampered ownership fields.
|
||||
- [ ] Confirm every attempt is rejected without state change or AP loss.
|
||||
|
||||
**Level:** Automated security integration plus live test
|
||||
**Pass evidence:** Rejection responses, unchanged state, and audit logs.
|
||||
|
||||
### AT-013 — Multiple independent viewers
|
||||
|
||||
**PRD criterion:** 13
|
||||
|
||||
- [ ] Spawn at least two verified viewers and have each issue actions through
|
||||
their own Extension during the same Player Phase.
|
||||
|
||||
**Level:** Live multi-viewer integration
|
||||
**Pass evidence:** Stream recording, ordered commands, and per-player state.
|
||||
|
||||
### AT-014 — Reliable Extension commands
|
||||
|
||||
**PRD criterion:** 14
|
||||
|
||||
- [ ] Exercise Up, Down, Left, Right, Attack, target selection, self-heal, and
|
||||
pass, including valid, invalid, duplicate, and stale requests.
|
||||
- [ ] Confirm one authoritative result per request and correct UI feedback.
|
||||
|
||||
**Level:** Automated E2E plus live spot check
|
||||
**Pass evidence:** Command suite output and controller recording.
|
||||
|
||||
### AT-015 — Phase cycle
|
||||
|
||||
**PRD criterion:** 15
|
||||
|
||||
- [ ] Run repeated Player Phase and Enemy Phase cycles.
|
||||
- [ ] Confirm players always receive initiative and Goblin actions occur only in
|
||||
Enemy Phase.
|
||||
|
||||
**Level:** Automated domain/integration
|
||||
**Pass evidence:** State-transition assertions and ordered event log.
|
||||
|
||||
### AT-016 — Scaled timer and cap
|
||||
|
||||
**PRD criterion:** 16
|
||||
|
||||
- [ ] Verify durations of 25, 50, 75, 100, and 120 seconds for one through five
|
||||
living players and 120 seconds for more than five.
|
||||
|
||||
**Level:** Automated fake-clock domain test plus one live timing check
|
||||
**Pass evidence:** Parameterized test output and live timer recording.
|
||||
|
||||
### AT-017 — Early Player Phase completion
|
||||
|
||||
**PRD criterion:** 17
|
||||
|
||||
- [ ] Have every initially eligible living player spend/pass all AP before the
|
||||
deadline and confirm Enemy Phase begins immediately.
|
||||
- [ ] Confirm a late spawn or resurrection does not extend the completion set.
|
||||
|
||||
**Level:** Automated domain/integration
|
||||
**Pass evidence:** Fake-clock transition assertions and event sequence.
|
||||
|
||||
### AT-018 — AP, Guard, combat, heal, HP, and death
|
||||
|
||||
**PRD criterion:** 18
|
||||
|
||||
- [ ] Exercise every valid AP combination, valid and invalid movement, player
|
||||
and Goblin hits/misses, Guard conversion/blocks, heal use/refresh, damage, and
|
||||
death.
|
||||
- [ ] Confirm invalid actions cost no AP and unused AP blocks only successful
|
||||
hits in the immediately following Enemy Phase.
|
||||
|
||||
**Level:** Automated deterministic domain suite
|
||||
**Pass evidence:** Branch/parameterized test output and state snapshots.
|
||||
|
||||
### AT-019 — Accurate action log
|
||||
|
||||
**PRD criterion:** 19
|
||||
|
||||
- [ ] Trigger every log category required by PRD section 4.2.
|
||||
- [ ] Confirm messages are chronological, accurate, backend-generated, restored
|
||||
after reconnect, and ordered by sequence.
|
||||
|
||||
**Level:** Automated integration plus visual review
|
||||
**Pass evidence:** Expected/actual event fixture and rendered log capture.
|
||||
|
||||
### AT-020 — Complete Goblin behavior
|
||||
|
||||
**PRD criterion:** 20
|
||||
|
||||
- [ ] Verify passive guarding, aggro on attack, target pursuit, move/attack AP,
|
||||
target death, deterministic return, resumed guarding, and remaining behind on
|
||||
transition.
|
||||
|
||||
**Level:** Automated deterministic domain suite
|
||||
**Pass evidence:** State-machine test output and representative replay.
|
||||
|
||||
### AT-021 — Repeated valid floor generation
|
||||
|
||||
**PRD criterion:** 21
|
||||
|
||||
- [ ] Generate a large deterministic seed sample.
|
||||
- [ ] Confirm every floor has exactly two rooms, a spawn, exit, guard, navigable
|
||||
connection, and variation in room or corridor properties.
|
||||
|
||||
**Level:** Automated property/invariant test
|
||||
**Pass evidence:** Seed count, invariant results, variation metrics, and samples.
|
||||
|
||||
### AT-022 — Escape without killing Goblin
|
||||
|
||||
**PRD criterion:** 22
|
||||
|
||||
- [ ] Aggro but do not kill the Goblin, move a living player onto the exit, and
|
||||
confirm immediate group advancement and a new Goblin on the next floor.
|
||||
|
||||
**Level:** Automated E2E plus live scenario
|
||||
**Pass evidence:** Before/after snapshots and stream recording.
|
||||
|
||||
### AT-023 — Dead players revive on advancement
|
||||
|
||||
**PRD criterion:** 23
|
||||
|
||||
- [ ] Kill one player, advance with another, and confirm the dead player returns
|
||||
at spawn with full HP and refreshed self-heal on the next floor.
|
||||
|
||||
**Level:** Automated E2E plus live scenario
|
||||
**Pass evidence:** Before/after player and floor state.
|
||||
|
||||
### AT-024 — Same-floor death cannot use `!spawn`
|
||||
|
||||
**PRD criterion:** 24
|
||||
|
||||
- [ ] Kill a player and repeat `!spawn` from that Twitch identity.
|
||||
- [ ] Confirm rejection, no duplicate/replacement, and unchanged death state.
|
||||
|
||||
**Level:** Automated integration plus live spot check
|
||||
**Pass evidence:** Rejection log and unchanged player record.
|
||||
|
||||
### AT-025 — Correct-player Bits resurrection
|
||||
|
||||
**PRD criterion:** 25
|
||||
|
||||
- [ ] With at least two players and one dead, send a qualifying live Bits event
|
||||
from the dead viewer.
|
||||
- [ ] Confirm exactly that character returns at spawn with full HP, preserved
|
||||
heal availability, and AP beginning next Player Phase.
|
||||
- [ ] Confirm duplicate, insufficient, living-user, and other-user events do not
|
||||
mutate the dead character.
|
||||
|
||||
**Level:** Automated integration plus live Bits event
|
||||
**Pass evidence:** Redacted event, deduplication log, and before/after state.
|
||||
|
||||
### AT-026 — Total-party wipe reset
|
||||
|
||||
**PRD criterion:** 26
|
||||
|
||||
- [ ] Kill the final living participant before exit.
|
||||
- [ ] Confirm an immediate new run on Floor 1, new floor/Goblin, every participant
|
||||
alive at full HP, refreshed heals, and one wipe/reset log sequence.
|
||||
|
||||
**Level:** Automated E2E plus live scenario
|
||||
**Pass evidence:** Run/floor transition and participant snapshots.
|
||||
|
||||
### AT-027 — Zero players differs from wipe
|
||||
|
||||
**PRD criterion:** 27
|
||||
|
||||
- [ ] Compare a new game with no participants to a run where the final player
|
||||
dies.
|
||||
- [ ] Confirm the first remains dormant on its current floor and the second
|
||||
resets immediately with participants restored.
|
||||
|
||||
**Level:** Automated domain/integration
|
||||
**Pass evidence:** Side-by-side state-transition assertions.
|
||||
|
||||
### AT-028 — Spawn into an empty current floor
|
||||
|
||||
**PRD criterion:** 28
|
||||
|
||||
- [ ] From dormant state, issue an eligible `!spawn` for a viewer without a
|
||||
current-floor death marker.
|
||||
- [ ] Confirm the existing floor is retained, banner disappears, player spawns,
|
||||
and a fresh Player Phase begins.
|
||||
|
||||
**Level:** Automated integration plus live scenario
|
||||
**Pass evidence:** Matching floor ID before/after, spawn event, and timer start.
|
||||
|
||||
### AT-029 — Refresh and interruption safety
|
||||
|
||||
**PRD criterion:** 29
|
||||
|
||||
- [ ] Refresh and temporarily disconnect Extension and view clients during
|
||||
Player Phase, Enemy Phase, death, and floor transition.
|
||||
- [ ] Confirm identity re-verification, one character, preserved critical state,
|
||||
full-snapshot recovery, and no replayed command.
|
||||
|
||||
**Level:** Automated fault-injection E2E plus live network test
|
||||
**Pass evidence:** Reconnect traces, sequence-gap recovery, and invariant results.
|
||||
|
||||
### AT-030 — Repeated complete-loop stability
|
||||
|
||||
**PRD criterion:** 30
|
||||
|
||||
- [ ] Run a multi-floor soak containing spawns, concurrent actions, expiry,
|
||||
combat, heal, death, resurrection, escape, advancement, and wipe reset.
|
||||
- [ ] Confirm integration, phase, player, Goblin, generator, and log invariants
|
||||
remain valid throughout.
|
||||
|
||||
**Level:** Automated soak plus live multi-floor session
|
||||
**Pass evidence:** Duration/floor count, event totals, invariant report, and video.
|
||||
|
||||
### AT-031 — First-time-viewer usability
|
||||
|
||||
**PRD criterion:** 31
|
||||
|
||||
- [ ] Recruit a real viewer who has not received private operating instructions.
|
||||
- [ ] Observe them watch, follow, use `!spawn`, discover controls, and perform a
|
||||
meaningful action without developer intervention.
|
||||
|
||||
**Level:** Moderated usability test
|
||||
**Pass evidence:** Consent-safe observation notes, completion result, and issues.
|
||||
|
||||
### AT-032 — Troubleshooting completeness
|
||||
|
||||
**PRD criterion:** 32
|
||||
|
||||
- [ ] Have a second operator use the documentation to diagnose controlled
|
||||
failures in authentication, Twitch events/transport, Extension loading,
|
||||
identity mismatch, configuration, follower verification, and Bits handling.
|
||||
- [ ] Confirm each failure has a discoverable symptom, diagnostic, and remedy.
|
||||
|
||||
**Level:** Independent documentation fault-injection review
|
||||
**Pass evidence:** Failure matrix, operator results, and documentation fixes.
|
||||
|
||||
### AT-033 — Concept-validation evidence
|
||||
|
||||
**PRD criterion:** 33
|
||||
|
||||
- [ ] Run the complete prototype with real viewers and collect structured
|
||||
observations about joining, control comprehension, waiting, cooperation,
|
||||
combat/escape choices, death/resurrection, and desire to continue.
|
||||
- [ ] Record what worked, what blocked play, and whether evidence supports
|
||||
expanding, revising, or stopping the concept.
|
||||
|
||||
**Level:** Real-viewer validation session
|
||||
**Pass evidence:** Consent-safe session summary, observed metrics, issues, and an
|
||||
explicit MVP learn/build decision. Passing means the prototype produced enough
|
||||
reliable evidence to make that decision; it does not require positive feedback.
|
||||
|
||||
## 7. Acceptance Campaign Order
|
||||
|
||||
Run acceptance in increasing order of cost and external dependency:
|
||||
|
||||
1. Domain unit and invariant tests.
|
||||
2. Generator property tests and deterministic multi-floor simulations.
|
||||
3. Backend/API integration tests with fake Twitch adapters.
|
||||
4. Browser E2E tests with synthetic authenticated identities.
|
||||
5. Clean-checkout and independent-operator setup tests.
|
||||
6. Twitch development-channel tests for chat, followers, Extension, and Bits.
|
||||
7. Multi-viewer complete-loop and soak sessions.
|
||||
8. First-time-viewer and concept-validation sessions.
|
||||
|
||||
A failure at an earlier layer should be corrected before repeating a more
|
||||
expensive live test that depends on it.
|
||||
|
||||
## 8. MVP Acceptance Decision
|
||||
|
||||
The MVP is accepted only when:
|
||||
|
||||
- [ ] AT-001 through AT-033 each have passing evidence;
|
||||
- [ ] all standard quality gates pass from a clean checkout;
|
||||
- [ ] no unresolved defect breaks identity ownership, authoritative state,
|
||||
required gameplay, setup reproducibility, or the complete viewer loop;
|
||||
- [ ] known non-blocking defects and accepted MVP exploits are documented;
|
||||
- [ ] setup and troubleshooting documentation passed independent review; and
|
||||
- [ ] the real-viewer validation summary records an explicit decision about
|
||||
whether and how to continue Twungeon.
|
||||
|
||||
## 9. Change Control
|
||||
|
||||
- PRD changes require a corresponding success-criteria and scope review.
|
||||
- Technical-rule changes require specification, contract, and test updates.
|
||||
- Checklist sequencing may change without altering requirements when the reason
|
||||
and dependency impact are recorded.
|
||||
- A checked item may be reopened when later evidence invalidates it.
|
||||
- Deferred and non-goal features must not be added merely to close an MVP test.
|
||||
|
||||
This checklist is the execution index. The PRD defines what must be proven, and
|
||||
the technical specification defines how the MVP is designed to prove it.
|
||||
@@ -1,5 +1,17 @@
|
||||
# Twungeon MVP Product Requirements Document
|
||||
|
||||
**Status:** Approved product baseline
|
||||
|
||||
**Baseline date:** 2026-08-17
|
||||
|
||||
**Implementation design:** [Twungeon MVP Technical Specification](Twungeon_MVP_Technical_Specification.md)
|
||||
|
||||
**Execution and verification:** [Twungeon MVP Acceptance-Test and Build Checklist](Twungeon_MVP_Acceptance_Test_and_Build_Checklist.md)
|
||||
|
||||
This document remains the source of truth for MVP product scope and acceptance.
|
||||
The companion specification defines implementation behavior, and the checklist
|
||||
tracks build sequencing and evidence without replacing these requirements.
|
||||
|
||||
## 1. Product Summary
|
||||
|
||||
**Twungeon** is a Twitch-controlled cooperative dungeon game in which viewers watch a shared game world on the Twitch stream and control their own characters through a Twitch Extension.
|
||||
|
||||
@@ -0,0 +1,992 @@
|
||||
# Twungeon MVP Technical Specification
|
||||
|
||||
**Status:** Approved implementation baseline
|
||||
|
||||
**Date:** 2026-08-17
|
||||
|
||||
**Approved:** 2026-08-17
|
||||
|
||||
**Product source of truth:** [Twungeon MVP PRD](Twungeon_MVP_PRD_Current.md)
|
||||
|
||||
**Execution and verification:** [Twungeon MVP Acceptance-Test and Build Checklist](Twungeon_MVP_Acceptance_Test_and_Build_Checklist.md)
|
||||
|
||||
**Intended implementation:** TypeScript, RPGJS, Twurple, and a Twitch Extension
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This approved document translates the Twungeon MVP Product Requirements
|
||||
Document into an implementation-ready system design. It defines component responsibilities,
|
||||
authoritative state, command handling, game-state transitions, spatial rules,
|
||||
integration boundaries, failure behavior, and verification requirements.
|
||||
|
||||
The PRD remains authoritative for product scope and acceptance. If this
|
||||
technical specification conflicts with the PRD, the PRD wins and this document
|
||||
must be corrected.
|
||||
|
||||
This specification intentionally does not add post-MVP features. Decisions made
|
||||
here resolve behavior that the PRD requires but does not define precisely enough
|
||||
for deterministic implementation.
|
||||
|
||||
## 2. Design Goals
|
||||
|
||||
The implementation must optimize for the following goals, in order:
|
||||
|
||||
1. Prove the complete Twitch viewer-to-gameplay loop with real viewers.
|
||||
2. Keep all game and identity decisions authoritative on the backend.
|
||||
3. Make command processing deterministic and testable.
|
||||
4. Keep Twungeon domain rules independent of RPGJS where practical.
|
||||
5. Make Twitch setup reproducible from a clean checkout.
|
||||
6. Prefer observable, recoverable failure over silent state corruption.
|
||||
7. Avoid systems outside the MVP, including long-term progression and
|
||||
production-grade persistence.
|
||||
|
||||
## 3. Scope and Constraints
|
||||
|
||||
### 3.1 Included
|
||||
|
||||
- Twitch chat `!spawn` handling and follower validation
|
||||
- Stable Twitch user identity binding between chat and Extension
|
||||
- One character per Twitch user
|
||||
- Twitch Extension controls
|
||||
- Shared stream-facing game view and chronological action log
|
||||
- Dormant, Player Phase, Enemy Phase, floor transition, and run reset states
|
||||
- AP, movement, combat, AutoGuard, self-heal, death, and resurrection
|
||||
- One Goblin Guard with guarding, pursuit, and return behavior
|
||||
- Varied, navigable two-room floors
|
||||
- Runtime reconnect and refresh handling
|
||||
- Clean-checkout Twitch integration documentation
|
||||
- Automated domain tests and live integration verification
|
||||
|
||||
### 3.2 Excluded
|
||||
|
||||
All non-goals in PRD section 22 remain excluded. In particular, this design does
|
||||
not introduce accounts beyond Twitch identity, inventory, progression, multiple
|
||||
classes or enemies, sophisticated AI, long-term persistence, or anti-exploit
|
||||
systems.
|
||||
|
||||
### 3.3 Runtime persistence boundary
|
||||
|
||||
The authoritative run exists in backend memory. Browser refreshes and temporary
|
||||
client disconnects do not remove or duplicate characters because clients
|
||||
reconnect to that backend state using the same Twitch user ID.
|
||||
|
||||
Surviving a backend process restart is not an MVP requirement. On an intentional
|
||||
or unintentional backend restart, Twungeon starts a new run on Floor 1 and logs
|
||||
the reset. Configuration and secrets persist outside the run state.
|
||||
|
||||
## 4. System Architecture
|
||||
|
||||
Twungeon uses one authoritative backend process for game decisions. Other
|
||||
components translate external input into authenticated commands or render
|
||||
backend state; they never modify game state directly.
|
||||
|
||||
```text
|
||||
Twitch chat ----> Twitch adapter -----------+
|
||||
|
|
||||
Twitch events --> Twitch adapter -----------+--> Authoritative backend
|
||||
| | |
|
||||
Extension ------> Extension API/WebSocket --+ | +--> Action log
|
||||
|
|
||||
+--> RPGJS adapter
|
||||
|
|
||||
+--> State snapshots
|
||||
|
|
||||
+------------------+----------------+
|
||||
| |
|
||||
Stream view Extension view
|
||||
```
|
||||
|
||||
### 4.1 Authoritative backend
|
||||
|
||||
The backend owns:
|
||||
|
||||
- the current run, floor, map, phase, and phase deadline;
|
||||
- all participating player records and character state;
|
||||
- Twitch identity bindings and follower eligibility results;
|
||||
- the Goblin state and AI decisions;
|
||||
- command ordering, validation, and idempotency;
|
||||
- random outcomes;
|
||||
- floor generation and transitions;
|
||||
- the canonical action log; and
|
||||
- state snapshots distributed to clients.
|
||||
|
||||
Only this component may accept or reject a command or perform a state
|
||||
transition.
|
||||
|
||||
### 4.2 Twitch adapter
|
||||
|
||||
The Twitch adapter uses Twurple to:
|
||||
|
||||
- receive chat messages needed for `!spawn`;
|
||||
- extract the stable Twitch user ID and display data from the chat event;
|
||||
- verify follower eligibility using the configured broadcaster identity;
|
||||
- receive the Bits event selected for resurrection;
|
||||
- normalize Twitch events into internal messages; and
|
||||
- reconnect without submitting the same external event more than once.
|
||||
|
||||
Version-specific Twitch scopes, event types, and transport configuration must
|
||||
be confirmed against the official Twitch and Twurple documentation during the
|
||||
integration task and recorded in the setup guide. They must not be guessed or
|
||||
hard-coded into domain logic.
|
||||
|
||||
### 4.3 Extension gateway
|
||||
|
||||
The Extension gateway:
|
||||
|
||||
- accepts Twitch-authenticated Extension sessions;
|
||||
- verifies the credential server-side;
|
||||
- resolves the credential to a stable Twitch user ID;
|
||||
- binds that ID to the same player created from chat;
|
||||
- accepts controller commands;
|
||||
- adds a server-issued connection and request identity;
|
||||
- forwards normalized commands to the game core; and
|
||||
- distributes personalized state and command results.
|
||||
|
||||
The Extension never supplies an authoritative player ID, AP value, position,
|
||||
target validity, damage result, or follower result.
|
||||
|
||||
### 4.4 Domain game core
|
||||
|
||||
The domain core is a framework-independent TypeScript module containing:
|
||||
|
||||
- state types;
|
||||
- command validation and reducers;
|
||||
- phase and floor state machines;
|
||||
- movement and combat rules;
|
||||
- Goblin AI;
|
||||
- dungeon generation contracts;
|
||||
- deterministic random interfaces; and
|
||||
- structured domain events.
|
||||
|
||||
It must not import RPGJS, Twurple, browser APIs, or Twitch SDK types.
|
||||
|
||||
### 4.5 RPGJS adapter
|
||||
|
||||
The RPGJS adapter maps domain state and events to prototype rendering and any
|
||||
engine-specific map representation. It must not decide whether movement,
|
||||
attacks, spawning, resurrection, or floor completion are valid.
|
||||
|
||||
### 4.6 Views
|
||||
|
||||
The presentation is implemented as one shared UI system with two modes:
|
||||
|
||||
- **Broadcast mode:** a read-only stream source that renders the three-section
|
||||
layout. Its upper-left area shows shared status and a visible controller
|
||||
legend, the upper-right area shows the dungeon, and the bottom area shows the
|
||||
running log.
|
||||
- **Extension mode:** an authenticated controller using the same visual
|
||||
language. It renders interactive controls and personalized player status,
|
||||
while consuming the same authoritative shared state.
|
||||
|
||||
This resolves the difference between a personalized controller and a shared
|
||||
broadcast: controls are visibly represented on the stream, but only an
|
||||
authenticated viewer's Extension controls are interactive.
|
||||
|
||||
## 5. Trust and Security Model
|
||||
|
||||
### 5.1 Stable identity
|
||||
|
||||
`twitchUserId` is the canonical player key. Display name, chat name, Extension
|
||||
connection ID, and browser storage are metadata only and cannot establish
|
||||
ownership.
|
||||
|
||||
### 5.2 Identity-binding sequence
|
||||
|
||||
1. The Twitch adapter receives `!spawn` with a stable chat user ID.
|
||||
2. The backend verifies that user follows the configured broadcaster.
|
||||
3. The backend creates or rejects the character using `twitchUserId`.
|
||||
4. The Extension sends its Twitch-authenticated credential to the gateway.
|
||||
5. The gateway verifies the credential and extracts its stable user ID.
|
||||
6. Controls become enabled only when that ID equals the character owner ID.
|
||||
7. Every later control command uses the verified server session; client-sent
|
||||
ownership fields are ignored.
|
||||
|
||||
### 5.3 Secrets and configuration
|
||||
|
||||
Secrets must be supplied through environment variables or ignored local secret
|
||||
files. They must never be committed, logged, returned to clients, included in
|
||||
URLs, or embedded in the Extension bundle.
|
||||
|
||||
Configuration validation must fail startup with a specific error when required
|
||||
values are missing or inconsistent. Logs may name a missing variable but must
|
||||
not print its value.
|
||||
|
||||
### 5.4 Input safety
|
||||
|
||||
All external messages are schema-validated. Invalid, unauthorized, stale, or
|
||||
duplicate messages are rejected without changing game state. Display names and
|
||||
other viewer text are escaped before rendering or logging.
|
||||
|
||||
## 6. Authoritative Data Model
|
||||
|
||||
The following types are conceptual contracts. Exact TypeScript syntax may vary,
|
||||
but the fields and ownership boundaries must remain equivalent.
|
||||
|
||||
### 6.1 Run state
|
||||
|
||||
```ts
|
||||
interface RunState {
|
||||
runId: string
|
||||
floorNumber: number
|
||||
floor: FloorState
|
||||
phase: PhaseState
|
||||
players: Map<TwitchUserId, PlayerState>
|
||||
goblin: GoblinState
|
||||
actionLog: ActionLogEntry[]
|
||||
nextEventSequence: number
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 Player state
|
||||
|
||||
```ts
|
||||
interface PlayerState {
|
||||
twitchUserId: string
|
||||
displayName: string
|
||||
followerVerified: boolean
|
||||
characterCreated: boolean
|
||||
extensionBound: boolean
|
||||
connectionState: 'connected' | 'disconnected'
|
||||
position: TilePosition
|
||||
hp: 0 | 1 | 2 | 3
|
||||
lifeState: 'alive' | 'dead'
|
||||
ap: 0 | 1 | 2
|
||||
guard: 0 | 1 | 2
|
||||
healAvailable: boolean
|
||||
participatingFloor: number
|
||||
diedOnFloor: number | null
|
||||
eligibleThisPhase: boolean
|
||||
}
|
||||
```
|
||||
|
||||
Connection state does not determine whether a living character participates in
|
||||
the turn. A disconnected living character remains in the dungeon, receives AP,
|
||||
and converts unused AP to AutoGuard.
|
||||
|
||||
### 6.3 Phase state
|
||||
|
||||
```ts
|
||||
type PhaseState =
|
||||
| { kind: 'dormant' }
|
||||
| {
|
||||
kind: 'player'
|
||||
phaseId: string
|
||||
startedAt: number
|
||||
deadlineAt: number
|
||||
initialEligiblePlayerIds: string[]
|
||||
}
|
||||
| { kind: 'enemy'; phaseId: string }
|
||||
| { kind: 'transition'; reason: 'floor-advance' | 'party-wipe' }
|
||||
```
|
||||
|
||||
The backend uses a monotonic clock for elapsed phase timing. Wall-clock values
|
||||
may be included for display but cannot determine acceptance ordering.
|
||||
|
||||
### 6.4 Floor state
|
||||
|
||||
```ts
|
||||
interface FloorState {
|
||||
floorId: string
|
||||
width: number
|
||||
height: number
|
||||
tiles: TileKind[][]
|
||||
spawnTiles: TilePosition[]
|
||||
exitPosition: TilePosition
|
||||
goblinGuardPosition: TilePosition
|
||||
generationSeed: string
|
||||
}
|
||||
|
||||
type TileKind = 'wall' | 'floor' | 'exit'
|
||||
```
|
||||
|
||||
### 6.5 Goblin state
|
||||
|
||||
```ts
|
||||
interface GoblinState {
|
||||
hp: 0 | 1 | 2
|
||||
position: TilePosition
|
||||
guardPosition: TilePosition
|
||||
mode: 'guarding' | 'pursuing' | 'returning' | 'dead'
|
||||
targetPlayerId: string | null
|
||||
}
|
||||
```
|
||||
|
||||
### 6.6 Structured action log
|
||||
|
||||
```ts
|
||||
interface ActionLogEntry {
|
||||
sequence: number
|
||||
runId: string
|
||||
floorNumber: number
|
||||
phaseId: string | null
|
||||
type: string
|
||||
actorId: string | null
|
||||
targetId: string | null
|
||||
message: string
|
||||
occurredAt: string
|
||||
}
|
||||
```
|
||||
|
||||
The backend creates log messages from domain events. Clients do not submit log
|
||||
text. Sequence numbers establish canonical ordering.
|
||||
|
||||
## 7. Spatial and Interaction Rules
|
||||
|
||||
These rules make movement and combat deterministic while preserving the PRD's
|
||||
simple cooperative intent.
|
||||
|
||||
### 7.1 Grid
|
||||
|
||||
- Movement is orthogonal: up, down, left, or right by one tile.
|
||||
- Diagonal movement and attacks are not permitted.
|
||||
- Walls are impassable.
|
||||
- The exit tile is traversable by living players.
|
||||
- A Goblin blocks player movement into its tile.
|
||||
- A player blocks Goblin movement into its tile.
|
||||
- Multiple players may share a tile. This prevents spawn-room crowding and
|
||||
cooperative path blocking from becoming an accidental MVP system.
|
||||
|
||||
### 7.2 Spawn placement
|
||||
|
||||
New characters spawn on the first spawn tile chosen by deterministic ordering.
|
||||
Players may share that tile. A late join never changes the current phase timer
|
||||
or the set of players required to finish the phase.
|
||||
|
||||
### 7.3 Attack range and targeting
|
||||
|
||||
- Player and Goblin attacks target an orthogonally adjacent tile.
|
||||
- A player attack requires a selected living Goblin adjacent to the player.
|
||||
- A Goblin attack requires its living pursuit target to be adjacent.
|
||||
- Invalid or stale targets do not consume AP.
|
||||
- A valid attack consumes AP even when the hit roll misses.
|
||||
- A successful unblocked hit applies exactly 1 HP of damage.
|
||||
|
||||
### 7.4 Exit behavior
|
||||
|
||||
When a living player successfully moves onto the exit tile, the move consumes
|
||||
1 AP and the floor transition starts immediately after that command resolves.
|
||||
No later queued command for the old floor is processed.
|
||||
|
||||
## 8. Command Model
|
||||
|
||||
### 8.1 Player commands
|
||||
|
||||
```ts
|
||||
type PlayerCommand =
|
||||
| { type: 'move'; direction: 'up' | 'down' | 'left' | 'right' }
|
||||
| { type: 'attack'; targetId: string }
|
||||
| { type: 'heal-self' }
|
||||
| { type: 'pass' }
|
||||
```
|
||||
|
||||
Each Extension request includes:
|
||||
|
||||
- a client-generated `requestId`;
|
||||
- the current `runId`, `floorId`, and `phaseId` last observed by the client; and
|
||||
- exactly one command payload.
|
||||
|
||||
The gateway supplies the authenticated `twitchUserId`; it is not accepted from
|
||||
the payload.
|
||||
|
||||
### 8.2 Command ordering
|
||||
|
||||
The backend processes accepted messages serially in arrival order. Each message
|
||||
is fully validated against the state produced by all earlier messages before it
|
||||
is applied.
|
||||
|
||||
This rule resolves simultaneous actions:
|
||||
|
||||
- the first accepted player to enter the exit ends the floor;
|
||||
- the first accepted attack may invalidate a later attack by killing the
|
||||
target;
|
||||
- duplicate request IDs return the original result without applying again; and
|
||||
- commands for an old run, floor, or phase are rejected as stale.
|
||||
|
||||
### 8.3 Player command validation
|
||||
|
||||
A command is accepted only when:
|
||||
|
||||
- the session is authenticated and bound to the character owner;
|
||||
- the character exists, is alive, and is eligible to act;
|
||||
- the current phase is Player Phase;
|
||||
- the command reaches the authoritative queue before the deadline;
|
||||
- the player has at least 1 AP;
|
||||
- the supplied run, floor, and phase IDs match current state; and
|
||||
- command-specific spatial or resource rules pass.
|
||||
|
||||
Rejected commands consume no AP and return a machine-readable reason plus a
|
||||
safe display message.
|
||||
|
||||
### 8.4 Pass semantics
|
||||
|
||||
Pass costs exactly 1 AP. A player with 2 AP who wants to finish immediately
|
||||
must pass twice. There is no separate zero-cost end-turn command in the MVP.
|
||||
|
||||
## 9. Turn and State Machines
|
||||
|
||||
### 9.1 Dormant state
|
||||
|
||||
The game starts with a generated Floor 1 and no participating characters.
|
||||
While no active character exists:
|
||||
|
||||
- phase is `dormant`;
|
||||
- no phase deadline exists;
|
||||
- no Enemy Phase can run;
|
||||
- the Goblin cannot act; and
|
||||
- the spawn banner is visible.
|
||||
|
||||
The first accepted `!spawn` creates a living character, removes the banner, and
|
||||
starts a fresh Player Phase.
|
||||
|
||||
The MVP has no voluntary leave or character-removal command. Temporary
|
||||
disconnects therefore do not create dormancy. A total-party death triggers a
|
||||
run reset rather than dormancy.
|
||||
|
||||
### 9.2 Starting Player Phase
|
||||
|
||||
For every living participant present when the phase starts:
|
||||
|
||||
1. set AP to 2;
|
||||
2. set Guard to 0;
|
||||
3. set `eligibleThisPhase` to true; and
|
||||
4. include the player in `initialEligiblePlayerIds`.
|
||||
|
||||
The duration is:
|
||||
|
||||
```text
|
||||
min(living-player-count * 25 seconds, 120 seconds)
|
||||
```
|
||||
|
||||
The count includes disconnected living characters, matching the PRD's AFK
|
||||
AutoGuard behavior.
|
||||
|
||||
Players who spawn or resurrect after the phase starts receive 0 AP, are not
|
||||
added to the phase completion set, and may act beginning with the next Player
|
||||
Phase.
|
||||
|
||||
### 9.3 Ending Player Phase
|
||||
|
||||
The phase ends when either:
|
||||
|
||||
- every player in the initial eligible set has 0 AP or is dead; or
|
||||
- the authoritative deadline is reached.
|
||||
|
||||
At the transition, each living player's remaining AP becomes Guard one-for-one,
|
||||
then AP becomes 0. Dead players receive no Guard.
|
||||
|
||||
Commands already waiting in the serialized backend queue are accepted only if
|
||||
the gateway recorded their arrival before the deadline. A command arriving at
|
||||
or after the deadline is rejected even if the phase-transition task has not yet
|
||||
run.
|
||||
|
||||
### 9.4 Enemy Phase
|
||||
|
||||
The living Goblin receives 2 AP and repeatedly selects one deterministic action
|
||||
until it has no AP or no valid action.
|
||||
|
||||
After the Goblin finishes, Guard is discarded and a new Player Phase begins,
|
||||
unless the floor advanced or the run reset during the Enemy Phase.
|
||||
|
||||
### 9.5 AutoGuard
|
||||
|
||||
When a Goblin attack hits:
|
||||
|
||||
1. if the target has Guard greater than 0, decrement Guard and apply no damage;
|
||||
2. otherwise, subtract 1 HP;
|
||||
3. if HP reaches 0, perform player death handling.
|
||||
|
||||
A miss never consumes Guard. Guard cannot carry into another round.
|
||||
|
||||
## 10. Player Lifecycle
|
||||
|
||||
### 10.1 `!spawn`
|
||||
|
||||
An accepted spawn requires:
|
||||
|
||||
- a stable Twitch chat user ID;
|
||||
- verified follower status;
|
||||
- no existing character for that ID; and
|
||||
- no death marker for that ID on the current floor.
|
||||
|
||||
The backend creates one character at full HP with heal available. If the game is
|
||||
already active, the player has 0 AP until the next Player Phase.
|
||||
|
||||
Repeated `!spawn` attempts for an existing character return an informative chat
|
||||
response or log result and never create another character.
|
||||
|
||||
### 10.2 Heal
|
||||
|
||||
A valid self-heal:
|
||||
|
||||
- costs 1 AP;
|
||||
- requires the player to be alive;
|
||||
- requires `healAvailable` to be true;
|
||||
- restores HP to 3 even if already full; and
|
||||
- sets `healAvailable` to false.
|
||||
|
||||
### 10.3 Death
|
||||
|
||||
When HP reaches 0:
|
||||
|
||||
- life state becomes dead;
|
||||
- AP and Guard become 0;
|
||||
- `diedOnFloor` becomes the current floor number;
|
||||
- controls are disabled; and
|
||||
- a death event is logged.
|
||||
|
||||
The dead character remains associated with the Twitch user ID and cannot be
|
||||
replaced with `!spawn`.
|
||||
|
||||
### 10.4 Bits resurrection
|
||||
|
||||
The Bits price is a required positive configuration value and may change
|
||||
without changing domain code. An accepted resurrection event must identify the
|
||||
same Twitch user ID as the dead character, satisfy the configured transaction
|
||||
rule, and have a unique external event ID.
|
||||
|
||||
Resurrection:
|
||||
|
||||
- restores the player to 3 HP;
|
||||
- places the player on the deterministic spawn tile;
|
||||
- clears the current-floor death marker;
|
||||
- preserves whether the floor heal was already used;
|
||||
- grants 0 AP during the current phase; and
|
||||
- enables action beginning with the next Player Phase.
|
||||
|
||||
Extra, duplicate, anonymous, insufficient, or non-dead-user events do not alter
|
||||
game state and must produce a diagnostic result without exposing secrets.
|
||||
|
||||
### 10.5 Refresh and reconnect
|
||||
|
||||
On Extension refresh or reconnection, the gateway re-verifies identity and
|
||||
returns the existing character and current personalized snapshot. It never
|
||||
creates a character from browser state. Multiple connections for the same user
|
||||
may display state, but all share one player command budget and idempotency
|
||||
history.
|
||||
|
||||
## 11. Goblin Guard Behavior
|
||||
|
||||
### 11.1 Guarding
|
||||
|
||||
The Goblin begins at its guard position in `guarding` mode. It spends no AP and
|
||||
does not attack until it is attacked by a player.
|
||||
|
||||
### 11.2 Aggro and pursuit
|
||||
|
||||
The first valid player attack changes the Goblin to `pursuing` and sets that
|
||||
attacker as its target, whether the attack hits or misses. Later attacks do not
|
||||
retarget it while the target lives.
|
||||
|
||||
During each Enemy Phase, the Goblin:
|
||||
|
||||
1. attacks its target if orthogonally adjacent;
|
||||
2. otherwise moves one tile along a shortest path to the target; and
|
||||
3. repeats until its 2 AP are spent or no path/action exists.
|
||||
|
||||
Shortest paths use breadth-first search. Equal choices use a fixed direction
|
||||
priority of up, left, right, then down so tests are deterministic.
|
||||
|
||||
### 11.3 Target death and return
|
||||
|
||||
If the pursued player dies, the Goblin enters `returning`, clears its target,
|
||||
and uses later Enemy Phases to take shortest-path movement toward its original
|
||||
guard position. It does not attack players while returning. On reaching the
|
||||
guard position, it becomes passive `guarding` again.
|
||||
|
||||
### 11.4 Goblin death
|
||||
|
||||
At 0 HP the Goblin becomes `dead`, is removed as a blocking entity, and takes no
|
||||
further actions. The exit remains usable whether the Goblin is alive or dead.
|
||||
|
||||
## 12. Floor Generation and Progression
|
||||
|
||||
### 12.1 Generator contract
|
||||
|
||||
For a supplied seed, the generator must return the same floor and guarantee:
|
||||
|
||||
- exactly one rectangular spawn room;
|
||||
- exactly one rectangular exit room that does not overlap the spawn room;
|
||||
- one exit tile in the exit room;
|
||||
- one Goblin guard position adjacent to or near the exit;
|
||||
- an orthogonally navigable floor path between a spawn tile and the exit; and
|
||||
- enclosing impassable walls.
|
||||
|
||||
Variation must affect room sizes, room positions, or connecting corridor shape
|
||||
across seeds. Generation retries with a derived seed when validation fails and
|
||||
fails startup/transition visibly after a bounded retry count rather than loading
|
||||
an invalid map.
|
||||
|
||||
### 12.2 Floor advancement
|
||||
|
||||
When a living player enters the exit:
|
||||
|
||||
1. enter transition state and reject remaining old-floor commands;
|
||||
2. increment the floor counter;
|
||||
3. generate and validate a new floor and Goblin;
|
||||
4. place every participating player on the new spawn tile;
|
||||
5. restore every player to 3 HP and alive;
|
||||
6. clear death markers, AP, and Guard;
|
||||
7. refresh every self-heal;
|
||||
8. log the new floor; and
|
||||
9. begin a fresh Player Phase.
|
||||
|
||||
The previous Goblin and map are discarded.
|
||||
|
||||
### 12.3 Total-party wipe
|
||||
|
||||
After any death resolution, if participating characters exist and none is
|
||||
alive, the backend immediately:
|
||||
|
||||
1. enters transition state;
|
||||
2. creates a new run ID;
|
||||
3. sets the floor counter to 1;
|
||||
4. generates a new starting floor and Goblin;
|
||||
5. restores all participating players alive at 3 HP;
|
||||
6. clears death markers, AP, and Guard;
|
||||
7. refreshes all self-heals;
|
||||
8. places all players at the spawn tile;
|
||||
9. logs the wipe and reset; and
|
||||
10. begins a fresh Player Phase.
|
||||
|
||||
Because the reset is immediate, a Bits event cannot interrupt a completed
|
||||
total-party wipe. Zero participating characters is explicitly not a wipe.
|
||||
|
||||
## 13. Randomness
|
||||
|
||||
All random behavior goes through an injected pseudo-random interface. The
|
||||
backend is the sole random authority.
|
||||
|
||||
Randomness is used for:
|
||||
|
||||
- player 65% attack hit rolls;
|
||||
- Goblin 50% attack hit rolls; and
|
||||
- procedural floor parameters.
|
||||
|
||||
Tests use fixed sequences or seeds. Production logs record the run/floor seed
|
||||
and outcome event, but clients never provide rolls or seeds used to resolve a
|
||||
command.
|
||||
|
||||
## 14. Backend Interfaces
|
||||
|
||||
Exact framework routing may change, but equivalent contracts are required.
|
||||
|
||||
### 14.1 Health
|
||||
|
||||
`GET /health`
|
||||
|
||||
Returns process readiness without credentials or game secrets. Readiness is
|
||||
false when required Twitch configuration or the game core failed to initialize.
|
||||
|
||||
### 14.2 Extension session
|
||||
|
||||
`POST /api/extension/session`
|
||||
|
||||
Accepts the Twitch Extension authentication credential, verifies it, and
|
||||
returns a short-lived Twungeon session plus personalized state. It does not
|
||||
create a character.
|
||||
|
||||
### 14.3 Commands
|
||||
|
||||
`POST /api/commands`
|
||||
|
||||
Accepts an authenticated player command envelope and returns:
|
||||
|
||||
```json
|
||||
{
|
||||
"requestId": "client-generated-id",
|
||||
"accepted": true,
|
||||
"eventSequence": 42,
|
||||
"reason": null
|
||||
}
|
||||
```
|
||||
|
||||
Rejected responses use a stable reason such as `UNAUTHENTICATED`,
|
||||
`IDENTITY_NOT_BOUND`, `CHARACTER_DEAD`, `WRONG_PHASE`, `STALE_PHASE`,
|
||||
`NO_AP`, `INVALID_TARGET`, `BLOCKED_TILE`, or `DUPLICATE`.
|
||||
|
||||
### 14.4 State stream
|
||||
|
||||
`GET /ws` upgrades to an authenticated WebSocket when personalized state is
|
||||
needed or a read-only broadcast connection otherwise. Messages include:
|
||||
|
||||
- complete snapshot on connection;
|
||||
- ordered state/event updates;
|
||||
- current server time and phase deadline;
|
||||
- action-log entries; and
|
||||
- explicit resynchronization after sequence gaps.
|
||||
|
||||
Clients must replace local state with a complete snapshot after reconnect or a
|
||||
sequence gap. UI animation state is local; game state is not.
|
||||
|
||||
### 14.5 Internal Twitch messages
|
||||
|
||||
Twitch events normalize into idempotent internal messages:
|
||||
|
||||
```ts
|
||||
type TwitchMessage =
|
||||
| {
|
||||
type: 'spawn-requested'
|
||||
externalEventId: string
|
||||
twitchUserId: string
|
||||
displayName: string
|
||||
broadcasterId: string
|
||||
}
|
||||
| {
|
||||
type: 'bits-resurrection-received'
|
||||
externalEventId: string
|
||||
twitchUserId: string
|
||||
amount: number
|
||||
}
|
||||
```
|
||||
|
||||
## 15. Presentation Requirements
|
||||
|
||||
### 15.1 Three-section layout
|
||||
|
||||
The default wide layout reserves:
|
||||
|
||||
- a compact upper-left control/status area;
|
||||
- the largest upper-right area for the map; and
|
||||
- a full-width bottom area for the action log.
|
||||
|
||||
Temporary shapes, colors, labels, and sprites are acceptable. Every required
|
||||
entity, wall, traversable path, and exit must remain distinguishable.
|
||||
|
||||
### 15.2 Player status
|
||||
|
||||
The personalized Extension status includes at least identity/binding status,
|
||||
HP, AP, Guard, heal availability, alive/dead status, current phase, and a clear
|
||||
disabled reason when controls are unavailable.
|
||||
|
||||
### 15.3 Action log
|
||||
|
||||
The view displays canonical entries by sequence, oldest to newest, with the
|
||||
latest entries visible. It must cover every event category required by PRD
|
||||
section 4.2. Reconnection restores recent history from the backend rather than
|
||||
starting an empty client-only log.
|
||||
|
||||
### 15.4 Dormant banner
|
||||
|
||||
When phase is dormant, both applicable views prominently display exactly:
|
||||
|
||||
`Type !spawn to spawn in the Twungeon!`
|
||||
|
||||
## 16. Failure and Recovery Behavior
|
||||
|
||||
### 16.1 Twitch unavailable
|
||||
|
||||
- Existing authenticated gameplay may continue if the backend remains healthy.
|
||||
- New spawn, new identity binding, and Bits events fail closed when they cannot
|
||||
be verified.
|
||||
- The operator view and logs identify the unavailable integration.
|
||||
- Reconnect uses bounded exponential backoff and does not duplicate events.
|
||||
|
||||
### 16.2 Extension disconnected
|
||||
|
||||
The character remains participating. The current phase continues, unused AP
|
||||
becomes Guard, and reconnection restores authoritative state.
|
||||
|
||||
### 16.3 View disconnected
|
||||
|
||||
Game simulation continues. The view requests a full snapshot on return and does
|
||||
not replay commands.
|
||||
|
||||
### 16.4 Invalid floor
|
||||
|
||||
An invalid generated floor is never activated. Generation retries a bounded
|
||||
number of times. If all retries fail, phase progression stops with an operator-
|
||||
visible error rather than corrupting the active run.
|
||||
|
||||
### 16.5 Unexpected domain exception
|
||||
|
||||
The command is not partially applied. Command handling must compute and commit
|
||||
one atomic state transition. The error is correlated with request, run, floor,
|
||||
phase, and event sequence identifiers without logging secrets.
|
||||
|
||||
## 17. Observability
|
||||
|
||||
Structured operational logs must distinguish:
|
||||
|
||||
- Twitch connection and subscription state;
|
||||
- authentication and identity-binding results;
|
||||
- follower checks;
|
||||
- accepted and rejected spawn attempts;
|
||||
- accepted and rejected controller commands;
|
||||
- phase transitions and timer expiry;
|
||||
- Bits-event deduplication and resurrection results;
|
||||
- floor-generation seed and validation result;
|
||||
- reconnect and snapshot resynchronization; and
|
||||
- run reset or fatal errors.
|
||||
|
||||
Logs must use stable user IDs only where operationally required and must avoid
|
||||
credentials and full authentication payloads.
|
||||
|
||||
## 18. Proposed Source Layout
|
||||
|
||||
```text
|
||||
/
|
||||
|-- apps/
|
||||
| |-- backend/ # Process composition, APIs, WebSocket, scheduler
|
||||
| |-- extension/ # Authenticated Twitch controller UI
|
||||
| `-- stream-view/ # Read-only broadcast layout
|
||||
|-- packages/
|
||||
| |-- domain/ # Framework-independent game state and rules
|
||||
| |-- dungeon-generator/ # Seeded two-room generation and validation
|
||||
| |-- twitch-adapter/ # Twurple chat, follower, and Bits integration
|
||||
| |-- rpgjs-adapter/ # Mapping between domain state and RPGJS
|
||||
| |-- contracts/ # Shared validated API/event schemas
|
||||
| `-- ui/ # Shared layout, status, controls, and log components
|
||||
|-- tests/
|
||||
| |-- domain/ # Deterministic rule and state-machine tests
|
||||
| |-- integration/ # Backend, adapters, APIs, reconnect, deduplication
|
||||
| `-- e2e/ # Multi-viewer and complete-loop scenarios
|
||||
|-- docs/
|
||||
| |-- twitch-setup.md # Clean-checkout Twitch setup and troubleshooting
|
||||
| `-- testing.md # Local and live-channel verification procedure
|
||||
|-- .env.example # Names and descriptions, never secret values
|
||||
|-- Twungeon_MVP_PRD_Current.md
|
||||
`-- Twungeon_MVP_Technical_Specification.md
|
||||
```
|
||||
|
||||
The exact monorepo tooling may be selected during project scaffolding. Component
|
||||
boundaries and dependency direction are mandatory even if folders are renamed.
|
||||
|
||||
## 19. Dependency Direction
|
||||
|
||||
Allowed dependency direction:
|
||||
|
||||
```text
|
||||
apps -> adapters/contracts -> domain
|
||||
UI apps -> contracts/UI components
|
||||
domain -> no framework or external-service package
|
||||
```
|
||||
|
||||
The domain package exposes commands, state, and events. Adapters translate
|
||||
between those contracts and RPGJS, Twurple, HTTP, WebSocket, or browser APIs.
|
||||
|
||||
## 20. Verification Strategy
|
||||
|
||||
### 20.1 Domain unit tests
|
||||
|
||||
Deterministic tests must cover:
|
||||
|
||||
- all accepted and rejected command conditions;
|
||||
- AP spending and early phase completion;
|
||||
- timer duration and 120-second cap;
|
||||
- deadline boundary behavior;
|
||||
- AutoGuard conversion, hit blocking, misses, and reset;
|
||||
- player and Goblin hit probabilities through injected rolls;
|
||||
- heal availability and floor refresh;
|
||||
- death, spawn lockout, resurrection, advancement, and wipe reset;
|
||||
- Goblin guarding, aggro on hit or miss, pursuit, return, and death;
|
||||
- exit entry with a living Goblin;
|
||||
- dormant versus total-party-wipe conditions;
|
||||
- serial ordering and stale/duplicate command handling; and
|
||||
- deterministic floor generation and connectivity validation.
|
||||
|
||||
### 20.2 Integration tests
|
||||
|
||||
Integration tests use test doubles before live Twitch testing and cover:
|
||||
|
||||
- chat event to follower check to spawn;
|
||||
- non-follower rejection;
|
||||
- chat-to-Extension identity match and mismatch;
|
||||
- two authenticated viewers controlling separate characters;
|
||||
- refresh/reconnect without duplication;
|
||||
- Twitch event and command deduplication;
|
||||
- Bits event mapped to the correct dead character;
|
||||
- backend snapshots, ordered events, and sequence-gap recovery; and
|
||||
- RPGJS rendering updates without domain authority leakage.
|
||||
|
||||
### 20.3 End-to-end scenarios
|
||||
|
||||
At minimum, the live test plan must demonstrate:
|
||||
|
||||
1. clean setup and startup from repository documentation;
|
||||
2. dormant banner before any player joins;
|
||||
3. follower spawn and non-follower rejection;
|
||||
4. matching Extension control and mismatched identity rejection;
|
||||
5. two or more simultaneous viewer characters;
|
||||
6. movement, two attacks, heal, pass, timer expiry, and AutoGuard;
|
||||
7. Goblin aggro, pursuit, attack, target death, and return;
|
||||
8. Bits resurrection of the correct dead viewer;
|
||||
9. floor escape with the Goblin alive and dead-player revival;
|
||||
10. total-party wipe and Floor 1 reset;
|
||||
11. refresh and temporary disconnect recovery; and
|
||||
12. repetition across multiple generated floors.
|
||||
|
||||
### 20.4 PRD success-criteria traceability
|
||||
|
||||
| PRD criteria | Primary verification |
|
||||
|---|---|
|
||||
| 1-6 | Clean-checkout, configuration, Twitch event, Extension, and layout E2E tests |
|
||||
| 7-13 | Dormancy, spawn eligibility, duplicate prevention, and identity integration tests |
|
||||
| 14-19 | Controller, phase, timer, AP, combat, heal, death, Guard, and log tests |
|
||||
| 20-22 | Goblin AI, generator validation, and live-Goblin escape tests |
|
||||
| 23-29 | Floor revival, death lockout, Bits, wipe, zero-player, late spawn, and reconnect tests |
|
||||
| 30-33 | Multi-floor soak test, first-time-viewer test, setup troubleshooting review, and viewer-feedback session |
|
||||
|
||||
The test implementation should reference individual PRD criterion numbers in
|
||||
test names or metadata so failures remain traceable to product acceptance.
|
||||
|
||||
## 21. Implementation Sequence
|
||||
|
||||
Implementation should proceed through vertical, independently verifiable
|
||||
slices:
|
||||
|
||||
1. Scaffold the repository, shared contracts, configuration validation, and
|
||||
framework-independent domain package.
|
||||
2. Implement the deterministic floor generator and static stream rendering.
|
||||
3. Implement player/Goblin state, commands, turn phases, timer, and action log
|
||||
using local test drivers.
|
||||
4. Implement death, resurrection messages, floor advancement, wipe reset,
|
||||
dormancy, reconnect, and idempotency.
|
||||
5. Add the RPGJS adapter without moving rules out of the domain package.
|
||||
6. Add Twurple chat and follower verification for `!spawn`.
|
||||
7. Add Extension authentication, identity binding, controller commands, and
|
||||
personalized state.
|
||||
8. Add the Twitch Bits adapter and configurable resurrection rule.
|
||||
9. Complete clean-checkout Twitch setup and troubleshooting documentation.
|
||||
10. Run automated, live-channel, multi-viewer, and repeated-floor acceptance
|
||||
tests against all 33 PRD criteria.
|
||||
|
||||
## 22. Decisions Deferred to Integration Configuration
|
||||
|
||||
The following are intentionally configurable or version-dependent and do not
|
||||
change the domain design:
|
||||
|
||||
- exact Bits resurrection price;
|
||||
- concrete Twitch developer application and Extension identifiers;
|
||||
- exact Twitch scopes, EventSub event names, and Twurple configuration required
|
||||
by the versions selected at implementation time;
|
||||
- callback, WebSocket, public endpoint, and HTTPS values for each environment;
|
||||
- UI art, typography, and final dimensions; and
|
||||
- retention limits for operational logs and the on-screen action-log window.
|
||||
|
||||
These values must be resolved and documented before live acceptance testing.
|
||||
|
||||
## 23. Definition of Ready for Implementation
|
||||
|
||||
Implementation may begin when:
|
||||
|
||||
- the PRD and this specification are accepted as the product and technical
|
||||
baselines;
|
||||
- the eight resolved behavior choices below are acknowledged;
|
||||
- the initial repository/tooling scaffold is selected;
|
||||
- a Twitch development channel and required developer access are available; and
|
||||
- secrets can be supplied outside source control.
|
||||
|
||||
Resolved behavior choices:
|
||||
|
||||
1. Players may share tiles; the Goblin and players may not share a tile.
|
||||
2. Movement and attacks are orthogonal, and attacks are adjacent-only.
|
||||
3. The backend serializes commands by authoritative arrival order.
|
||||
4. The arrival timestamp at the backend gateway decides timer-boundary commands.
|
||||
5. Run state survives client reconnects but not backend process restarts.
|
||||
6. Bits resurrection restores full HP at spawn and grants AP next Player Phase.
|
||||
7. Broadcast and Extension modes share presentation, but only the authenticated
|
||||
Extension is interactive.
|
||||
8. The backend domain core is the sole authority for every state transition.
|
||||
|
||||
Changes to these decisions must update this specification and any affected
|
||||
tests before or alongside implementation.
|
||||
Reference in New Issue
Block a user