CurioQuest

specs/02-Module-Functional-Specs.md

CurioQuest — Module Functional Specs

Goal: one finalized spec per module so we build the pilot end-to-end and output the first real illustrated book. Each block: Input → Output (real artifact contracts), Function, Method/AI, Gate, Failure modes, Build status (what's real vs stub today).

Legend — Method: SCRIPT (pure code, no AI) · LLM (gpt-4o text) · IMG (gpt-image-2) · VISION (gpt-4o vision). Gate: ⛔ = pipeline pauses for operator approve / regenerate / reject. Build status: ✅ real · 🟡 partial/stub · ❌ not done.

Pilot brief = Leo, age 7, G1→G2, topic s2p2_forces, Fulton County GA. Book = 24 pages, 7 narrative beats, preview = first ~5 pages (~20%).


Pipeline at a glance

Precondition (offline, scheduled): Module 0 — Curriculum Research populates the Topic Catalog that Intake + Curriculum-Resolve read from.

Per-book pipeline: Brief → [2 curriculum] → [3 lesson⛔] → [4 cast⛔] → [5 world⛔] → [6 outline] → [7 manuscript⛔] → [8 page-plan] → [9 page-specs⛔] → [10 image-prompt] → [11 generate-image] → [12 QC⛔] → [13 compose] → [14 assemble] → [15 editorial⛔] → [16 deliver]

Gates: 3, 4, 5, 7, 9, 12, 15 (7 total).


Module 0 — Curriculum Research & Topic Catalog (NEW — standalone, scheduled)

  • Method: scheduled agent (LLM + web research) · Runs: monthly on a schedule (not per-book) · Gate: ⛔ human validation before publish · Status: ❌ not built
  • Input: target scope — states → counties → grades → subject. Pilot scope [DECIDED]: Georgia, 3 counties (Fulton locked + 2 TBD), grades K / G1 / G2, subject science.
  • Output: Curriculum Topic Catalog (persisted to the real DB). Per topic record (proposed schema): topic_id, state, county, grade, standard_code, title, learning_objectives[], key_vocabulary[], misconceptions[], source_url[], prevalence(#counties), researched_at, validated_by, validated_at, status(draft|validated|published), catalog_version.
  • Function [DECIDED]: Research each county's science curriculum from authoritative sources, normalize + de-dupe across counties, rank topics by cross-county prevalence, and produce a per-grade topic list. This catalog feeds Module 1 (the grade→topic dropdown the buyer picks from) and Module 2 (the validated lesson pack).
  • Gate [PROPOSED — strong rec]: topics are human-validated before published to customers. Educational trust is the product; an agent's research cannot go live unreviewed (Project-Objective: content must be educator-validated). Each topic carries its source citation for review.
  • Failure modes: hallucinated/outdated standards → mitigated by authoritative sourcing + provenance + human gate; curriculum changes month-to-month → catalog_version pins each book to the catalog it used so in-flight/sold books don't break.
  • [DECIDED 2026-06-03] M0 produces the FULL validated pack per topic (objectives, vocabulary, misconceptions) — Module 2 just retrieves it by topic_id. One source of truth, no double-research.
  • ❓ OPEN: (a) which 2 counties beyond Fulton? (b) where does the monthly job run (infra/schedule)?

Module 1 — Intake (REVISED 2026-06-03)

  • Method: SCRIPT (+ reads M0 catalog) · Gate: none · Status: ✅ base real; 🟡 needs the revisions below
  • Input: the operator/buyer form (dynamic — topic options come from the M0 catalog).
  • Output: CreationBrief. Revised contract:
  • Hero [DECIDED]: hero_first_name, hero_age, pronouns, grade_mode toggle: grade (dropdown: Kindergarten | G1 | G2) OR grade_transition (dropdown: K→G1 | G1→G2). (Replaces the single grade_transition field.)
  • Appearance [DECIDED]: skin_tone, hair_color, hair_style, glasses, build? + new prop? — optional dropdown from a short curated list (e.g. school bag, toy car, soccer ball, teddy bear, water bottle, skateboard).
  • Interests [unchanged]: interests[≥1].
  • Supporting cast [DECIDED — optional]: friends[≤3] and pet?. Friend schema expanded to {name, age, ethnicity, hair_color, prop?} (was name+trait) so friends get the same character-consistency treatment as the hero. If the buyer enters no cast, Module 4 invents fitting cast from the story (not required input).
  • Guide [unchanged]: guide_type (+ details).
  • Curriculum & setting [DECIDED — major change]: Remove GSE/NGSS from the buyer's view (buyers don't know those terms). Instead: buyer picks grade → system suggests topics from the M0 catalog → buyer selects a topic. The standard_set/standard_code ride along behind the scenes (derived from the catalog, not user input). Keep city_region (roots the setting). language defaults English.
  • Format [DECIDED — pilot]: Pilot = digital only and single purchase (test case). digital+print and weekly_drip are post-pilot; print fulfillment intended via Printify (⚠️ TBD — contradicts frozen "NOT Printify / use Lulu-Gelato-Peecho"; revisit before building print).
  • Function: Validate the brief; serve grade-filtered topic options from the catalog; reject bad input with field-level errors.
  • [DECIDED 2026-06-03] Pilot is no-photo only — the photo-upload branch is dropped for the pilot (add post-pilot behind COPPA gates + 30-day delete).
  • [DECIDED 2026-06-03] Hero and friends keep separate appearance schemas (hero: skin_tone/hair/…; friend: name/age/ethnicity/hair_color/prop). Consistency pipeline (M4/M11/M12) must handle both shapes.

Module 2 — Curriculum Resolve

  • Method: SCRIPT · Gate: none · Status: ✅ (real GSE-G2 pack for s2p2_forces)
  • Input: CreationBrief.
  • Output: LessonSpectopic_code, standard_code, title, grade_band, learning_objectives[], key_vocabulary[].
  • Function: Look up the validated curriculum pack for the topic from the knowledge base (real standard code, objectives, vocabulary, misconceptions). No AI — this is the trusted, educator-validated source.
  • Failure modes: unknown topic code → hard fail (we only ship validated topics).
  • ❓ To finalize: For the pilot, which topics must exist in the pack? (Today: s2p2_forces. The 8-story Summer Bridge pack needs all 8 resolved.)

Module 3 — Lesson Design + Activity ⛔

  • Method: LLM x2 (gpt-4o) · Gate: ⛔ (one gate, shows both halves) · Status: ✅ built (2026-06-04)
  • Input: LessonSpec (enriched with misconceptions, standard_text, summary, catalog_version from M2).
  • Output (one gate, two artifacts):
  • LessonBlueprint{archetype, big_idea, clue_chain[], learning_check, reward{secret_code, badge_name}, activity_brief}.
  • ActivitySheet (NEW) — {title, hypothesis_question, materials[], steps[], expected_result, the_science, safety_notes[], parent_guidance, est_time_minutes, mess_level}.
  • Function (two sequential LLM calls under one gate):
  • Call 1LessonBlueprint: pick the mission archetype (Detective/Engineer/Explorer), the big idea in kid language, the clue chain (discovery beats), the in-narrative learning check, the reward unlocked by answering it (secret_code + badge_name), and a one-line activity_brief seeding the experiment.
  • Call 2ActivitySheet: derive a safe, household-item experiment grounded in Call 1's big_idea/clue_chain/activity_brief. Call 2 uses a dedicated safety-focused system prompt; the result is also run through the code-side banned-hazard checklist (book_factory.safety) before being accepted. The experiment is always derived from the story's concept, not invented independently.
  • Gate shows (6 cards): Blueprint (archetype + big idea) · Clue chain · Learning check + reward · Activity overview (seed, materials, time, mess) · Activity steps · Science + safety.
  • Safety: layered (defense in depth): (1) safety instructions in the Call-2 prompt; (2) required safety_notes[] + parent_guidance fields in the schema; (3) deterministic banned-hazard checklist that hard-blocks flame/blades/chemicals/electricity/heat/choking hazards before the operator ever sees the result; (4) operator confirms at the gate. On a hazard detection the pipeline raises SafetyViolation rather than gating.
  • Reward: secret_code is a short fun word/number unlocked by answering the learning check; badge_name is a collectible badge themed to the archetype/topic. Both LLM-generated alongside the blueprint.
  • Steering feedback: operator may type a note before hitting Regenerate ("pick Engineer archetype", "less messy activity"); the note is injected into both call prompts on the re-run.
  • Failure modes: LLM returns off-schema JSON → retry/repair; banned hazard in derived activity → SafetyViolation → operator must regenerate; archetype mismatch to topic type.
  • Downstream contract: LessonBlueprint feeds M6 (Narrative Outline); ActivitySheet feeds M8 (ACTIVITY page role) + M7 (learning check placement); reward surfaces on the LEARNING_CHECK page (M8/M13).

Module 4 — Cast Definition ⛔

  • Method: LLM + IMG · Gate: ⛔ · Status: ✅ text real; 🟡 reference image real but consistency not solved
  • Input: CreationBrief.
  • Output: CharacterCastitems: CharacterSheet[] where each = {character_id, role(HERO|GUIDE|FRIEND|PET), name, description, reference_image(ImageRef)}. Must contain exactly 1 hero + 1 guide.
  • Function: Write each character's visual + personality description (hero = the child, guide = Professor T-Rex by default) and generate a locked reference image per character to anchor visual consistency across all pages.
  • Gate shows: each character's description + reference image (image grid).
  • Failure modes: missing hero/guide → contract violation; reference image off-model.
  • ❓ To finalize: This is the hard one. How do we lock character consistency across 24 pages (the M2 problem)? Reference-image passing is best-effort today. Acceptable for pilot, or must-solve?

Module 5 — World Design ⛔

  • Method: LLM + IMG · Gate: ⛔ · Status: ✅ text real; 🟡 style ref real, consistency best-effort
  • Input: CreationBrief.
  • Output: LocationSetitems: LocationSheet[] where each = {location_id, name, description, style_ref(ImageRef)}.
  • Function: Describe the story's settings (rooted in city_region) and generate style-reference art for visual consistency of backgrounds.
  • Gate shows: each location description + style ref (image grid).
  • ❓ To finalize: How many locations per book? Driven by the outline, or fixed set?

Module 6 — Narrative Outline

  • Method: LLM · Gate: none · Status: ✅ real
  • Input: LessonBlueprint.
  • Output: NarrativeOutlinebeats: Beat[] exactly 7, each {index(1–7), title, summary}.
  • Function: Produce the 7-beat arc (Spark → Call → Wrong-Idea → Investigation → Reveal → Win → Hand-Off) carrying the clue chain.
  • ❓ To finalize: Is 7 beats fixed for all books? Confirm the beat template.

Module 7 — Manuscript ⛔

  • Method: LLM · Gate: ⛔ · Status: ✅ real + personalized (reads hero name/pronouns/interests)
  • Input: NarrativeOutline (+ cast + brief for personalization).
  • Output: Manuscript{title, segments: ManuscriptSegment[]}, each segment {beat_index, narration, dialogue[]{speaker,text}}.
  • Function: The core creative gen — write the actual narration + dialogue per beat, personalized to the child, embedding the learning check and tagging vocabulary.
  • Gate shows: title + each beat's narration & dialogue (text). This is the most important gate.
  • Failure modes: reading level too high; learning check missing; hero details ignored.
  • ❓ To finalize: Reading-level target for G1→2? Word-count band per beat? Must the learning-check question appear verbatim?

Module 8 — Page Plan

  • Method: LLM · Gate: none · Status: ✅ real
  • Input: Manuscript.
  • Output: PagePlanpages: PagePlanEntry[] exactly 24, each {page_number, page_role(COVER|STORY|LEARNING_CHECK|BACK), beat_index(nullable), manuscript_text}.
  • Function: Distribute the 7 beats across the 24-page template (cover, story pages, the learning-check page, back).
  • ❓ To finalize: Confirm the 24-page template structure (how many cover/story/check/back pages).

Module 9 — Page Specs ⛔

  • Method: LLM · Gate: ⛔ · Status: ✅ real
  • Input: PagePlan + CharacterCast + LocationSet.
  • Output: PageSpecsitems: PageSpec[] (24), each {page_number, page_role, scene, composition, on_page_text, character_ids[], location_id, props[]}.
  • Function: For each page, decide the scene, the composition, the exact on-page text, which characters/location/props appear.
  • Gate shows: per-page scene + on-page text (24 rows).
  • ❓ To finalize: Anything beyond scene/composition/text needed per page (e.g., camera/shot type, emotion)?

Module 10 — Image Prompt

  • Method: SCRIPT (deterministic by design) · Gate: none · Status: ✅ logic real; prompt text to tune
  • Input: PageSpecs + CharacterCast.
  • Output: ImagePromptBatchitems: ImagePromptPayload[] (24), each {page_number, prompt, reference_image_paths[], negative_prompt}.
  • Function: Assemble each page's image prompt deterministically ("Sandwich Method": fixed style + scene + locked character refs) so results are reproducible.
  • ❓ To finalize: The prompt template wording (style descriptors, negative prompt) — needs tuning against real gpt-image-2 output.

Module 11 — Generate Image

  • Method: IMG (gpt-image-2) · Gate: none · Status: ✅ real (writes PNG bytes); ❗never finished a full 24-page run
  • Input: ImagePromptBatch.
  • Output: PageImagesitems: PageImage[] (24), each {page_number, image(ImageRef), prompt_used}. PNGs on disk.
  • Function: Generate each page's artwork via gpt-image-2, passing reference anchors. No fallback — if gpt-image-2 is unavailable the run stops.
  • Failure modes: model unavailable → hard stop; rate limit; partial batch (the known gap — 19 PNGs then died).
  • ❓ To finalize: Retry/backoff policy; how to resume a partial batch without regenerating all 24 (cost).

Module 12 — Consistency & Safety QC ⛔

  • Method: VISION + SCRIPT · Gate: ⛔ · Status: 🟡 light check only (full consistency = later/M2)
  • Input: PageImages + CharacterCast.
  • Output: PageQCReportitems: PageQC[] (24), each {page_number, consistency_score(0–1), consistency_pass, safety_pass, notes}; all_passed property.
  • Function: Vision-compare each page to the locked character refs (consistency) and check child-safety; flag failures; loop back to regenerate on fail (max N retries, then human flag).
  • Gate shows: per-page consistency score + pass/fail + safety + notes.
  • ❓ To finalize: Consistency score threshold to auto-pass? Max auto-retries before human flag? Safety check definition for pilot.

Module 13 — Compose Page

  • Method: SCRIPT · Gate: none · Status: 🟡 passthrough (no real text-on-image layout yet)
  • Input: PageImages + PageSpecs.
  • Output: FinishedPagesitems: FinishedPage[] (24), each {page_number, composed_image(ImageRef)}.
  • Function: Place the on-page text onto the page image per the layout template.
  • ❓ To finalize: Text placement rules (where text sits, font, safe margins). Currently the image passes through without text composited — needs real layout for a shippable book.

Module 14 — Assemble Book

  • Method: SCRIPT · Gate: none · Status: ✅ embeds real PNGs + Unicode font; produces PDF
  • Input: FinishedPages + PageSpecs + Manuscript.
  • Output: Book{title, full_pdf_path, preview_pdf_path, page_count, preview_page_count}.
  • Function: Render the full print-ready PDF + the ~20% preview PDF (first ~5 pages).
  • ❓ To finalize: Print specs (page size, bleed, DPI) for the POD vendor; preview page count (5? cover+3?).

Module 15 — Editorial QC ⛔

  • Method: LLM · Gate: ⛔ · Status: ✅ real
  • Input: Book + Manuscript.
  • Output: EditorialReport{accuracy_pass, reading_level_ok, engagement_pass, notes}; approved requires all true.
  • Function: Final whole-book read-through — curriculum accuracy, reading level, narrative coherence, engagement, no banned content.
  • Gate shows: the four pass/fail flags + notes.
  • ❓ To finalize: What does each check actually assert? Hard-block on which failures?

Module 16 — Deliver

  • Method: SCRIPT (+ commerce) · Gate: none · Status: 🟡 stub (no real commerce; Sheet ledger now cancelled)
  • Input: Book.
  • Output: DeliveryManifest{listing_id, channel, status(PUBLISHED|QUEUED|FAILED), book_path, preview_path}.
  • Function: Register the finished book, publish the listing, wire badge/secret-code, unlock digital on purchase, trigger POD.
  • DECIDED (PRD): persists to the real DB (system of record); Shopify owns checkout/POD; Google Sheet dropped.
  • ❓ To finalize: For the pilot (concierge, manual sale) — what does "deliver" minimally do? Just record + produce the PDF for manual sharing?

Open cross-cutting questions (block "first book today")

  1. Character consistency (M4/M11/M12): the hard problem. Pilot-acceptable as best-effort, or must-improve before book 1?
  2. Page composition (M13): needs real text-on-image layout to be a shippable book — today it's a passthrough.
  3. Partial-batch resume (M11): so a died run doesn't re-bill all 24 images.
  4. Reading level + word bands (M7): the quality bar for the prose.

What's already TRUE end-to-end (so we're not starting from zero)

  • Steps 2–16 run end-to-end; 193 factory tests + 30 API tests green.
  • 8 LLM steps + image gen + PDF assembly are wired to real OpenAI.
  • The operator console runs it with the 7 gates working (built + browser-verified this session).
  • Gap to first real book: finish one full real run with images (steps 11→14) without dying, and give M13 real text layout.