specs/00-Curriculum-Service.md
Curriculum Service — Module 00 (standalone software)
A separate, standalone piece of software with its own UI (3 screens) and its own database. It researches school science curricula per
(state, county), runs voting/deduping, lets a human finalize, and publishes the Topic Catalog. The Book Factory is a separate system that calls this software and embeds its Screen 3 (finalized topic list) so the buyer can select a topic. Coupled only through the catalog. This is the first module we build.
Key facts that shape the design [RESOLVED 2026-06-03]
- GA science standards are statewide (GSE). Fulton and Cobb teach the same standards. So per-county research + "voting/dedupe" in GA returns one topic set (the vote confirms GSE), not different topics.
- The real per-county difference is the pacing guide — the district's order and timing for teaching those standards. Pacing powers the Summer-Bridge pitch ("what your child sees next year, in your county's order").
- The cross-county/cross-state prevalence-ranking machinery earns its keep at multi-state scale (where standards genuinely differ). The pilot builds the hooks; the payoff is post-pilot.
- "East Cobb" → Cobb County (Cobb County School District). The curriculum unit is the district.
Approach [DECIDED 2026-06-03]
- Full per-county research, parameterized by
(state, county)— via input form OR programmatic params. Long-term target: all counties, all US states. - Pre-research batch model (NOT on-demand). Rationale: curriculum must be human-validated before any customer sees it; on-demand research can't honor that gate at order time. So the job pre-researches, dedupes/votes, validates, and stores — orders only ever read published data.
- Idempotent job: for each
(state, county): if validated+fresh data exists → skip; else research → merge/dedupe with existing → draft → human-validate → publish. Adding a county later = add to config + run. - Pilot config:
(GA, Fulton),(GA, Cobb). All GSE K–G2 science topics.
Research Output Standard — THE QUALITY BAR [DECIDED 2026-06-03]
Golden exemplar: docs/specs/00-Curriculum-Sources-GA.md (the operator-sourced GA research). Every research run, for any (state, county), must hit this depth — it is the acceptance bar, not a nice-to-have. The module's research output AND the Screen-3 gate are judged against these criteria:
- Currency determination — explicitly identify which standard set is currently in effect for the target year, with adoption year, board-approval date, and effective school year; and explicitly check whether it was recently replaced (state which set applies now). If no evidence of replacement: say so.
- Primary/official sources only — every claim cited to an official government/education domain; third-party/blog/summary sources rejected.
- Exact source URLs — master standards platform + per-grade document/node URLs; prefer structured standards APIs (CASE) over PDFs.
- Exact codes + verbatim descriptions — per grade, the official standard code + the official description text verbatim, each with its own source URL.
- Provenance dates — capture document/revision/
lastChange/effective dates per source. - District pacing with sequences — per-district teaching order across the year, with official district URLs + dates.
- Honest gaps — when something can't be verified from an official source, output "not found in an official source" — never guess or fabricate.
- Structured output — organized by grade (tables/lists), machine-parseable.
This bar IS the product's credibility moat. A run that returns topics without current-vs-replaced resolution, verbatim codes, official URLs, and honest gaps is a failing run, regardless of how complete it looks.
Purpose
Maintain a trustworthy, human-validated catalog of grade-appropriate science topics (with full lesson packs) so a buyer can pick grade → topic without ever seeing standards jargon, and the Book Factory can build from validated content.
Scope (pilot) [DECIDED]
- State: Georgia · Counties: Fulton + Cobb · Grades: K, G1, G2 · Subject: science · Catalog size: all GSE K–G2 science topics.
Trigger / cadence [DECIDED]
- Scheduled monthly batch job (cron) + parameterized invocation by
(state, county). Idempotent (skip already-validated counties). Not request-driven; never runs at order time.
Pacing guides [explained]
The standards (GSE) are statewide; a pacing guide is the district's order + timing for teaching them. It's the genuine per-county signal and powers the Bridge sequencing. [DECISION] Capture pacing as optional enrichment per county (don't block a topic's publish on having pacing).
Process (pipeline within the service)
- Discover the authoritative source [MODULE'S JOB — DECIDED 2026-06-03] — given
(state, subject), the module itself finds the official standards source (web search constrained to official domains:*.gadoe.org,georgiastandards.org,doe.k12.ga.us, district.orgsites). It does NOT rely on a human supplying URLs. The discovered source URL is carried through to the gate so the human can verify authenticity at Screen 3. (Discovery's fallibility is covered by the validation gate — not by pre-curating URLs by hand.) - Fetch + read — pull the discovered source for each grade. Prefer structured standards APIs (GA publishes via the CASE v1p1 API at
case.georgiastandards.org— machine-readable JSONCFPackage/CFItemwith codes + verbatim descriptions + change-dates); fall back to PDF parsing where no API exists. Verified GA registry:docs/specs/00-Curriculum-Sources-GA.md. - Enrich the pack — the standard code + description come verbatim from the official source; the LLM only adds kid-friendly title, learning objectives, key vocabulary, and misconceptions on top. It never authors the standard itself (provenance guarantee).
- Normalize + dedupe — collapse identical standards (trivial within one state; real across states later).
- Rank — order topics per grade (pilot: by standard sequence and/or county pacing).
- Draft catalog — write records with
status=draft+ the discovered source URL. - Human validation gate ⛔ (Screen 3) — a person reviews each topic and its source link and approves
→ published. Unvalidated topics are NOT sellable. This is where "is this an authentic source?" is answered — by the human, on the evidence the module surfaced. - Publish — bump
catalog_version; the catalog now offers the new/changed topics.
Source-discovery capability needed: the module needs a way to search the live web (e.g., OpenAI web-search tool / Responses API, or a search API) restricted to official domains. This is a Phase 2 build decision.
Output — the Topic Catalog (persisted to the real DB)
Per-topic record (proposed schema):
topic_id (stable id, e.g. ga_g2_sci_forces)
state, grade, subject
county / district (metadata; pacing source)
standard_code (e.g. S2P2) + standard_text
title (kid-friendly display name)
learning_objectives[]
key_vocabulary[]
misconceptions[]
pacing_hint? (per-county sequence/timing, optional)
source_url[] (authoritative citation)
status (draft | validated | published)
validated_by, validated_at
researched_at, catalog_version
- System of record: the DB (per the storage decision). A JSON export is emitted per run for human review/diffing.
- This IS the "full pack" Module 2 retrieves by
topic_id— no second research.
User Interface — standalone app, 3 screens [DECIDED 2026-06-03 · mockup: docs/mockup/curriculum-research-mockup.png]
Own branded UI ("Curriculum Service" header + a 3-step stepper Intake → Research → Final Topics), glass-box style, matching the operator-console aesthetic.
Screen 1 — Intake (the research request)
- Fields: State (dropdown, Georgia), County (multi-select chips — Fulton County, Cobb County), Grade (toggle set K / G1 / G2), Subject (dropdown, Science).
- Catalog status panel: per-grade current state so the operator knows what needs work — e.g. Kindergarten: Missing · Grade 1: Published v3 · Grade 2: Needs review.
- "Run research" CTA → starts the parameterized
(state, county)job.
Screen 2 — Glass-box research progress (the live machine)
- Progress bar with % + current phase label (e.g. "Finding pacing guides").
- Live activity feed: per-county research events streaming in real time.
- Topics found listed live as they arrive, each with standard, source citation, and pacing.
- Footer: "Next: vote and dedupe topics" → then the voting/dedupe plays out (topics from each county merge into one list with a vote count per topic + per-county pacing preserved).
Screen 3 — Final topics ready (the published catalog + validation gate)
- "Review the validated list… Ready to approve?" — grade tabs (K / G1 / G2).
- Table columns: Topic · Standard · Votes · Pacing · Source(link); already-published rows shown for context.
- This screen is the human validation gate: operator reviews each topic against its source/pacing, edits/rejects, then "Approve catalog" →
published. Only published topics are sellable. - This is the screen/data the Book Factory embeds for grade→topic selection (see Integration).
Integration with the Book Factory [DECIDED]
- The Book Factory (separate software) calls this service's API to fetch the published catalog filtered by grade, and renders the Screen-3 topic list inside the book intake (Module 1) for the buyer to pick a topic.
- The book flow never triggers research — it only reads published topics. The chosen
topic_id+catalog_versionflow into theCreationBrief; Module 2 retrieves the full pack by that id. - API (proposed):
POST /research(start a run for(state,county,grades)),GET /runs/{id}(Screen 2 live progress + topics + votes),GET /catalog?grade=(published topics — Screen 3 / book-flow integration),POST /topics/{id}/publish(finalize).
Tech [PROPOSED]
- Standalone software = backend + frontend, mirroring the operator-console pattern:
- Backend: Python (per the language-split ADR) — research pipeline + FastAPI for the 4 endpoints + its own database (SQLite to start; Postgres later). TDD.
- Frontend: Next.js 3-screen app (reuse the editorial design system + glass-box progress components already built).
- Layout [DECIDED]: research core + models + DB in a new Python package
services/curriculum-service/; expose its endpoints via the existingoperator-api(add a curriculum router); UI is a "Curriculum" section inside the existingoperator-console(reuse the design system + glass-box components). Logically standalone (own DB + pipeline), physically reuses the two existing apps. - Data source [DECIDED]: the module discovers the authoritative Georgia DOE science standards itself (web search restricted to official domains), fetches them, then LLM structures them into topics (objectives, vocabulary, misconceptions); stores the source URL per topic for the Screen-3 review. (Not LLM-from-memory; not human-curated URLs — discovery is the module's job, human verifies at the gate.)
Failure modes
- Hallucinated/outdated standard → mitigated by authoritative source + stored citation + the human gate.
- Source site changes/unavailable → job logs + retries next run; existing published catalog unaffected.
- Curriculum changes month to month →
catalog_versionpins each sold book to the catalog it used.
Resolved decisions (2026-06-03)
- Module number: 00 (first to build). This is standalone software (own UI + own DB).
- County treatment: full per-county research, parameterized
(state, county); pilot = Fulton + Cobb, GA. (Expect identical GSE topics across the two; pacing is the delta.) - Catalog size: all GSE K–G2 science.
- Approach: pre-research batch + store + human-validate (not on-demand).
- UI: 3 screens (Intake → glass-box research/voting/dedupe → finalized list). Validation gate lives on Screen 3 of this app (not the book operator console).
- Integration: the Book Factory calls this service's API and embeds the Screen-3 published list for topic selection.
- Pacing: optional enrichment per county.
Remaining open (small)
- Source-discovery capability: how the module searches the live web for official sources (OpenAI web-search tool / Responses API vs a dedicated search API). Phase 2 build decision.
- Exact DB engine (SQLite vs Postgres) — SQLite is fine to start.