# Architecture & Judging Coverage — Midnight Mystery with Detective Shawn This document does two jobs: 1. Explains how the system is built (for technical judges and future contributors). 2. Maps the build to the **Build Small** judging surface so the submission collects as many "ways to win" as possible. --- ## 1. System overview ``` main.py (FastAPI) ┌───────────────────────┼───────────────────────────┐ │ │ │ Gradio: onboarding Gradio: game Gradio: case-closed (custom noir form) (HUD + iframe map) (reveal + debrief) │ │ │ ▼ ▼ ▼ case_generator Phaser 3 (game.html) debrief service (5-pass pipeline) ⇅ postMessage / fetch │ │ │ │ ▼ ▼ ▼ └──────── backend/routers (case · interrogation · forensic) ───────┘ │ inference_client (HF Serverless / Ollama) │ Qwen3.5-9B (text) FLUX.2-klein-4B (portraits) ``` - **Three Gradio apps, one FastAPI host.** Each page is its own `gr.Blocks` mounted via `gr.mount_gradio_app`, so onboarding, the game, and the reveal are independent and each fully custom-styled. - **Phaser ⇄ backend bridge.** The map is a self-contained Phaser scene in an iframe. It talks to FastAPI with `fetch` and `postMessage` — movement, clue discovery, and interrogation all flow over HTTP. - **State.** A Pydantic `CaseFile` holds the entire game; an in-memory store keyed by `case_id` carries it across requests. A complete hardcoded `SEED_CASE` is the guaranteed fallback. --- ## 2. The generation pipeline (the centerpiece) A single small text model is driven through five narrow passes. Splitting the work keeps a 9B model reliable: each prompt is small, each output is validated, each failure is recoverable. | Pass | Input | Output | Guarantee | |------|-------|--------|-----------| | **0 · Roster** | victim, scene, count, difficulty | cast (name, occupation, archetype, role) | exactly one culprit; fixed cast for later passes | | **1 · Story Bible** | roster + setting | the hidden ground truth (how/why/when, motive) | the truth is written once and never sent to suspects | | **2 · Souls** | story + one cast member | per-suspect "soul": voice, alibi, reveal rules, crack progression | runs **in parallel** (`asyncio`); each has a validator + fallback | | **3 · Evidence** | story + soul summaries + map rooms | clues anchored to real locations + soul write-backs | **≥2 solvable paths**; clues land on real `clue_anchors` | | **4 · Briefing** | **public fields only** | police dossier lines | structurally cannot leak the culprit | **Why this wins points:** it's a concrete, defensible answer to "can a small model do something hard?" — yes, if you decompose the task, validate each step, and constrain it to a real world (the map manifest). It's not prompt-and-pray. ### Live systems layered on top - **Emotional state machine** (`state_mutator`, `interrogation_pipeline`): trust / anxiety / defensiveness per suspect; crack thresholds scale with `lying_skill` (1–10). State is rendered into natural-language instructions so the model *enacts* pressure instead of describing it. - **Knowledge gate** (`knowledge_gate`): suspects can only reveal authorized facts; everything else is forbidden context. - **Prompt-injection defense**: known injection patterns are caught and deflected *in character* by archetype. - **Reactive world** (`patrol`, alertness): suspects patrol their zones; a stealth/alertness layer escalates suspects and can warn the culprit. - **Forensics** (`forensic_lab`): clue analysis that can detect contradictions against interrogation transcripts. - **Debrief** (`debrief`): the model grades the playthrough and narrates the resolution. --- ## 3. Small-model compliance (the hard requirement) | Component | Model | Params | < 32B? | |-----------|-------|--------|--------| | Case generation | `Qwen/Qwen3.5-9B` | ~9B | ✅ | | Interrogation / debrief / forensics | `Qwen/Qwen3.5-9B` | ~9B | ✅ | | Portraits | `black-forest-labs/FLUX.2-klein` | ~4B | ✅ | Rule check: *"each model's parameter count must stay below 32B."* Largest single model here is **~9B**. Comfortably compliant — and the *narrative* of the project is precisely "look how much one small model can carry." > ⚠️ **Consistency fix before submitting:** model names are stated inconsistently across the repo. `inference_client.py` (the source of truth) defaults to **Qwen3.5-9B** + **FLUX.2-klein-4B**, but `DEPLOYMENT.md` lists Qwen3-14B + Mistral-Small-24B + FLUX, and the onboarding CTA still says "Qwen-2.5-7B". Pick the real set, then make README, DEPLOYMENT.md, the onboarding CTA, and the demo VO all agree. Judges will notice a mismatch. --- ## 4. Judging-surface coverage The field guide describes ~29 ways to win across track placements, Community Choice, sponsor prizes, the Custom-UI category, and stackable bonus badges. This project is strongest where it leans into being *AI-native* and *visually distinct*. | Target | Why this build qualifies | Action to lock it in | |--------|--------------------------|----------------------| | **Thousand Token Wood** (track placement) | Couldn't exist without AI; the model *is* the game | Lead the README + video with this framing ✅ | | **Custom UI badge** | Zero default-Gradio surfaces — bespoke noir CSS, Phaser map, custom loader | Show the UI prominently in the video; tag `custom-ui` | | **OpenBMB / small-model sponsor** | Whole pitch is "one 9B model runs a game" | State param counts everywhere; confirm sponsor tag slug | | **Community Choice** | Shareable, novel hook ("name a victim, AI writes the murder") | Strong social clip; post early for votes | | **"Most badges stacked"** | Genuinely spans creativity + UI + small-model + agentic | Add every *honestly applicable* badge tag | | **Full-package** | App + demo video + social post all exist and align | Ship all three; keep them consistent | ### Submission checklist (hard requirements) - [ ] Deployed as a **Gradio app in the official `build-small-hackathon` HF org** - [ ] **Demo video** showing the app working (see `DEMO_VIDEO_SCRIPT.md`) - [ ] **Social post** created and **linked from the README** (see `SOCIAL_POST.md`) - [ ] README **YAML tags** for the track + every badge being claimed - [ ] All models verified **< 32B** and named consistently everywhere - [ ] Submitted before **June 15, 23:59 UTC** --- ## 5. Pre-submission risk list 1. **Theme consistency.** The game is now *Detective Shawn* (human noir). Sweep for leftover pet/animal copy in user-facing strings (onboarding hints reference "animals in the neighbourhood"; portrait assets are animal placeholders). Anything a judge sees must match the shipped theme. 2. **Model-name drift.** See §3 warning — unify before recording the video. 3. **Inference reliability during judging.** The seed-case fallback covers a hard outage, but verify the Space's `HF_TOKEN`/provider and that portraits degrade gracefully. The demo video is your insurance — record it on a known-good run. 4. **First-paint impression.** Onboarding is the most-judged screen after the video. It's already strong; make sure fonts load on the Space (Google Fonts CDN reachable) so the noir look survives deployment.