CurioQuest

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:

  1. 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.
  2. Primary/official sources only — every claim cited to an official government/education domain; third-party/blog/summary sources rejected.
  3. Exact source URLs — master standards platform + per-grade document/node URLs; prefer structured standards APIs (CASE) over PDFs.
  4. Exact codes + verbatim descriptions — per grade, the official standard code + the official description text verbatim, each with its own source URL.
  5. Provenance dates — capture document/revision/lastChange/effective dates per source.
  6. District pacing with sequences — per-district teaching order across the year, with official district URLs + dates.
  7. Honest gaps — when something can't be verified from an official source, output "not found in an official source" — never guess or fabricate.
  8. 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)

  1. 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 .org sites). 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.)
  2. 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 JSON CFPackage/CFItem with codes + verbatim descriptions + change-dates); fall back to PDF parsing where no API exists. Verified GA registry: docs/specs/00-Curriculum-Sources-GA.md.
  3. 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).
  4. Normalize + dedupe — collapse identical standards (trivial within one state; real across states later).
  5. Rank — order topics per grade (pilot: by standard sequence and/or county pacing).
  6. Draft catalog — write records with status=draft + the discovered source URL.
  7. 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.
  8. 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_version flow into the CreationBrief; 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 existing operator-api (add a curriculum router); UI is a "Curriculum" section inside the existing operator-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_version pins 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.