July 13 — Foundation
Intent
Turn a detailed concept document into an executable, modular foundation while preserving a public record that another first-time game developer can follow.
Decisions
- Canonical name: Webwoven.
- Product track: Education.
- Runtime graph: immutable SQLite behind an interface.
- AI boundary: development-time Codex artifacts only; deterministic gameplay.
- Creation workflow: Codex-native artifacts with truthful
generator: codexprovenance, strict grounding validation, and human approval; no external model integration or AI credential. - Visual direction: editorial atlas, Newsreader and IBM Plex, no purple or gradients.
Work
- Established repository, documentation, licensing, design, and validation conventions.
- Began independent data, backend, and web workstreams after the shared contracts were fixed.
- Rechecked the official Build Week and Devpost overview pages and preserved a pre-submission rules verification gate.
- Locked 20 playable relations and 160 live-verified anchor QIDs, exactly 40 in each category.
- Compiled the deterministic smoke graph: 48 synthetic entities, 96 edges, 100 candidates, and 40 fixture approvals with the locked difficulty distribution.
- Replaced anonymous numbered smoke-test waypoints with four clearly fictional, readable story rings. The fixture still has the same locked counts and no network dependency, but its routes now connect distinct people, works, species, institutions, and places across all 20 playable relation types, making local game sessions useful for human testing before the production snapshot exists.
- Bumped the immutable graph to schema v2 so every compiled edge retains its forward or inverse direction. The API now presents the matching registry label without replacing the complete fixture fact sentence used for route explanations.
- Responded to the first hands-on playtest by replacing the quiet route utility line with a persistent active-round masthead. It makes the running timer, objective, start, goal, difficulty, moves, and score timing explicit; the route ribbon now marks Start and Current, and mobile puts the current entity before the illustration.
- A second hands-on playtest showed that the route ribbon, entity stage, and relationship accordions still read as a data website rather than a game. Replaced that composition with a deterministic map board: the current node, one visible goal marker, connected paths, and direct entity move controls now form the primary play surface.
- Added a pure renderer-independent
MapBoardprojection with stable normalized positions. A presentation-only Three.js layer draws the tactile paper field and connections, while semantic DOM buttons retain the entity names and complete fact sentences needed for keyboard, screen reader, reduced-motion, and WebGL-fallback play. - Hardened the map after cross-discipline review: duplicate edges to one entity now become one domain-owned choice with every fact preserved, large choice sets use fixed deterministic lanes, the Compass asks the player which visible route to evaluate, short screens cannot be covered by the hint dock, and a deterministic SVG keeps the connection map visible without WebGL.
- Separated the full Compose same-origin address from the split Vite/API development origins, so a
copied local
.envcannot make Caddy-served session creation fail its own Origin guard. - Made the local Caddy bind address configurable and documented the explicit LAN origin settings needed for real-device playtesting without weakening the default localhost-only setup.
- Preserved complete relationship sentences across API-backed moves so the result trail explains the route instead of showing an unexplained list of entity names. Server-provided entity IDs, labels, and order remain authoritative.
- Exposed the server's optimal distance in every session snapshot so the active-round masthead shows a numeric par from the same immutable graph used for scoring.
- Hardened the playtest path after review: direction-aware relation-group IDs prevent duplicate-key failures, stale commands cannot attach a locally selected fact to another tab's move, schema-v1 graphs are rejected before health succeeds, and a current position reached through Back is not crossed out.
- Separated synthetic fixture provenance from production knowledge provenance. Fictional local entities no longer receive fabricated Wikidata links or CC0 labels; the Sources drawer identifies them as project-authored MIT test data.
- Replaced the Results page's old static Cartographer anecdote with a deterministic recap assembled only from the completed route's entity labels and move count.
- Added Codex-artifact schemas and validators for exact prompt capture, hashes, fact grounding, English-only output, answer-leak rejection, and explicit human approval.
- Made the committed Draft 2020-12 schema executable with format checks, then strengthened the semantic gate so cited fact IDs cannot legitimize unrelated prose. Added regressions for schema length limits, unsupported factual tokens, and non-English copy containing an English marker.
- Completed the first server-authoritative API and responsive Svelte vertical slice across Solo, Daily, and Multiplayer routes.
- Hardened the visual contract to exactly seven palette inks, constrained the three font families and seven-step type scale, split game CSS by interface responsibility, and kept unapproved illustration drafts out of the production bundle.
- Recorded project-owner approval for all four category plates. The first Cartographer composition was rejected because its outward-facing map had an ambiguous orientation; a new composition put the map flat on a tilted field table so the character's gaze, hands, and visible map surface agree.
- Approved the replacement Cartographer and promoted all five reviewed WebP derivatives into the production bundle with prompt hashes, source and derivative hashes, validation results, and the human approval timestamp preserved in their manifest. The app serves these immutable assets without runtime AI calls or provider credentials.
- Acquired the first real two-hop Wikidata playtest snapshot through 46 immutable, hashed
wbgetentitiesbatches. After rejecting one entity without an English label, the compiled graph contains 2,214 real entities, 12,130 directed playable edges, all 20 relation types, 100 route candidates, and 40 locally enabled anchor-to-anchor routes. - Added a real-data bundle assembler, explicit
wikidataversustest_fixturemanifest identity, graph/manifest build-ID verification, reviewed-anchor endpoint selection, and truthful pending review records. The bundle has no Commons documentary media or approved production rounds yet. - Removed silent synthetic fallbacks from normal browser and API startup. The active game now either loads the real immutable graph or shows an error; the smoke and Hokusai graphs remain available only to explicitly configured automated tests.
- The first real Einstein session exposed 51 stored neighbors, which was correct graph data but a poor game board. Added a deterministic six-destination projection that preserves relation variety, groups multiple facts per target, and guarantees a visible move closer to the goal.
- The first real route also exposed qualifier loss: ended historical capitals and territories were being rendered as present-tense facts. The shared statement policy now follows Wikidata's best rank, excludes relationships with an end-time qualifier, rejects unlabelled nodes, and removes self-loops before graph compilation.
- Fixed a route-entry race where navigation hydration and the landing action each created a Solo session. Route hydration now owns session creation, producing exactly one server request per round. Successful API responses are also checked for a JSON media type and a complete body, so transport failures identify the affected method and endpoint instead of exposing a native browser JSON parser error.
- Reworked the map after the next hands-on playtest showed that replacing the frontier still felt flat and stateless. Every applied Follow or Back now persists the exact decision frontier, while hints and duplicate or stale commands do not. The client renders each visit as a distinct occurrence, retains rejected choices as grey noninteractive branches, highlights the selected breadcrumb, and adds a horizontally scrollable column for the next move. The history survives refresh and reconnect without retaining expired edge tokens.
- Gave the Three.js markers a visibly physical cel-shaded treatment: low-poly extruded atlas tokens, discrete light bands, ink outlines, offset shadows, stronger breadcrumb paths, and muted discarded branches. The SVG fallback mirrors those states, and the semantic DOM remains the only interaction owner.
- Added same-tab active-session resume after the live browser pass exposed that a refresh replaced
the signed guest before it could reload the persisted map. The browser stores only the opaque
session ID;
GET /api/v1/guests/merestores the existing cookie-bound guest and CSRF token, then the authoritative session snapshot reconstructs every resolved column. No edge token or credential enters browser storage. - Replaced the one-axis route strip with a shared spatial camera. The map now supports background drag, two-dimensional pan, cursor-anchored wheel and pinch zoom, keyboard navigation, fixed zoom controls, Fit map, and Current focus on desktop and touch screens. The semantic Svelte world, viewport-sized Three.js renderer, and SVG fallback consume the same camera contract, so long routes stay aligned without allocating an ever-wider WebGL framebuffer.
- Kept the phone canvas playable by focusing its initial camera on the current node and first two routes at a readable minimum scale; the full explored graph remains available through Fit map, and the remaining choices are reached by dragging the same canvas.
- Made old branches genuinely inspectable. Taken and rejected nodes are focusable read-only controls that reveal their descriptions, source-to-target connection, and every retained fact; they never spend a move. Resume reconstruction now restores Follow and Back link semantics, suppresses the duplicate return option created by some inverse edges, and preserves grouped facts without storing signed edge tokens.
Validation evidence
The first runnable foundation passed strict Python typing, Ruff, pipeline and API tests, Svelte
diagnostics, production web compilation, strict MkDocs, SQLite integrity, fixture checksum, token
palette, and authored-file-size checks. The reproducible graph build id is
df03018f41595db58d31bbc5652bac9fb984a5a1d0a3213758daf5616132f476.
After the expanding-map integration, 104 Python tests, 45 frontend unit tests, and 14 Playwright
desktop/mobile journeys pass. Ruff, Pyright, Svelte diagnostics, Prettier, Stylelint, strict MkDocs,
dependency audits, the design-token guard, the 600-line guard, and all three container image builds
also pass.
A fresh credential-free Compose stack brought PostgreSQL, Valkey, the API, the verified graph, the
game, and /docs/ to healthy state; guest creation through Caddy issued the signed HttpOnly guest
cookie and separate CSRF cookie as designed.
The final security pass bound CSRF tokens to the authenticated guest, expanded abuse limits to all state-creating game routes, added shared WebSocket concurrency leases plus idle and lifetime bounds, separated loopback-only local Compose from validated production deployment, and moved private backups outside the repository by default.
Raw private task transcripts, hidden reasoning, local environment output, and credentials are intentionally excluded.