Architecture Decision Records (ADR)
ADR-0001: Record architecture decisions as ADRs
Context
GAME_SPEC.md captures what the game is (rules, FR/NFR). It doesn't
capture why we built it a particular way, and that reasoning otherwise
lives only in chat history or a contributor's head — which the AEA framework
explicitly excludes as shared memory ("Chat is not shared memory";
architecture.artof.link/comparison.html).
Decision
Every non-trivial technical decision (stack choice, engine/UI split,
data format, a reversal of an earlier decision) gets a short ADR in
docs/adr/, numbered sequentially, following TEMPLATE.md. ADRs are never
renumbered or deleted (same ID-freeze discipline as FR/NFR IDs).
Consequences
Anyone — human or AI agent — picking this repo up cold reads AGENTS.md,
then GAME_SPEC.md, then skims docs/adr/ to understand not just the rules
but the reasoning already spent, instead of re-litigating settled questions.
---
ADR-0002: TypeScript monorepo, 2D now, 3D-and-native deferred behind one renderer interface
Context
Target progression is 2D (board-game style) now, 3D later, deployed to
laptop (web), then tablets and phones (Android first for validation).
NFR-1 (determinism) and NFR-4/NFR-10 (fast, isolated, headless testing of
the solver and hero AI) need to hold throughout that progression.
A game engine such as Unity or Godot would also reach web+mobile+3D from one
project, and a Unity license is available if this direction is revisited.
The trade-off: those engines fuse simulation and presentation, which makes
the deterministic, UI-free unit testing NFR-1/NFR-10 ask for harder to keep
cheap in CI (headless render setups, license activation per CI run), and
makes scripts/check-requirements-trace.mjs (linking FR/NFR IDs to plain
test files) awkward against engine-native test frameworks.
Decision
packages/engine: pure TypeScript, no DOM/engine dependency. Owns everyFR-xx/NFR-xx behavior and is exhaustively unit-tested (Vitest) in CI in
seconds, with no build/device step.
apps/web: the Maker, Vite + React. Renders the dungeon on a plain 2Dcanvas now (matches the board-game phase). A future 3D pass swaps in
three.js / react-three-fiber behind the same room-state props — engine
code does not change.
apps/web running directly in a browser.apps/web output withCapacitor to produce an installable Android app with zero UI fork. Revisit
React Native only if Capacitor's WebView performance becomes a real
constraint once 3D lands.
the existing Unity license stays a fallback if the 2D-canvas → three.js →
Capacitor path hits a wall — not adopted now, per the trade-off above.
Consequences
One engine codebase, one UI codebase, for the whole 2D→3D / laptop→tablet→
phone progression. The only two things that change over time are which
renderer is mounted (canvas vs. three.js) and which shell runs apps/web
(browser vs. Capacitor) — packages/engine never has to know.
---
ADR-0003: Multi-agent collaboration across OpenAI, Claude, Grok, AGY, Copilot, Kimi, and DeepSeek
Context
Development on this repository involves multiple autonomous AI agents and coding assistants across distinct providers and frameworks — including Anthropic Claude, OpenAI/Codex, xAI Grok, Google Antigravity / Gemini (AGY), GitHub Copilot, Moonshot Kimi, and DeepSeek.
Without strict architectural constraints:
1. Each tool introduces proprietary configuration formats or instructions that drift out of sync.
2. Agents assume ephemeral chat history represents shared knowledge, leading to forgotten context between different agent sessions.
3. Concurrent agent sessions can rebase or overwrite each other's in-flight work or make simultaneous uncoordinated edits to single-source ledgers (docs/STATUS_LEDGER.md, docs/FINDINGS.md).
4. Cross-platform checkout differences (e.g., Windows CRLF vs. Linux/Mac LF in CI containers) cause diff noise across agents.
Decision
1. Single Source of Truth (AGENTS.md): All agent guidelines reside exclusively in AGENTS.md. Tool-specific entrypoints (CLAUDE.md, GEMINI.md, CODEX.md, OPENAI.md, GROK.md, KIMI.md, DEEPSEEK.md, .github/copilot-instructions.md, .cursorrules) are strict, minimal pointers that redirect directly to AGENTS.md. No tool-specific instructions may diverge.
2. Shared Memory Discipline: Chat history is not shared memory. The default branch, PR branches, and committed docs (GAME_SPEC.md, docs/STATUS_LEDGER.md, docs/FINDINGS.md, docs/journal/) are the sole shared memory between agents.
3. Isolated Workspaces & Branch Convention: Agents work on separate topic branches named agent/<agent-family>/<task-slug> or copilot/<task-slug>. Agents must never rebase over another in-flight branch.
4. Peer Review & Verification: A producer agent does not self-approve or merge its own changes. Pull requests must pass automated CI checks (pnpm test) and governance checks (pnpm governance) before review and merge by another agent or human.
5. Cross-Platform Line Ending Normalization: Enforce eol=lf via .gitattributes so agents operating across heterogeneous environments (Windows, Linux, macOS) produce uniform diffs.
Consequences
AGENTS.md and operates under identical constraints without prompt drift.---
ADR-0004: Deployment architecture, knowledge site, and observability
Context
Following the dual-site architecture of the Adaptive Experience Architecture framework (architecture.artof.link + aea.artof.link) and Café Fausse (knowledge.cafe.artof.link + cafe.artof.link), Zorg's Dungeon Maker requires two distinct public endpoints:
1. Implementation & Playback view (zorg.artof.link): Interactive 2D Maker grid canvas and extermination simulation runner.
2. Knowledge Base (knowledge.zorg.artof.link): Canonical reference for game rules, requirements traceability graph, honesty ledger, coherence findings, and dev journals.
3. Observability (https://zorg.artof.link/grafana/): Public monitoring of host and container metrics, matching https://aea.artof.link/grafana/.
Evaluation between AWS ECS Fargate + ALB vs. AWS Lightsail + Docker Compose revealed:
small_3_0, \$12/mo flat) provides 2 vCPUs, 2 GB RAM, 60 GB SSD, 3 TB egress, and static IP. It hosts a self-contained Docker Compose stack with zero cloud sprawl and matches the existing operational model of cafe.artof.link.Decision
1. Implementation Compute: Deploy zorg.artof.link on AWS Lightsail instance zorg-dungeon-prod (Ubuntu 24.04, small_3_0) in us-east-1a with static IP 54.152.172.19.
2. Implementation Stack: Use Docker Compose running:
- web: Multi-stage build of @zorg/engine and @zorg/web served by Nginx.
- caddy: Reverse proxy providing automated Let's Encrypt TLS and reverse proxying /grafana/ to Grafana and / to the web app.
- prometheus: Scrapes node and web metrics with local TSDB persistence.
- grafana: Served at /grafana/ with anonymous viewer access enabled, pre-provisioned Prometheus datasource, and system dashboards.
- node-exporter: Exposes host CPU, RAM, disk, and network metrics.
3. Knowledge Site: Host knowledge.zorg.artof.link on GitHub Pages (artofdream.github.io.) built via GitHub Actions (.github/workflows/knowledge.yml) from markdown files in docs/ and GAME_SPEC.md.
4. DNS Management: Manage records in Route 53 zone Z1178AFMV41RWP (artof.link.):
- zorg.artof.link. $\rightarrow$ A 54.152.172.19 (TTL: 60)
- knowledge.zorg.artof.link. $\rightarrow$ CNAME artofdream.github.io. (TTL: 300)
Consequences
/grafana/ without credentials required for inspection.---