midnight_mystery / docs /ARCHITECTURE.md
lcpizani's picture
Add full app: pages, assets, backend, config
811d960
|
Raw
History Blame Contribute Delete
7.84 kB
# 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.