Commit Graph
21 Commits
Author SHA1 Message Date
John SmithandClaude 96ced54af3 feat(auditor): ground truth from live engine, audit-before-yield streaming, narrative lore triples
- Grounding: NarrativeGenerateRequest gains engine_session_id /
  target_entity_id. When a session is named, _resolve_audit_inputs fetches
  the live snapshot and the auditor reconciles against IT: lethality fields
  come from the live entity (a payload claiming death while the engine says
  25 HP can no longer smuggle a kill past Vector 3), entity counts come
  from the live snapshot, named-but-missing targets are rejected as ghost
  entities, and an unreachable engine fails closed with
  WORLD_INSPECTOR_UNAVAILABLE instead of auditing stale client claims.
- Streaming: tokens are now HELD until the sentence they belong to has
  passed the auditor; violating sentences and everything after them are
  never emitted — only the corrective SYSTEM frame and the cut.
- Lore continuity: Vector 4 was dead code (nothing ever populated its
  lore_* payload keys). The auditor now derives (subject, predicate,
  object) triples from canon entity names and predicate verbs appearing in
  the draft itself, including reflexive assertions like "Oakhaven Keep
  still stands". Payload triples still take precedence.

Co-Authored-By: Claude <[email protected]>
2026-08-24 01:08:47 -04:00
John SmithandClaude a7dc5868b5 fix(homebrew): fail-loud parsing, never fabricate statblocks
Unparseable input used to silently yield a combat-ready fake: AC 14,
HP 30, invented "Claw Strike" action with +5 / 2d6+3. Core fields now
stay absent when not parsed, every missing field is reported in
warnings, and responses carry parse_ok. Strict mode (new flag on
HomebrewParseRequest) rejects with 422 instead of returning a
half-invented statblock. Placeholder lists are copied per call to stop
cross-parse state leaks.

Co-Authored-By: Claude <[email protected]>
2026-08-24 01:08:27 -04:00
John SmithandClaude a0d724e8dc fix(playtest): honest benchmark reporting — repair quoting, respawn sparring target
The step-4 report block had escaped quotes inside f-strings passed through
python -c, a guaranteed SyntaxError that suppressed live MCR/HCI/AFPR output
entirely. Replaced with a quoted-delimiter heredoc so the Python reaches the
interpreter byte-for-byte, and pinned AUTH_SECRET so the fail-closed engine
and the playtest signer agree.

First honest run then exposed a harness bug: the runner kept attacking its
training dummy after killing it (~100 turns of TARGET_ALREADY_DEAD rejections
dragging MCR to 76%). The runner now replaces the dummy when it drops, so
MCR measures action acceptance against living targets. Result: MCR 100%,
HCI 1.0, AFPR 0.0%, trust boundary 8/8.

Co-Authored-By: Claude <[email protected]>
2026-08-24 00:43:06 -04:00
John SmithandClaude beef779d51 fix(gateway): strict CORS allowlist, forward caller identity to engine proxies
- CORS: replace wildcard origins + credentials with an env-driven
  allowlist (CORS_ALLOW_ORIGINS), mirroring the engine's strict_cors.
- identity: engine proxies (spawn/cast-spell/move/turn-next/damage/
  reactions-arm, plus attack and death-save) now verify the caller's
  token and mint a forwarded-identity HMAC token carrying the real
  user_id and role, so the engine's RBAC authorizes the actual actor.
  Previously every proxied action spoke as 'orchestrator-service' with
  no role and was rejected ENTITY_NOT_OWNED on player-owned entities —
  deployed characters could not be driven end-to-end. Omitting the
  token keeps legacy service-mediated behavior.
- tests: proxy identity forwarding, 401 on invalid tokens, contract
  route updated to act as GM.

Co-Authored-By: Claude <[email protected]>
2026-08-24 00:42:52 -04:00
John SmithandClaude 9f31b5db26 feat(wave16): lobbies, character persistence, engine proxies, observability, rate limits
Closes the five product gaps surfaced by the campaign-harness exploration:
- Lobby REST API: create/join-by-invite-code/launch with dual-mode storage
  (Postgres lobbies+lobby_members / MemoryStore), host-only launch binding
  an engine session; LobbyView wired to real roster + invite code
- Character persistence: player_characters table + CRUD; deploy endpoint
  materializes a stat block as an RBAC-owned engine entity
  (owner_player_id = deploying user); CharacterBuilder persists on deploy
- Orchestrator proxy routes for spawn/cast-spell/move/turn-next/damage/
  reactions-arm (service-token authenticated, EngineRejectedError mapping)
- Observability: JSONL LLM call logger (tools + stream paths) and FastAPI
  request logging middleware; mitmproxy opt-in documented for MCP capture
- Rate limiting: in-memory sliding window (auth 30/min, agent 60/min,
  default 600/min) returning 429 + Retry-After
- Engine: orchestrator-service principal trusted to bind ownership on
  behalf of authenticated players during mediated spawns

Co-Authored-By: Claude <[email protected]>
2026-08-23 23:16:55 -04:00
John SmithandClaude 18239bf7b5 feat(wave15): zero-trust hardening, real WFC, write-through Postgres, RBAC, Yjs default
Phase 1-5 remediation + four-gap closure:
- Authoritative engine: ids-only combat payloads (deny_unknown_fields),
  server-side stat blocks, ActionBudget consumption, cover->AC, LoS gating,
  difficult-terrain Dijkstra, HMAC auth middleware + strict CORS
- Honest metrics: live-engine synthetic playtest with trust-boundary probes,
  MCR = valid/(valid+rejected), benchmark script boots its own engine
- Mechanics: condition lifecycle timers, spell slot economy w/ damage caps,
  topological ModifierSource graph, reaction stack (Shield/Counterspell/OA),
  X-card full ledger replay restoration
- Persistence: sqlx write-through tailer to event_sourcing_log,
  snapshot persist/hydrate bridge, recursive CTE inventory functions
- vtt-wfc: dead solver activated (reseed-retry contradictions, flood-fill
  single-region guarantee, deterministic dressing); fixed template removed
- RBAC: role claims in gateway tokens, identity propagation, entity
  ownership, spectator/owner enforcement, fog layer ownership at WS
- Client: PixiJS v8 board layer, physics dice with server-predetermined
  faces, Silero VAD, HRTF PannerNode chain, Y.Doc CRDT default transport
  with HMAC-authenticated ysync relay and LWW fallback

Co-Authored-By: Claude <[email protected]>
2026-08-23 22:41:53 -04:00
John SmithandClaude 013677eb4d feat(wave13): UI/UX hardening — code splitting, dice history, a11y & honest ambience
Perf:
- Route-level code splitting (React.lazy + Suspense): entry chunk 1.9 MB → 241 kB,
  30 on-demand view/modal chunks, Vite chunk-size warning gone

Features:
- DiceHistoryPanel: session audit log of every engine-resolved roll with
  crit/fumble highlighting, 50-entry cap, localStorage persistence
- ShortcutsModal + global keys: `?` cheat-sheet, Escape closes top-most modal,
  typing guard; "Keyboard Shortcuts" entry in Cmd+K palette
- Real WebAudio ambience engine (startAmbience/stopAmbience/setAmbienceVolume):
  jukebox presets synthesize per-track noise+drone loops; play state is now
  honest (opens paused) and master slider is live

Bug fixes:
- pyproject: declare reportlab (6 test modules failed collection on fresh envs)
- Navbar clipped X-CARD at 1366×768: responsive collapse, 0 overflow 900→1920px
- Canvas tool rail clipped under character dock: flex-wrap + max-width
- Macro quickbar occluded ~80% of chat console: collapsed by default
- Alarm-fatigue sounds removed from pagination/mic-toggle/seat-pick

A11y:
- Global :focus-visible rings, prefers-reduced-motion, .selectable-text
- aria-labels on icon-only controls; all modal close buttons labeled + autoFocus
  so focus enters dialogs on open; unlabeled form fields fixed (0 remaining)

SEO: meta description, <main> landmark, robots.txt, spec-compliant llms.txt

Verified: cargo ✅, pytest 57/1 ✅, MCR 100% / HCI 1.0 ✅, build ~1s ✅,
Lighthouse 100/100/100, Chrome DevTools sweeps 900→1920px with 0 visible
overflows. Details in docs/improvement-log.md.

Co-Authored-By: Claude <[email protected]>
2026-08-23 15:16:15 -04:00
John SmithandClaude 6aef9e73b8 feat(wave12): Postgres persistence & campaign save/load
- storage.py: dual-mode store — PostgresStore (asyncpg pool) when
  DATABASE_URL is reachable, MemoryStore fallback otherwise; idempotent
  _ensure_tables() DDL at startup; PBKDF2 credential helpers centralized
- 03_campaign_persistence.sql: narrative_state.users, campaigns (anchors
  the previously free-floating campaign_id), campaign_saves (JSONB
  snapshots) + owner/updated index — also auto-run by compose init
- auth routes now persist users across restarts (verified live: seeded GM
  account survives process restarts via Postgres)
- new token-guarded API: POST /api/v1/campaign/save (upsert by owner+name),
  GET /campaign/saves, GET /campaign/save/{id}, DELETE /campaign/save/{id}
- client: CampaignSaveModal (save/list/load/delete with round + timestamp),
  Campaign Saves entry in Table Tools dropdown, snapshot build/apply in App
- fix compose postgres crash-loop on SELinux systems (:ro,z relabel flag)
- tests: memory-mode API CRUD always runs; PG end-to-end incl. cross-owner
  denial and durability-across-reinit skips without DATABASE_URL
  (58 pytest pass with Postgres up, cargo clean, MCR 100%)

Co-Authored-By: Claude <[email protected]>
2026-08-23 10:53:40 -04:00
John SmithandClaude 3920b10e59 feat(wave11): SRD-grounded narration, end-to-end X-card rewind & honest voice activity
- narrative stream: extract_srd_context() scans player intents against the
  SRD 5.2 bestiary/grimoire and injects stat-block facts (AC/HP/actions,
  spell level/school/description) into both live LLM prompts and the
  deterministic mock generator — the DM can no longer contradict the rules
- new GET /api/v1/compendium/lore-lookup for client-side fact resolution
- safety: X-card now applies a real ledger rewind on the engine session
  (POST /sessions/{id}/safety/x-card) via the orchestrator, recording
  SAFETY_REWIND_APPLIED audit events; client wires the SafetyModal through
- voice: removed the random speaking simulation from WebRTCMeshManager;
  local mic RMS (getUserMedia + AnalyserNode) drives the real speaking
  ring; remote peers stay silent until genuine P2P audio lands
- tests: +7 grounding/x-card suite (53 pytest total pass), cargo clean,
  client ~1s build, MCR 100% / HCI 1.0 / AFPR 0%

Co-Authored-By: Claude <[email protected]>
2026-08-23 01:35:50 -04:00
John SmithandClaude ce03c0fae0 feat(wave10): real multiplayer backbone — WebSocket CRDT relay, live presence & server-backed auth
- vtt-server: activate the dormant CrdtRelayHub with a live PeerRegistry and
  actix-ws endpoint /ws/sessions/{id}/sync (root + /api/v1 alias). Token moves
  pass LWW vector-clock arbitration before fan-out; stale transforms are
  suppressed. GET /rooms/{id}/presence reports connected peers.
- client: VttCrdtSyncClient gains remote-update listeners, exponential
  backoff reconnect, solo-safe no-ops; App.tsx instantiates it, broadcasts
  token drags, applies peer updates; LobbyView polls live relay presence
- orchestrator: /api/v1/auth/{signup,login,session} — PBKDF2-salted password
  hashes, HMAC-signed 12h tokens (AUTH_SECRET env), default GM seed account;
  AuthModal uses the server with demo-account fallback offline
- tests: +5 auth suite; all suites green (46 pytest engine-up, cargo clean,
  client ~1s build, MCR 100% / HCI 1.0)

Co-Authored-By: Claude <[email protected]>
2026-08-23 01:23:15 -04:00
John SmithandClaude d2af1487bd feat(wave9): resolve all dice through the authoritative Rust rules engine
- vtt-server: new POST /api/v1/actions/{save,concentration,death-save}
  handlers backed by vtt-core RulesEvaluator; /actions/check now honors
  advantage/disadvantage
- orchestrator: routing/engine_client.py + /api/v1/engine/* proxy routes
  (session, attack, check, save, concentration, death-save, map/generate)
  with 502 on engine-down; ENGINE_API_URL env-configured
- client: App.tsx attack/spell/check/macro rolls now resolve server-side
  via api/rules_engine.ts (local dice fallback offline); WfcStudioView
  hits the real engine WFC route and maps its Vec<Vec<u8>> tile grid
- tests: 8 proxy tests (live-engine integration + 502 contract), all
  suites green: 41 pytest pass engine-up / 34+7 skip engine-down,
  cargo workspace clean, client builds in ~1s, MCR 100% / HCI 1.0
- fix misleading "ALL PHASES 1-7" benchmark banner

Co-Authored-By: Claude <[email protected]>
2026-08-23 01:00:30 -04:00
John SmithandClaude Opus 5 07ac5ce9ca feat(wave8): expand compendium with SRD 5.2 magic items, feats, origins, animals & full stat blocks
- New srd52_importer.py parses the flat-file SRD 5.2.1 markdown layout
  (downfallx/dnd-5e-srd-markdown, CC BY 4.0) into 7 fixture domains:
  235 monsters with complete trait/action/legendary sections (was 28 of
  318 shells), 352 spells with untruncated descriptions + upcast text,
  260 magic items with rarity/attunement, 95 animal stat blocks,
  17 feats, 8 backgrounds + 9 species origins, 154 glossary terms
- Server: prefer srd_5_2 fixtures (5.1 fallback); add /api/v1/compendium
  routes for magic-items, feats, origins, animals, glossary
- Client Codex: new Magic Items / Feats / Animals / Glossary tabs reusing
  pagination engine; rarity chips; animal spawn-to-canvas; attribution footer
- CommandPalette: live-indexes spells/items/feats/glossary over Cmd+K search
- Fix mismatched API paths in CharacterBuilderView and BundleManagerView
- Add ATTRIBUTION.md (Wizards of the Coast SRD, CC BY 4.0)
- Tests: +12 importer tests against checked-in sample markdown (33 total pass)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-23 00:27:49 -04:00
John Smith 3ed3815820 feat: complete Horizons 1, 2, and 3 (Docker Compose, Procedural Quest Engine & Concordia Pacts, and 3D Elevation) 2026-08-22 19:49:55 -04:00
John Smith 82125ed1a6 feat(srd): parse D&D 5e SRD markdown into hardcoded VTT core logic, schemas, and relational tables 2026-08-22 19:40:57 -04:00
John Smith 774c68410a feat(campaign-bundles-homebrew): implement COMPASS .vttbundle packaging, Homebrewery markdown parser, and bundle manager studio 2026-08-22 19:31:12 -04:00
John Smith 8ef12b5e4d feat(dynasty-empirical-playtest): implement opendnd dynasty lineages, feud matrix, and dnddata empirical party benchmarks 2026-08-22 19:27:54 -04:00
John Smith 04400c31a6 feat(character-builder-pdf): implement 5e character studio, strict modifier graph, and vector PDF exporter 2026-08-22 19:12:08 -04:00
John Smith a412361071 feat(srd-loot-lighting-audio): integrate full SRD 5.1 dataset, Dungeoneer loot tables, 2D raycast lighting, and Web Audio cues 2026-08-22 19:00:42 -04:00
John Smith ee48e290b1 feat(llm-dice-ci): add configurable LLM streaming gateway, 3D dice physics, particle FX, and GitHub Actions CI 2026-08-22 18:51:37 -04:00
John Smith d2ccf6dfd3 feat(full-stack): add interactive React UI and Docker Compose stack (Tracks A & B) 2026-08-22 18:13:17 -04:00
John Smith 25a3301480 feat: complete Phases 1-7 enterprise autonomous AI-native virtual tabletop engine 2026-08-22 17:34:37 -04:00