Skip to content

Fix onboarding: model prefetch, shorter flow, escape hatch, real reminders toggle#1353

Open
r3dbars wants to merge 1 commit into
mainfrom
claude/app-onboarding-review-fgywyt
Open

Fix onboarding: model prefetch, shorter flow, escape hatch, real reminders toggle#1353
r3dbars wants to merge 1 commit into
mainfrom
claude/app-onboarding-review-fgywyt

Conversation

@r3dbars

@r3dbars r3dbars commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Why

An onboarding review found six problems with the first-run flow:

  1. The ~600 MB local voice model was never downloaded during onboarding, so the "try dictation right now" step — the emotional peak of the flow — could stall on a cold download. Same for the first Start Meeting on the meetings path.
  2. The calendar step's "Meeting reminders" toggle was cosmetic: it only fed analytics and never persisted anywhere.
  3. The flow was long — 12 screens (meetings) / 14 (dictation), with three consecutive screens making the same agent-value pitch.
  4. The required-permissions gate had no escape hatch: a Mac that can't grant Screen Recording (e.g. MDM-managed) dead-ended on a permanently disabled button, and every re-entry point routed back into onboarding.
  5. The mid-onboarding try-dictation step only worked because a preference-write side effect happened to repost .hotkeysDidChange and reinstall the event tap after Accessibility was granted — fragile coupling.
  6. Dead code and a visual bug: a legacy 8-step FirstRunOnboardingStep flow model that no longer matched the live flow, and decorative fake traffic lights drawn under the window's real buttons.

Product Impact

  • Affects: dictation / meetings
  • Lane: activation
  • Why this matters: these are the highest-leverage leaks in the first-value loop — the first dictation/meeting no longer stalls on a surprise download, users who can't grant permissions can still reach the app, and a toggle that promised behavior now delivers it.

What changed

  • Model prefetch during onboarding. makeOnboardingView() injects a model-state provider and a prefetch trigger into PermissionsOnboardingView; the view starts the prefetch on appear and polls state alongside the existing permission poll. A new OnboardingModelStatusLineView shows progress (with retry on failure) on the try-dictation and done steps, backed by a Foundation-pure FirstRunExperience.onboardingModelStatusLine(for:). STTRouter gains prefetchSelectedModelFiles(); the existing-install variant delegates to it. Emits the already-allowlisted onboarding_model_state_changed event and adds model_state to step-viewed/CTA/completion events (all already in Resources/analytics-events.psv).
  • Meeting reminders persist. New Sources/Support/MeetingReminderPreferences.swift (default on). The onboarding toggle writes it, MeetingPromptDetector's default calendar gate now checks it alongside TCC access, and Settings > General gets a matching "Meeting reminders" row.
  • Shorter flow: 9 screens (meetings) / 10 (dictation), from 12/14. Privacy pills fold into the welcome screen; the dictation intro merges into the live try-it step; the memory + agent-demo screens merge into one payoff screen (keeps the memory step id so funnels stay comparable); the diagnostics toggle moves onto the done screen. All contract-pinned automation identifiers and copy hooks are retained.
  • Permissions escape hatch. The permissions step is now skippable, only its own primary button gates on grants, and completion no longer requires them. Skipping still applies the chosen shortcut policy. The done screen shows a "grant them later in Settings" note when grants are missing.
  • Explicit hotkey re-registration. The onboarding poll rebroadcasts permission transitions via .transcriptedPermissionsDidChange; the app delegate observes it and calls recoverHotkeysAfterPermissionChange() when Accessibility flips, instead of relying on the preference-write side effect.
  • Cleanup. Deleted the dead FirstRunOnboardingStep/FirstRunOnboardingActionState/FirstRunOnboardingCopy legacy model and its test suites; removed the fake TrafficLights view and hid the zoom button (close stays as the abandon path).
  • Supporting updates. QA ui-smoke walk updated for the merged welcome step; new preference registered in run-tests.sh APP_SOURCES and Tests/FastTests.manifest with Tests/MeetingReminderPreferencesTests.swift; new FirstRunExperienceTests suites for analyticsValue and the model status line; Sources/Support/CLAUDE.md and CHANGELOG updated.

How I checked it

  • scripts/dev/agent-preflight.sh
  • Selected checks from .agents/test-matrix.yml for the files changed — via CI build-and-test (green at a8ca0b4): build.sh --no-open, run-tests.sh, swift test, run-integration-smoke.sh, run-e2e-smoke.sh, and all four Tools package tests
  • bash build.sh --no-open — CI build-and-test, green
  • bash run-tests.sh — CI build-and-test, green
  • Performance budget passed — bundle gate runs inside CI's build.sh --no-open; the runtime events check was not run (no runtime-sensitive change here)
  • bash run-integration-smoke.sh — CI build-and-test, green
  • swift test --package-path Tools/TranscriptedQA — CI build-and-test, green
  • bash -n run-tests.sh and bash -n scripts/entrypoints/run-tests.sh
  • python3 scripts/dev/check-build-source-lists.py
  • Manual check: fresh-install onboarding on both paths, model status line states (download progress, failure + retry), skip-permissions completion, Settings General reminders row — needs a human on a Mac
  • bash scripts/ops/transcripted-qa-bench.sh --mode ui — live AX walk needs local Accessibility permission; CI covers only the TranscriptedQA package tests

Verification status: authored in a Linux container with no Swift toolchain, so nothing Swift ran locally — but CI's macOS build-and-test job has since run the full stack (build, fast tests, SPM tests, integration smoke, E2E smoke, Tools package tests) green on this head. What remains is the live AX ui-smoke and the manual fresh-install pass above.

Risk Review

  • Privacy / local-first behavior reviewed — new analytics use only pre-allowlisted events/properties; analyticsValue never carries failure messages; the model status line uses plain copy, not raw errors
  • Storage path or migration impact reviewed — one new UserDefaults key (meeting-reminders-enabled, absent = on, so existing installs keep current behavior)
  • Public-facing copy stays concrete and matches current product scope
  • Release/update impact reviewed — CHANGELOG Unreleased section updated; no version/appcast changes
  • Agent PRs link the issue/workpad and stay draft until human review — opened as draft; marked ready by @r3dbars
  • UI changes include sanitized .agent-review/visuals/ evidence — not possible in this environment; needs a Mac run
  • No private transcripts, audio, tokens, personal paths, or customer data are included

Notes

Analytics continuity: removed step ids (privacy, dictation_intro, agent_demo, diagnostics) simply stop firing; the merged payoff screen keeps the memory id. Existing dashboards keep working; step-count-based funnels will show the shorter flow.

Behavior note on the permissions gate: onboarding completion no longer implies permissions are granted. MeetingRecordingStartGate and the dictation-start paths already handle missing grants at action time, and the done screen plus Settings point users back.

Agent handoff

COORD_DONE: BRIEF | https://github.com/r3dbars/transcripted/pull/1353 | six onboarding fixes (prefetch, persisted toggle, shorter flow, skip gate, hotkey re-register, dead-code/visual cleanup) | none | none | CI build-and-test green (build, fast tests, swift test, integration + e2e smokes, Tools packages) plus local preflight/bash -n/source-list checker | human: live AX ui-smoke + manual fresh-install onboarding pass on a Mac

🤖 Generated with Claude Code

https://claude.ai/code/session_019pLa23SibHfMcBSbJfqsZw

…nders toggle

Fixes from the onboarding review:

- Warm the local voice model while onboarding is open and surface its
  download state on the try-dictation and final steps, so the first
  dictation or meeting no longer stalls on a cold ~600 MB download.
  Emits the already-allowlisted onboarding_model_state_changed event and
  model_state properties.
- Persist the calendar step's Meeting reminders toggle. It previously
  only fed analytics; it now writes MeetingReminderPreferences, gates
  the calendar source in MeetingPromptDetector, and has a matching
  Settings > General row.
- Shorten the flow to 9 screens (meetings) / 10 (dictation) from 12/14:
  privacy pills fold into welcome, dictation intro merges into the live
  try-it step, the memory and agent-demo screens merge into one payoff
  screen (keeps the "memory" step id), and the diagnostics toggle moves
  onto the done screen.
- Let users skip the required-permissions step and finish onboarding in
  a degraded state instead of dead-ending on a disabled button; the done
  screen points to Settings when grants are still missing.
- Re-register the dictation event tap explicitly when Accessibility
  flips to granted (onboarding poll rebroadcasts transitions via
  .transcriptedPermissionsDidChange) instead of relying on a
  preference-write side effect.
- Delete the dead legacy FirstRunOnboardingStep flow model and its
  copy/tests; drop the decorative fake traffic lights that stacked under
  the real window buttons and hide the zoom button.

Updates the QA ui-smoke walk for the merged welcome step and registers
the new preference + tests in the fast-test runner and manifest.

Not verified by build: authored in a Linux container without a Swift
toolchain; needs bash build.sh --no-open, bash run-tests.sh, and
swift test --package-path Tools/TranscriptedQA on a Mac.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019pLa23SibHfMcBSbJfqsZw
@r3dbars

r3dbars commented Jul 2, 2026

Copy link
Copy Markdown
Owner Author

Maestro hold review: HOLD at head a8ca0b4. Still draft and changes first-run activation behavior: model prefetch, shortened flow, permissions escape hatch, persisted meeting-reminders toggle, hotkey recovery, Settings copy, and QA UI smoke path. The PR body says Swift build/tests and visual evidence were not run locally. Smallest clear path: run build.sh --no-open, run-tests.sh, run-integration-smoke.sh, TranscriptedQA UI smoke, then manually verify fresh-install dictation and meetings onboarding, skipped permissions, model status/retry, and Settings reminders state.

@r3dbars r3dbars marked this pull request as ready for review July 3, 2026 01:34

r3dbars commented Jul 3, 2026

Copy link
Copy Markdown
Owner Author

Re the hold: most of that checklist has since run in CI. The macOS build-and-test job passed green on this head (a8ca0b4) and it covers build.sh --no-open, run-tests.sh, swift test, run-integration-smoke.sh, run-e2e-smoke.sh, and the four Tools package tests including TranscriptedQA. PR body checkboxes updated to match.

Still genuinely open, and it needs a human on a Mac:

  • bash scripts/ops/transcripted-qa-bench.sh --mode ui — the live AX ui-smoke walks the new onboarding flow but needs local Accessibility permission, so CI can't run it
  • manual fresh-install pass: both onboarding paths end to end, the model status line (download progress, failure + retry), completing with permissions skipped, and the new Settings > General "Meeting reminders" row
  • sanitized .agent-review/visuals/ screenshots for the UI changes

Happy to fix anything those turn up.


Generated by Claude Code

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.

2 participants