Meadow  /  M1-007

Phase 2 Build Specification

Everything engineering needs to start building the moment M1 closes — without inventing missing product logic.
M1-007
v1.0 · May 2026
Deliverable for: M1 Sign-off
01 Executive Summary

What this document does

This is the engineering translation of M1-001 through M1-005. It takes every design decision — vocabulary, interaction model, onboarding, visual direction — and converts it into a buildable specification: data structures, algorithms, performance targets, and testable acceptance criteria.

After M1 approval, this document is the contract between product and engineering. If a behavior isn't described here, engineering will ask — not guess.

For AbleNet

Sections 01, 09, and 10 are written for you. The rest is engineering detail you can skip — but it's here if you want to verify that the design decisions you approved are faithfully translated.

For Engineering

Sections 02–08 are your build contracts. Data model, engine specs, algorithms, performance budgets, and test strategy. If it's not here, it's not in scope for M2.

For SLP Reviewers

Section 05 (SCS algorithm) and Section 06 (celebrations) describe how clinical decisions become runtime behavior. Verify these preserve the intent from M1-003.

Phase 2 at a glance

M2Engine Foundation
M3Kitchen Scene Complete
12M2 deliverables, 6 M3 deliverables
iPad 9minimum target hardware (A13, 3GB RAM)

What the client sees at M2 review: A TestFlight build on a real iPad. Navigation works. Tapping words speaks them. The SCS loop runs. The parent gate locks settings. VoiceOver announces every element. No final art — placeholder symbols only.

What the client sees at M3 review: The Kitchen scene at full fidelity — final illustrations, 100+ vocabulary items, sentence templates, SCS follow-ups, celebrations, and a complete child flow from entry to conversation.

02 Architecture Overview

System layers

Meadow is built in four layers. Views talk to engines. Engines talk to services. Services talk to data. Nothing skips a layer.

VIEWS SceneView · GridView · AvatarOverlay · OnboardingFlow · SettingsSheet · CompassFrame ENGINES — @Observable, @MainActor NavigationEngine · TTSEngine · SCSEngine · CelebrationEngine · SpeechBubbleState SERVICES — Protocol-oriented, injectable VocabularyService · ParentGateService · EventLogger · ProfileService BUNDLED JSON — read-only meadow-vocabulary.json · scene manifests SWIFTDATA — read/write UserProfile · EventRecord
Key constraint

All domain value types are Sendable. All engine types are @MainActor. Swift 6 strict concurrency — no sendability warnings, no data races.

Key constraint

Vocabulary and scene data are bundled JSON, decoded at launch. Only user preferences and event logs are persisted via SwiftData. No network calls, ever.

What's already built vs. what M2 adds

F1 (engine-first) work has already laid the foundation. M2 completes the runtime and adds views.

Built

Foundation models

FitzgeraldKey, Tier, CenterStageMode, VocabularyData (full JSON codable), SceneManifest, TierMapping (118 words), CompassLayout (50+ positions), SpeechBubbleState, NavigationState, UserProfile, EventRecord, RoutineConstants

Built

Core engines

MeadowTTSEngine (AVSpeechSynthesizer, rate 0.45, pitch 1.2), MeadowNavigationEngine (routine/mode/overlay state machine), MeadowEventLogger (SwiftData-backed), all protocols defined

M2 scope

Still needed

VocabularyService, ParentGateService, SCS conversation engine, celebration system, avatar system, all views, onboarding flow, accessibility infrastructure, content for Kitchen scene

03 Data Model

Entity map

Every piece of data Meadow stores or reads, grouped by storage type. Bundled JSON is read-only content shipped in the app. SwiftData is user-specific state persisted on-device.

VocabularyData Bundled JSON
schemaString
versionString
countsVocabCounts
fitzgeraldKey[String: FKDef]
coreVocabulary[CoreWord]
scenes[String: SceneVocab]
routines[RoutineDefinition]
sentenceTemplates[TemplateLevel]
CoreWord Bundled JSON
wordString
emojiString
fitzgeraldKeyFitzgeraldKey
groupString
projectCoreWordBool
SceneWord Bundled JSON
wordString
emojiString
fitzgeraldKeyFitzgeraldKey
zoneString
SceneManifest Bundled JSON
sceneIdString
routineString
backgroundString
labelDefaultBool
objects[SceneObject]
SceneObject Bundled JSON
idString
wordString
typeflat | container
tierTier
fitzgeraldKeyFitzgeraldKey
position{x, y}
size{w, h}
children[ChildObject]?
SentenceTemplate Bundled JSON
levelInt (1–3)
mluString
ageRangeString
patterns[Pattern]
SentencePattern Bundled JSON
patternString
functionString
exampleString
SCSFollowUp Bundled JSON — new
triggerWordString
sceneString?
phraseString
pragmaticFunctionPragmaticFn
tierMinimumTier
UserProfile SwiftData
tierLevelInt (default 1)
speechBubbleTimeoutDouble (12.0s)
showLabelsBool (false)
categoryDismissTimeoutDouble (5.0s)
childNameString
childAgeMonthsInt
voiceIdString
speechRateDouble (0.85)
expectantPauseDurationDouble
celebrationIntensityInt (1–3)
parentGatePINString?
hasCompletedOnboardingBool (false)
EventRecord SwiftData
timestampDate
eventTypeString
wordString?
sceneString?
tierLevelInt?
New entity: SCSFollowUp

The SCS follow-up data doesn't exist yet in the vocabulary JSON. It needs to be authored as part of the content pipeline (Section 08). Each follow-up ties a trigger word to a response phrase with a pragmatic function tag. Kitchen alone needs approximately 200–300 follow-up entries.

04 Content Format & Pipeline

How vocabulary gets into the app

Meadow's vocabulary is authored as JSON, validated against a schema, and shipped in the app bundle. There is no CMS, no API, no runtime content loading. Updating vocabulary means updating the JSON and shipping a new app version.

Current state

meadow-vocabulary.json exists with 74 core words (17 at T1, 52 at T2, 74 at T3) and 260+ scene words across 5 routines, totaling 400+ vocabulary items. Sentence templates cover 3 tier levels. This is the canonical vocabulary file.

What's missing

SCS follow-ups — the conversation continuation data. Each vocabulary item needs 2–4 follow-up suggestions tagged by pragmatic function. This is the largest content authoring task in M2/M3.

Content authoring pipeline

Who creates what, in what order, and how it gets validated.

Content Author Validator Format When
Core word list Developer (from M1-002) SLPs (M1-006) JSON array in vocabulary file Done — 78 words
Scene words Developer (from M1-002) SLPs JSON per-scene in vocabulary file Done — 256 words, 5 scenes
Sentence templates Developer (from M1-003) SLPs JSON tier-leveled patterns Done — 3 tier levels
SCS follow-ups Developer + SLP review SLPs JSON keyed by trigger word + scene Not started — M3 blocker
Scene manifests Developer Visual QA JSON per-scene with object positions Schema defined, Kitchen needed for M3
Illustrations AI generation (Codex prompts) Developer + AbleNet PNG/SVG in Assets.xcassets After art direction approval (M1-004)
Avatar phrases Developer + SLP review SLPs JSON per-scene context list Not started — M2 scope
Art pipeline — throughput estimate

Kitchen scene needs approximately 40–60 distinct illustrations (background, 6+ zone backgrounds, 100+ vocabulary item images). At AI generation rates, expect 3–5 images per prompt session. A full scene is roughly 2–3 days of focused generation and consistency review. This becomes the pacing constraint for M3 and M4.

SCS follow-up JSON schema

New data format needed for the conversation engine. Added to the vocabulary JSON as a top-level scsFollowUps array.

// Added to meadow-vocabulary.json "scsFollowUps": [ { "triggerWord": "banana", "scene": "kitchen", "phrase": "I want banana", "pragmaticFunction": "requesting", "tierMinimum": 2 }, { "triggerWord": "banana", "scene": "kitchen", "phrase": "yummy banana!", "pragmaticFunction": "commenting", "tierMinimum": 2 }, { "triggerWord": "banana", "scene": null, "phrase": "more banana", "pragmaticFunction": "requesting", "tierMinimum": 1 } ]
Pragmatic FunctionDescriptionExample
requestingAsking for something"I want banana"
protestingRefusing or rejecting"no banana"
commentingObserving or describing"yummy banana!"
greetingSocial acknowledgment"hi Mommy"
askingSeeking information"where banana?"
feelingExpressing emotion"I happy"
socialConnection and closeness"I love you"
directingTelling someone to act"open please"
05 SCS Conversation Engine

Speak → Choose → Speak loop

The core communication pattern for Tier 2 and Tier 3 children. Child taps a word, it speaks, three follow-up suggestions appear. Child taps one, it speaks, new follow-ups appear. The loop continues until the child navigates away or the speech bubble times out.

Child taps "banana" TTS speaks "banana!" 3 follow-ups "I want banana" "yummy banana!" "more banana" Child taps follow-up loop continues

Follow-up selection algorithm

Given a word the child just spoke, how the engine picks 3 follow-up suggestions.

StepLogic
1. Collect candidates All SCSFollowUp entries where triggerWord matches the spoken word AND tierMinimum ≤ child's tier. Prefer scene-specific entries (matching current scene) over scene-null (universal) entries.
2. Diversify by function Group candidates by pragmaticFunction. Select one candidate from each of up to 3 different functions. Priority order: requesting, commenting, then rotate through remaining functions.
3. Avoid repetition If the child has tapped the same trigger word in the last 3 SCS cycles, deprioritize previously shown follow-ups. Shuffle within function groups to provide variety.
4. Fallback If fewer than 3 candidates exist, pad with scene-null (universal) follow-ups for the same trigger word. If still fewer than 3, pad with generic pragmatic phrases ("more [word]", "no [word]", "[word] please") auto-generated from the sentence templates.
Tier 1 behavior

Tier 1 (First Words) does NOT run the SCS loop. Tapping a word speaks it immediately with no follow-ups. The companion may offer an expectant pause, but there are no conversation continuations. This is intentional — pre-verbal children at this stage communicate through single-word utterances.

Tier 2 vs Tier 3

Tier 2 shows 2-word follow-ups ("want banana", "more milk"). Tier 3 shows 3-word follow-ups ("I want banana", "give me milk"). The tierMinimum field on each follow-up controls which phrases appear at which tier.

06 Celebration & Reward System

Variable-ratio celebration algorithm

Celebrations should feel surprising and delightful, not predictable. The system uses a variable-ratio schedule inspired by behavioral reinforcement — the child never knows when the next celebration will come, which maintains engagement without creating dependency.

Trigger rules

TriggerProbabilityCooldown
Any word tap (Tier 1)20%5 events min
Any word tap (Tier 2)15%5 events min
Any word tap (Tier 3)10%5 events min
First word ever spoken100%none
First sentence completed100%none
First new scene explored100%none
10th word in a session100%none

Presentation rules

RuleValue
Max duration2.5 seconds
Blocks input?No — child can tap through
Animation typeParticle burst + haptic
SoundShort chime (< 1s), respects mute
Intensity levels3 (subtle / medium / full)
Configurable by parentYes — intensity and on/off
Clinical note

Celebrations must NEVER interrupt a communication act in progress. If the child is mid-SCS loop (follow-ups visible), the celebration queues until the current exchange completes or times out. Communication always takes priority over reward.

07 Performance Budgets

Measurable targets — tested on iPad 9 hardware

Every budget is a pass/fail gate. "It feels fast" is not a budget. These are numbers.

MetricTargetHow to measure
App launch to interactive ≤ 2.0 seconds Instruments Time Profiler — first frame with tappable content
Word tap to speech onset ≤ 400ms Timestamp delta: touch event → AVSpeechSynthesizer didStart callback
Scene transition ≤ 300ms to first content Navigation state change → scene objects rendered
SCS follow-up appearance ≤ 200ms after speech starts Follow-up buttons visible within one frame of speech onset
Memory ceiling (sustained use) ≤ 250 MB after 30 min Instruments Allocations — 30 minutes of active tapping across 3+ scenes
Touch response (any tappable element) ≤ 100ms visual feedback Touch down → visual state change (highlight, scale, or color shift)
Vocabulary JSON decode ≤ 200ms for full file JSONDecoder time on iPad 9 with production vocabulary file
Animation frame rate ≥ 55 fps during celebrations Core Animation Instruments — no dropped frames during particle bursts
No crashes 0 crashes in 60 min continuous use Manual testing session on iPad 9 hardware
iPad 9 constraint

The A13 chip is roughly 3× slower than A16. All performance budgets are validated on iPad 9, not simulator. Simulator performance is not a proxy — pass on simulator does not mean pass on hardware.

08 Test Strategy

Three layers of testing

Tests verify the specification, not the implementation. Every test must trace to a requirement from M1-001 through M1-005.

Unit tests — Swift Testing

Model logic, engine behavior, service contracts. Run on every build. Target: 100% coverage of engine and service logic. No network, no UI, no device dependency.

Framework: @Suite, @Test, #expect

Run: xcodebuild test in CI and local

UI tests — XCTest

End-to-end flows: onboarding completion, word tap → speech, SCS loop, parent gate lock/unlock, scene navigation. Run on iPad Air simulator.

Framework: XCUIApplication

Run: xcodebuild test with UI test scheme

Accessibility audit — XCTest

Every screen runs performAccessibilityAudit(). Catches missing labels, insufficient contrast, touch target violations, and VoiceOver ordering errors.

Pass bar: Zero audit failures

Run: Included in UI test suite

Device matrix

DeviceUsageRequired for pass
iPad Air 11" (M4) Simulator All automated tests (unit, UI, accessibility) Yes — every build
iPad Mini Simulator Layout validation — touch targets, overflow, orientation Yes — before milestone review
iPad 9 (physical hardware) Performance validation and manual testing Yes — before milestone review
Pass bar definition

M2 passes when: All unit tests green, all UI tests green, all accessibility audits green, all performance budgets met on iPad 9, and a 30-minute manual testing session on hardware produces zero crashes and zero blocked communication flows.

09 M2 Acceptance Criteria

Testable criteria for every M2 deliverable

Each criterion is a pass/fail statement. If the answer is "it depends" or "sort of," it fails.

IDDeliverableTestable acceptance criteria
M2-001 Navigation state machine Navigate Scene → Zone → Sub-zone → Item to depth 3. Press back at each level and return to previous state. Breadcrumb updates on every navigation. State survives app backgrounding (no loss on return). Tested on Kitchen scene structure.
M2-002 Communication board Swipe gesture toggles between scene view and grid view. Grid shows all core words visible at child's tier. Words are Fitzgerald Key color-coded. Tapping any word speaks it via TTS. Board state persists across scene changes.
M2-003 Sentence template engine Given a vocabulary item and the child's tier, the engine produces grammatically appropriate 2–3 word combinations. Tier 1 produces single words only. Tier 2 produces 2-word combos. Tier 3 produces 2–3 word combos. At least one template exists for every Kitchen vocabulary item.
M2-004 SCS conversation loop After tapping a Tier 2+ word: speech fires, 3 follow-up suggestions appear within 200ms. Tapping a follow-up speaks it and generates new follow-ups. Follow-ups span at least 2 different pragmatic functions. Loop runs for at least 5 consecutive exchanges without error. Speech bubble clears after 12-second timeout.
M2-005 Text-to-speech Any word tap produces audible speech within 400ms on iPad 9. Tapping a new word while speech is playing interrupts and speaks the new word. Speech rate matches UserProfile setting (default 0.85×). Works with device on silent (via audio session category). No TTS crash on rapid sequential taps (10 taps in 2 seconds).
M2-006 Core word bar Bar visible on every screen (scene view, grid view, overlays). Shows only words at or below the child's tier level. "I love you" is always visible regardless of tier or settings. Tapping any bar word speaks it and adds to speech bubble. Bar does not scroll off-screen or overlap content.
M2-007 Avatar system Avatar tappable from every screen. Opens feelings tray with context-appropriate phrases for current scene. Tapping any feeling speaks it immediately — no SCS loop. "I love you" fires from avatar or dedicated button. Avatar dismisses on outside tap or after 5-second timeout.
M2-008 Parent gate Settings gear is unresponsive to single-finger taps. Two-finger hold for 3 seconds opens gate (gear spins slowly as feedback). If PIN is set, large number pad PIN screen appears after gesture. 3 failed PIN attempts trigger 30-second cooldown. Settings accessible after passing gate. Gate re-engages after configurable timeout (5 / 10 / 30 min / never auto-lock).
M2-009 Child profile setup First launch shows onboarding. Child name, age, voice, and tier selected in under 60 seconds. Profile persists across app restarts. Age-derived defaults populate correctly per onboarding spec defaults table. Skipping optional fields completes setup with sensible defaults.
M2-010 Event logger Every word tap, speech output, navigation action, scene entry, and SCS follow-up selection creates an EventRecord in SwiftData. Records include timestamp, event type, word (if applicable), scene, and tier. 1000+ events do not degrade app performance. Events are queryable by date range and type.
M2-011 Celebration system Celebrations fire on variable-ratio schedule (not every tap, not on fixed interval). Milestone celebrations always fire (first word, first sentence, first scene, 10th word). Celebrations last ≤ 2.5 seconds. Child can tap through celebrations — they never block communication. Celebrations are configurable (intensity 1–3 or off) via parent settings. Animation maintains ≥ 55 fps.
M2-012 Accessibility infrastructure VoiceOver announces every tappable element with a meaningful label (not "button" or "image"). Switch Control can navigate all interactive elements. Touch targets are ≥ 60pt on shortest dimension (72pt for Tier 1 per M1-003). performAccessibilityAudit() passes on every screen. Dynamic Type does not break layout at accessibility sizes.
10 Build Sequence

M2 dependency order

What gets built first and why. Later items depend on earlier ones.

Wave 1 · Week 1–2

Foundation services

VocabularyService (JSON loading, tier filtering), ParentGateService, profile setup data layer. These have no UI dependency.

Wave 2 · Week 2–3

Core views

Scene view, grid view, compass frame layout, core word bar. These depend on VocabularyService and NavigationEngine.

Wave 3 · Week 3–4

Interaction engines

SCS conversation engine, celebration system, avatar overlay. These depend on views being in place to receive output.

Wave 4 · Week 4–5

Polish & gates

Onboarding flow, parent gate UI, accessibility pass, performance validation on iPad 9 hardware.

Timeline assumption

This 5-week estimate assumes M1 closes by early June, art direction is decided, and no major design revisions emerge from the SLP review. If SLP feedback requires vocabulary restructuring, add 1–2 weeks to Wave 1.

M3 follows immediately after M2 acceptance

M3 (Kitchen Scene Complete) adds content depth to the M2 engine. It does not introduce new architecture — it fills the Kitchen scene with final illustrations, full vocabulary depth, SCS follow-ups for every item, and scene-specific avatar phrases. Estimated 3–4 weeks, dominated by art generation throughput.

M3 content requirements

6+ kitchen zones with full vocabulary. 100+ distinct vocabulary items. 200–300 SCS follow-up entries. 40–60 illustrations. Scene-specific avatar phrases. Sentence templates for every item.

M3 blockers

Art direction must be chosen (M1-004) before illustration pipeline starts. SCS follow-ups must be authored — this is the largest content task. SLP validation of Kitchen vocabulary coverage (M1-006) should happen before or during M3.

11 Risks & Open Questions

Known risks

RiskImpactMitigation
SLP access delayed M1-006 can't close. M1 approval delayed. M2 start slips. M2 can start on engine work while SLP review runs in parallel. Vocabulary changes from SLP feedback get incorporated in M3.
Art pipeline bottleneck M3 (Kitchen) delayed. Cascading delays to M4–M5. Start art generation immediately after direction approval. Use placeholder symbols for M2 to decouple engine from art.
iPad 9 performance Celebration animations or large scenes exceed memory/CPU budget. Profile early on hardware. Keep celebration particle count configurable. Set hard memory ceiling alarm at 200MB.
SCS follow-up content volume 200–300 entries per scene is substantial authoring work. Use sentence templates to auto-generate baseline follow-ups. SLP review validates and refines, not authors from scratch.
Apple Kids Category rejection App Store submission blocked at M5. Review Apple guidelines during M2 and build to compliance from the start. No analytics, no ads, no external links, no account creation.
No real child testing Design assumptions unvalidated by actual target users before launch. SLP proxy testing during M3. Caregiver beta testers via TestFlight during M4. Post-launch feedback loop planned.

Open questions requiring M1 approval

These questions must be answered before M2 can fully close. They don't block M2 start, but they block M2 acceptance.

QuestionBlockingDefault if unanswered
Which art direction? (Soft Crayon / Chalkboard / Bright & Bubbly / Gouache) M3 start None — cannot proceed without choice
Is "Meadow" the confirmed product name? M5 (App Store listing) Use "Meadow" as working name, finalize before M5
Will AbleNet facilitate SLP reviewers or just provide a contact list? M1-006 timeline Developer reaches out directly with AbleNet introduction
Does AbleNet want TestFlight access during M2, or only at milestone review? Distribution setup Provide TestFlight access at milestone review only