Skip to content

feat(onboarding): the learner says what to call them, and Profile greets by it (#245) - #297

Merged
maximsan merged 1 commit into
mainfrom
feat/learner-name-and-route-tier-guard
Aug 23, 2026
Merged

feat(onboarding): the learner says what to call them, and Profile greets by it (#245)#297
maximsan merged 1 commit into
mainfrom
feat/learner-name-and-route-tier-guard

Conversation

@maximsan

Copy link
Copy Markdown
Owner

Closes #245 — the last user story it left open. One of the two loose ends I flagged turned out not to exist; the honest finding is below.

The greeting (story 6)

Profile said Hello there. because nothing in the app stored a name. Onboarding now has an optional third step that asks for one, and the header greets Hello, Maya. where it was given and Hello, there. where it was skipped — the design's exact sentence and its exact fallback (prototype/screens.jsx:668).

  • Skippable, and honest about it. The button reads Skip until something is typed, the copy says "Only used to say hello. You can skip this.", and whitespace-only collapses to the same "no name" as skipping — one fact, one representation.
  • learnerName is nullable, schema v9. Purely additive; existing devices arrive with "no name given", which is true for them and is what the greeting already handles. Column added by name, so the migration trap fixed in fix(storage): the v7 step drops two columns by name, not by rebuilding (#273) #287 stayed fixed — this is the first new user_settings column since, and it needed no edit to any older step.
  • The flow completes at the last step, not at the brewer: a learner who quits on the name screen is still un-onboarded and restarts, rather than leaving a half-written row.
  • Its own learnerNameProvider, so toggling haptics doesn't rebuild the header.

The route-tier guard — I was wrong

I reported that the tier table wasn't checked for exhaustiveness. It already is, in test/unit/app_routes_test.dart, which walks the real GoRouter configuration (nested routes and shell branches included) and asserts both directions — every registered route has a tier, and the table names no route the router has dropped. I had looked only in header_tier_test.dart and drew the wrong conclusion.

I first added an AppRoutes.all catalogue and a second exhaustiveness test, then reverted both: the existing guard is strictly stronger, and a hand-maintained list is exactly the thing that goes stale. The new route is simply filed in the table that already exists — and that guard is what caught it, failing with Actual: Set:['onboardingName'] before I did.

A third thing, which the schema bump forced

#245 named the testWithDataIntegrity cases that hardcode the current version as "a smaller instance of the same shape". Bumping to v9 broke all four, exactly as predicted. Rather than retarget them to 9, they now read the newest dumped schema (GeneratedHelper.versions.last) and build the target with databaseForVersion, so the next bump edits nothing here. A new first test asserts AppDatabase.schemaVersion and the newest file in drift_schemas/ agree, which catches a bump without a dump — and says so in its failure.

Tests

  • Greeting, named and skipped, on the pure tabHeaderFor.
  • NameController: trimming, skip-vs-empty, re-entry, typing ignored mid-flight.
  • NameScreen: Skip↔Continue, a typed name reaching complete(), skipping carrying null, the optional copy.
  • Draft/repository cases for a name persisted with the rest and a blank one persisted as none.
  • Full suite 1253/1253; analyze, metrics, format and changelog gates all clean.

@maximsan
maximsan merged commit 64a0f6c into main Aug 23, 2026
6 checks passed
@maximsan
maximsan deleted the feat/learner-name-and-route-tier-guard branch August 23, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App header: one shell-owned slot over the four tabs

1 participant