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.
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.
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.
Section 05 (SCS algorithm) and Section 06 (celebrations) describe how clinical decisions become runtime behavior. Verify these preserve the intent from M1-003.
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.
Meadow is built in four layers. Views talk to engines. Engines talk to services. Services talk to data. Nothing skips a layer.
All domain value types are Sendable. All engine types are @MainActor. Swift 6 strict concurrency — no sendability warnings, no data races.
Vocabulary and scene data are bundled JSON, decoded at launch. Only user preferences and event logs are persisted via SwiftData. No network calls, ever.
F1 (engine-first) work has already laid the foundation. M2 completes the runtime and adds views.
FitzgeraldKey, Tier, CenterStageMode, VocabularyData (full JSON codable), SceneManifest, TierMapping (118 words), CompassLayout (50+ positions), SpeechBubbleState, NavigationState, UserProfile, EventRecord, RoutineConstants
MeadowTTSEngine (AVSpeechSynthesizer, rate 0.45, pitch 1.2), MeadowNavigationEngine (routine/mode/overlay state machine), MeadowEventLogger (SwiftData-backed), all protocols defined
VocabularyService, ParentGateService, SCS conversation engine, celebration system, avatar system, all views, onboarding flow, accessibility infrastructure, content for Kitchen scene
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.
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.
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.
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.
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.
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 |
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.
New data format needed for the conversation engine. Added to the vocabulary JSON as a top-level scsFollowUps array.
| Pragmatic Function | Description | Example |
|---|---|---|
requesting | Asking for something | "I want banana" |
protesting | Refusing or rejecting | "no banana" |
commenting | Observing or describing | "yummy banana!" |
greeting | Social acknowledgment | "hi Mommy" |
asking | Seeking information | "where banana?" |
feeling | Expressing emotion | "I happy" |
social | Connection and closeness | "I love you" |
directing | Telling someone to act | "open please" |
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.
Given a word the child just spoke, how the engine picks 3 follow-up suggestions.
| Step | Logic |
|---|---|
| 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 (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 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.
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 | Probability | Cooldown |
|---|---|---|
| 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 spoken | 100% | none |
| First sentence completed | 100% | none |
| First new scene explored | 100% | none |
| 10th word in a session | 100% | none |
| Rule | Value |
|---|---|
| Max duration | 2.5 seconds |
| Blocks input? | No — child can tap through |
| Animation type | Particle burst + haptic |
| Sound | Short chime (< 1s), respects mute |
| Intensity levels | 3 (subtle / medium / full) |
| Configurable by parent | Yes — intensity and on/off |
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.
Every budget is a pass/fail gate. "It feels fast" is not a budget. These are numbers.
| Metric | Target | How 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 |
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.
Tests verify the specification, not the implementation. Every test must trace to a requirement from M1-001 through M1-005.
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
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
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 | Usage | Required 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 |
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.
Each criterion is a pass/fail statement. If the answer is "it depends" or "sort of," it fails.
| ID | Deliverable | Testable 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. |
What gets built first and why. Later items depend on earlier ones.
VocabularyService (JSON loading, tier filtering), ParentGateService, profile setup data layer. These have no UI dependency.
Scene view, grid view, compass frame layout, core word bar. These depend on VocabularyService and NavigationEngine.
SCS conversation engine, celebration system, avatar overlay. These depend on views being in place to receive output.
Onboarding flow, parent gate UI, accessibility pass, performance validation on iPad 9 hardware.
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 (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.
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.
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.
| Risk | Impact | Mitigation |
|---|---|---|
| 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. |
These questions must be answered before M2 can fully close. They don't block M2 start, but they block M2 acceptance.
| Question | Blocking | Default 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 |