MAINICHI / ENGINEERING

Making an AI tutor
dependable on iOS.

AI powers Mainichi’s personalized lesson journey, from goals and interests to teaching, contextual help, and feedback. Native UI and explicit state ownership keep that experience dependable.

Tim Horng · Personal iOS project · September 2026


  • SwiftUI
  • Supabase
  • Typed AI responses
  • Local lesson persistence

The engineering question

How do you make a personalized AI learning path feel dependable as lessons, network requests, and account state change?

01

AI personalizes the journey

Plans, lesson content, and contextual help work together around the learner’s goals.

02

Progress needs evidence

Completing a route is separate from demonstrating recall.

03

Refresh has one owner

Synchronization commands are separate from read-only projections.

DEEP DIVE / STATE OWNERSHIP

A refresh should not
trigger itself.

The failure

A Home refresh defect exposed a circular dependency: sync completion triggered a projection refresh, which requested another sync. Clearing the kanji selection during each pass made the ownership problem visible.

The change

Separate synchronization commands from projection reads. Freshness-sensitive actions wait for an explicit result covering their demand, while Home keeps previously loaded content visible.

AFTER / ONE-WAY OWNERSHIP

User demand

Explicit sync command

Sync result

Covers requested freshness

Projection read

No new sync command

User demand → sync result → read-only Home projection

Keep the displayed selection

Starting a new kanji lesson requires a current result and the same selection the learner saw.

Reject obsolete work

Account, reset, and workspace boundaries prevent stale asynchronous work from committing.

Preserve the accepted lesson

A lesson keeps its original focus even when Home’s next suggestion changes.

Personalized teaching.
Predictable foundations.

01

Give personalization a reliable shape

AI shapes plans and teaching content around the learner within versioned response contracts. Fixed SwiftUI components make that flexible content usable. Navigation and learning state stay app-owned, with OpenAI access behind the server.

02

Treat Japanese as structured text

Readings belong to exact occurrences, including grouped readings such as 今日 → きょう. Invalid annotations fall back to the original text; the renderer does not invent character-level alignment.

EVIDENCE, WITH ITS BOUNDARIES

A release receipt,
not a promise of perfection.

The September 28 release reached production backend services and internal TestFlight 2.0 (11). Authenticated checks exercised ordinary lessons, cached lessons, and feedback.


678 passed / 2 skipped / 0 failures

Serial native unit suite for that release. These are bounded test results, not evidence of learning outcomes or physical-device performance.

Still separate: public distribution, onboarding rollout, and signed physical-device completion. The new onboarding pipeline was deployed with its production rollout flag off.

Back to the app →