Almaatla Claude Opus 5 commited on
Commit
d19cbc4
Β·
unverified Β·
1 Parent(s): 718b0cb

docs: record in the PRD what the evidence resolved

Browse files

Two risks close on measurement rather than argument: WebSockets on HF
Spaces (verified through the edge proxy, and the owner's own Space
already does it) and free-tier CPU for concurrent matches (measured p99
4.6-9.1ms per tick against a 50ms budget). Three replace them, all
platform-level, all confirmed.

Q2 is answered β€” start on free CPU Basic. Q1 hardens from a preference
into a blocker: a private Space returns 404 for the running app, so
nobody can play until it is public.

Adds an evidence-base index so each claim points at the dossier behind it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PzkfXsTz4hxPfuySb1GvyS

Files changed (2) hide show
  1. docs/PRD.md +36 -12
  2. docs/analysis/05-mcp-agent-play.md +1 -1
docs/PRD.md CHANGED
@@ -1,6 +1,6 @@
1
  # SpaceCities β€” Product Requirements Document
2
 
3
- **Status:** Draft v0.1 β€” pending review
4
  **Owner:** alma92350
5
  **Last updated:** 2026-08-30
6
  **Related:** [`docs/adr/`](adr/) (architecture decisions) Β· [`TASKS.md`](../TASKS.md) (delivery tracking)
@@ -233,24 +233,48 @@ agent-seat match completion rate; desync events per 100 matches (target: 0).
233
 
234
  | Risk | Impact | Mitigation |
235
  |---|---|---|
236
- | **HF Space sleeps and kills live matches** | High | Short default matches (Β§6.1); lobby state on `/data`; reconnect-with-AI-takeover (Β§6.2) makes a wake-up survivable. Escalation: paid always-on. *Confirm behaviour β€” HF dossier.* |
237
- | **WebSockets constrained on Spaces** | High | Hand-rolled RFC 6455 behind a transport interface, so an SSE+POST fallback is a swap, not a rewrite ([ADR-0005](adr/0005-transport.md)). *Confirm β€” HF dossier.* |
 
 
 
238
  | **Server-authority refactor breaks determinism** | High | Determinism guards run in CI on every commit; the loopback transport (Phase 1) forces single-player through the identical code path, so the existing suite tests the multiplayer path too. |
239
  | **N-player generalization is broader than the `state.owners` scaffold suggests** | Medium | ~53 hardcoded owner comparisons are known to exist. Audited before work starts (engine dossier); 2-seat multiplayer ships first and needs almost none of it. |
240
- | **Free-tier CPU cannot run 4 concurrent 20 Hz sims** | Medium | Measure early with `tools/selfplay.js` as a load generator; the loop already degrades to slow motion rather than spiralling (`engine/loop.js` `MAX_SUBSTEPS`). |
241
  | **Empty lobbies make the game feel dead** | Medium | AI fills every open seat (FR-3): a solo arrival always gets a match. |
242
  | **Port drifts from upstream, losing future fixes** | Low | Upstream history preserved; `upstream` remote configured; engine changes kept minimal and upstreamable. |
243
 
244
  ## 11. Open questions
245
 
246
- - **Q1** Should the Space be public (Β§6.4)? Requires an explicit decision from the owner β€” it makes
247
- the game world-readable. *(Blocking for G1.)*
248
- - **Q2** Free tier, or paid always-on hardware? Determines whether long matches are viable.
249
- - **Q3** Is multiplayer **Odyssey** a wanted v2, or is skirmish the whole product? Shapes how much
250
- generality Phase 3 builds for.
251
- - **Q4** Should agent seats be visibly labelled to human opponents? (Fairness/transparency vs. a
252
- more interesting game.) Recommendation: **yes, labelled.**
253
- - **Q5** Does the existing single-player Elo/competition system get a multiplayer counterpart in v2?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  ---
256
 
 
1
  # SpaceCities β€” Product Requirements Document
2
 
3
+ **Status:** Draft v0.2 β€” pending review
4
  **Owner:** alma92350
5
  **Last updated:** 2026-08-30
6
  **Related:** [`docs/adr/`](adr/) (architecture decisions) Β· [`TASKS.md`](../TASKS.md) (delivery tracking)
 
233
 
234
  | Risk | Impact | Mitigation |
235
  |---|---|---|
236
+ | **Every deploy destroys in-flight matches** β€” a Space rebuilds and restarts on *every git push* | High | **Confirmed.** Matches snapshot to disk and restore on boot ([ADR-0012](adr/0012-crash-tolerant-matches.md)), sharing the reconnect mechanism. Raised from a Phase 7 nicety to a Phase 3 architectural requirement. |
237
+ | **The Space is private, so nobody can play** | High | **Confirmed blocker** β€” a private Space returns `404` for the running app, not just the source. Needs owner action (Q1). |
238
+ | **A non-PRO account may not be able to rebuild an existing Docker Space** | High | **Unverified, and cheap to test.** T-007a pushes a trivial commit and watches it build, before any porting effort is spent. Escalation: PRO at $9/month. |
239
+ | ~~WebSockets constrained on Spaces~~ | ~~High~~ | **Resolved.** Upgrades verified to traverse the HF edge proxy, and the owner's own live Space already serves a WebSocket plus `/mcp` on one port. A ~90-line zero-dependency server round-tripped against real Chromium ([ADR-0005](adr/0005-transport.md)). |
240
+ | **HF free hardware sleeps after 48 h idle** | Low | Tolerable for a game people play; snapshot/restore covers it. **No keep-alive pinger** β€” Spaces have been paused for abuse over exactly that. |
241
  | **Server-authority refactor breaks determinism** | High | Determinism guards run in CI on every commit; the loopback transport (Phase 1) forces single-player through the identical code path, so the existing suite tests the multiplayer path too. |
242
  | **N-player generalization is broader than the `state.owners` scaffold suggests** | Medium | ~53 hardcoded owner comparisons are known to exist. Audited before work starts (engine dossier); 2-seat multiplayer ships first and needs almost none of it. |
243
+ | ~~Free-tier CPU cannot run 4 concurrent 20 Hz sims~~ | ~~Medium~~ | **Resolved.** Measured: p99 4.6–9.1 ms/tick for realistic 200–400-unit matches against a 50 ms budget, and 22 ms even at 800 units in contact. Free tier is 2 vCPU / 16 GB. The real cost is serialization and fog filtering, not simulation β€” measured next (T-015). |
244
  | **Empty lobbies make the game feel dead** | Medium | AI fills every open seat (FR-3): a solo arrival always gets a match. |
245
  | **Port drifts from upstream, losing future fixes** | Low | Upstream history preserved; `upstream` remote configured; engine changes kept minimal and upstreamable. |
246
 
247
  ## 11. Open questions
248
 
249
+ - **Q1 β€” still open, and blocking.** Should the Space be made public (Β§6.4)? Now confirmed to be a
250
+ hard blocker rather than a preference: a private Space returns `404` for the running application,
251
+ so no anonymous player can reach the game at all. Requires an explicit owner decision, since it
252
+ makes the game world-readable. *(Blocks G1 and all of Phases 3–7 in production.)*
253
+ - **Q2 β€” answered.** Start on **free CPU Basic** ([ADR-0010](adr/0010-hf-deployment.md)). 48 hours of
254
+ idle tolerance is ample, and `$0.03/hour` CPU Upgrade removes sleep later if the game gets
255
+ traction. What remains is a *risk*, not a question: whether a non-PRO account can rebuild an
256
+ existing Docker Space β€” resolved empirically by T-007a.
257
+ - **Q3 β€” still open.** Is multiplayer **Odyssey** a wanted v2, or is skirmish the whole product?
258
+ Shapes how much generality Phase 5 builds for.
259
+ - **Q4 β€” still open.** Should agent seats be visibly labelled to human opponents?
260
+ Recommendation: **yes, labelled**, and their APM cap published alongside
261
+ ([ADR-0007](adr/0007-agent-pacing.md)).
262
+ - **Q5 β€” still open.** Does the single-player Elo/competition system get a multiplayer counterpart
263
+ in v2?
264
+
265
+ ## 12. Evidence base
266
+
267
+ Every claim in this document that could have been guessed was instead measured or verified. The
268
+ supporting dossiers live in [`docs/analysis/`](analysis/):
269
+
270
+ | Dossier | What it settles |
271
+ |---|---|
272
+ | [00 β€” Feasibility spikes](analysis/00-feasibility-spikes.md) | A ~90-line zero-dependency WebSocket server round-tripping against real Chromium; per-tick simulation cost under load; the platform precedent from the owner's own live Space |
273
+ | [01 β€” Engine N-player seams](analysis/01-engine-nplayer-seams.md) | Every owner literal in the engine, classified; the six real chokepoints; why two seats first is the cheap path |
274
+ | [02 β€” Command & wire protocol](analysis/02-command-wire-protocol.md) | The full command signature audit, the anti-cheat surface, the wire schema, and five engine defects that block multiplayer |
275
+ | [03 β€” Client coupling](analysis/03-client-coupling.md) | What the client must change, what is reusable verbatim, and why fog-filtered projection needs no renderer changes |
276
+ | [04 β€” HF Spaces](analysis/04-hf-deployment.md) | Platform limits, lifecycle, storage, secrets, and a ready-to-use Dockerfile and deploy workflow |
277
+ | [05 β€” MCP agent play](analysis/05-mcp-agent-play.md) | The current protocol revision verified against live docs, the tool surface, and the pacing analysis |
278
 
279
  ---
280
 
docs/analysis/05-mcp-agent-play.md CHANGED
@@ -18,7 +18,7 @@ occupy an ordinary player seat in a SpaceCities match.
18
  The current MCP protocol revision is **`2026-07-28`**, published **28 July 2026**, and it is
19
  declared *Current* on the versioning page:
20
 
21
- > "The **current** protocol version is [**2026-07-28**](/specification/2026-07-28/)."
22
  > β€” <https://modelcontextprotocol.io/specification/versioning>
23
 
24
  Revision history (all still reachable): `2026-07-28` (current), `2025-11-25`, `2025-06-18`,
 
18
  The current MCP protocol revision is **`2026-07-28`**, published **28 July 2026**, and it is
19
  declared *Current* on the versioning page:
20
 
21
+ > "The **current** protocol version is [**2026-07-28**](https://modelcontextprotocol.io/specification/2026-07-28/)."
22
  > β€” <https://modelcontextprotocol.io/specification/versioning>
23
 
24
  Revision history (all still reachable): `2026-07-28` (current), `2025-11-25`, `2025-06-18`,