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_versionpins 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) ORgrade_transition(dropdown: K→G1 | G1→G2). (Replaces the single grade_transition field.) - Appearance [DECIDED]:
skin_tone, hair_color, hair_style, glasses, build?+ newprop?— 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]andpet?. 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. Thestandard_set/standard_coderide along behind the scenes (derived from the catalog, not user input). Keepcity_region(roots the setting).languagedefaults English. - Format [DECIDED — pilot]: Pilot =
digitalonly andsinglepurchase (test case).digital+printandweekly_dripare 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:
LessonSpec—topic_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 1 →
LessonBlueprint: 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-lineactivity_briefseeding the experiment. - Call 2 →
ActivitySheet: derive a safe, household-item experiment grounded in Call 1'sbig_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_guidancefields 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 raisesSafetyViolationrather than gating. - Reward:
secret_codeis a short fun word/number unlocked by answering the learning check;badge_nameis 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:
LessonBlueprintfeeds M6 (Narrative Outline);ActivitySheetfeeds 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:
CharacterCast—items: 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:
LocationSet—items: 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:
NarrativeOutline—beats: 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:
PagePlan—pages: 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:
PageSpecs—items: 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:
ImagePromptBatch—items: 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:
PageImages—items: 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:
PageQCReport—items: PageQC[](24), each{page_number, consistency_score(0–1), consistency_pass, safety_pass, notes};all_passedproperty. - 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:
FinishedPages—items: 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};approvedrequires 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")
- Character consistency (M4/M11/M12): the hard problem. Pilot-acceptable as best-effort, or must-improve before book 1?
- Page composition (M13): needs real text-on-image layout to be a shippable book — today it's a passthrough.
- Partial-batch resume (M11): so a died run doesn't re-bill all 24 images.
- 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.