By end of P1, the new omnitutor repo has the foundation libs that every later phase consumes: backend scaffolding (FastAPI app · DB pool · session middleware · log handler · model client · cost tracker · rate-limit middleware · moderation middleware), frontend scaffolding (design tokens · owl SVG component · KaTeX integration · base CSS · base JS state), CI/CD (GitHub Actions deploy · pytest + Playwright + k6 harnesses), and operational scaffolding (SSM secrets · CloudWatch logs · pg_dump backup cron · cost-cap cron). No user-facing surfaces exist yet — that's P2.
Acceptance demo: visit https://omnitutor.ai/v1/healthz · returns {ok:true}. Visit https://omnitutor.ai/v1/hello · gets a Haiku-generated greeting in <3s · audit shows the call logged in model_runs with cost · trace_id · latency.
omnitutor repo · just schema_v0.sql + READMEomnitutor.service serves only /healthz/_design/*.html static review hub/v1/hello worksmodel_runs automaticallytokens.css · owl SVG component · KaTeXmainTwelve ordered steps. Each verifies before moving to the next.
app/main.py with /v1/healthz · /v1/session · /v1/event · /v1/hello (test endpoint). Pydantic models for User · Session · ErrorEnvelope.asyncpg connection pool. Alembic for migrations · seed with schema_v0.sql. Helper module db.py with get_user(anon_id), create_session(user_id), etc.ot_session HttpOnly cookie. If absent or expired, creates anonymous user + sets cookie. Attaches request.state.session. Renews on every request.trace_id per request. Logs request start + end. CloudWatch sink.app/models/anthropic.py wrapping the SDK. Wraps every call in track_run() that writes a model_runs row · catches errors · maps to ErrorEnvelope. Same for ElevenLabs.rate_buckets · enforces §8 limits per scope+bucket. Returns over_quota when exceeded · sets retry_after_ms.refused if blocked + logs safety.refused event.web/styles/tokens.css exporting all design-language vars (sky-100..900, sea, ink, gold, coral, mint, cream, type stack). Imported once in base layout.web/components/owl.html · drop-in <svg> partial with all viseme/state classes pre-wired. Same component used in modal, rail, favicon..ttx spans on DOMContentLoaded. Single shared init script..github/workflows/deploy.yml · on push to main: pytest → playwright headless → SSH to devbox → git pull + systemctl restart omnitutor. Pulls SSM secrets into /etc/omnitutor/env.cron/backup.sh nightly pg_dump → S3. cron/cost_cap.sh nightly compute spend · raise OT_OVER_QUOTA if ≥$50/day. cron/cache_prewarm.sh stub (real prewarm in P10).curl https://omnitutor.ai/v1/healthz → 200 with {ok:true,ts}POST /v1/session creates users + sessions rows · sets ot_session cookie · subsequent requests reuse itPOST /v1/hello with {topic:"physics"} returns Haiku-generated greeting in <3s · model_runs row written with cost_usd + latency_ms + trace_idjournalctl -u omnitutor · every request's logs share one trace_id · all 13 dictionary fields populated/v1/hello calls from one IP in an hour · 6th returns over_quota/v1/hello returns refused · safety.refused event loggedecho "OT_OVER_QUOTA=1" >> /etc/omnitutor/env · restart · next /v1/hello returns over_quota immediately, no model calltokens.css renders with the four-blue palette · KaTeX renders F=ma · owl SVG appears with bow tie + glassesmain · GitHub Actions run completes green · service restarts · healthcheck still 200 within 90scron/backup.sh manually · verify s3://omnitutor-assets/backups/<date>.sql.gz exists · restore into scratch DB · all 11 tables presentGET /v1/lesson/test/stream with Last-Event-ID echo · returns SSE-shaped events with monotonic IDs (just plumbing, no real beats yet)# pytest fixture · spins ephemeral postgres + asgi client @pytest.fixture async def client(): async with AsyncClient(app=app, base_url="http://test") as c: yield c async def test_hello_world(client): r = await client.post("/v1/hello", json={"topic": "hello"}) assert r.status_code == 200 body = r.json() assert body["ok"] is True assert "greeting" in body assert body["latency_ms"] < 3000 # DB-side: verify model_runs row written async with db.acquire() as conn: run = await conn.fetchrow("SELECT * FROM model_runs WHERE trace_id=$1", body["trace_id"]) assert run["cost_usd"] > 0 assert run["status"] == "ok"
P1 ships when every line below is true. P2 cannot start until then.
main branchmodel_runs auditablev1.1-p1-shipped