PT-4175: First-run state machine and modal shell#2576
Open
katherinejensen00 wants to merge 19 commits into
Open
PT-4175: First-run state machine and modal shell#2576katherinejensen00 wants to merge 19 commits into
katherinejensen00 wants to merge 19 commits into
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…tent resolve Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the step contract that all first-run wizard steps implement, plus four placeholder components (Language, Identify, Sync Consent, Sync Progress) with localized body text only. Placeholders are replaced by sibling tickets (PT-4176/77/78/79). Includes test that verifies mock localized strings render. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix storybook import in first-run-shell.stories.tsx (@storybook/react → @storybook/react-webpack5)
- Fix import/no-named-as-default warnings: use named imports for placeholder steps
- Fix no-null/no-null errors: replace () => null with () => undefined in test stubs
- Add required comment above eslint-disable-next-line import/first in app.component.test.tsx
- Switch to named import { App } in app.component.test.tsx to match renderer/index.tsx
- Regenerate lib/papi-dts/papi.d.ts to include platform.firstRunComplete (was missing from prior task)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ng test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…f from code review Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… docs, loading/error UX polish Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ng Storybook states Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eset across step nav; dedup interface-mode cache key; sort localization block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Spell out the bare `W` as `wizardActive` in the reducer comment and the two matching first-run-store.test.ts references (initialism guidance) - Relabel %firstRun_button_skip% "Skip" -> "Skip setup" (names the outcome: it ends setup rather than skipping a single step) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Session-URL: <session URL>
katherinejensen00
requested review from
irahopkinson,
jolierabideau,
lyonsil,
rolfheij-sil and
tjcouch-sil
as code owners
July 18, 2026 01:05
Resolved conflicts: - src/main/startup-tasks.ts (auto-merged, verified): keeps both PT-4162's power-mode session-sync restructure and PT-4175's first-run auto-sync gate; the gate sits in the simple-mode branch, before syncProjects. - src/main/startup-tasks.test.ts: kept main's power-mode + unreadable-settings tests alongside PT-4175's simple-mode first-run gate tests. - lib/platform-bible-react/dist/**: regenerated from merged source. - lib/papi-dts/papi.d.ts: clean 3-way merge (retains platform.firstRunComplete). Verified: startup-tasks + first-run tests pass (32); typecheck clean apart from the pre-existing buildInfo.json error. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Session-URL: <session URL>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PT-4175 delivers the foundation for the simple-mode first-run setup wizard: a persisted
platform.firstRunCompleteflag and a startup state machine that gates the app behind a non-dismissable modal until onboarding completes. It ships the shell, the gate, and four placeholder steps that the sibling tickets (PT-4176 Language / PT-4177 Identify / PT-4178 Sync consent / PT-4179 Sync progress) fill in by swapping entries in the shell'sstepComponentsmap. Additive and backward-compatible; the four review passes found no Critical or Important issues.What changed & where to look
Authored source below (
lib/papi-dts/papi.d.tsandlib/platform-bible-react/dist/**in the diff are regenerated build output, not hand-edited).State machine — start here
src/renderer/services/first-run.reducer.ts— puredecideFirstRun(firstRunComplete, wizardActive, registrationValidity)→showApp/completeThenShowApp(existing-user migration) /waitForRegistration/startWizard(step). The whole routing decision in one function; its test mirrors every row.src/renderer/services/first-run-store.ts— renderer store that feeds the reducer and exposes a subscribable status. Owns: idempotent startup resolve (StrictMode-safe), migration backfill, resume-to-sync after the registration relaunch, cache-non-clobber on read failure, retry, and the power-mode fast-path.src/renderer/services/resolve-registration-validity.ts— bounded (15s) tri-state check ofparatextRegistration.doesUserHaveValidRegistration.UI
src/renderer/components/first-run/first-run-overlay.component.tsx— the full-viewport non-dismissable gate (loading / error+Retry / wizard) atZ_INDEX_FIRST_RUN..../first-run-shell.component.tsx— wizard chrome (title, "Step X of Y", Back/Skip/Next footer, busy + inline error) and the injectablestepComponentsmap siblings use to swap in real steps..../steps/*.placeholder.component.tsx— the four temporary placeholders;first-run-step-props.model.ts— the step contract.Wiring & settings
src/renderer/app.component.tsx— mounts the overlay and kicks off resolution on startup.src/main/startup-tasks.ts— gates simple-mode auto-sync onfirstRunComplete(a fresh user never syncs before consenting).src/extension-host/data/core-settings-info.data.ts+src/declarations/papi-shared-types.ts— the new hiddenplatform.firstRunCompletesetting.lib/platform-bible-react/src/components/z-index.ts—Z_INDEX_FIRST_RUN(700, above the menubar).How to review
first-run.reducer.ts(+ its test) — the entire routing decision, small and pure.first-run-store.tsto see how the reducer is fed and how migration / resume / retry / power-mode work.The test files mirror each behavior, so they double as behavioral docs.
Testing
53 unit tests: reducer truth table; store (resume-after-relaunch, StrictMode idempotency, concurrent-retry dedup, cache-fallback, power-mode initial seed); resolver (timeout + non-boolean); the startup gate; and component/wiring tests. All user-facing text is localized; Storybook stories cover the gate (loading/error/wizard) and shell (all four steps).
Notes / follow-ups (mostly for the sibling tickets)
platform.restartand must keep theparatext-registrationstartup float suppressed while the wizard owns Identify.Full /review-paratext summary (findings, positives, interview notes)
Code Review Summary
Branch: worktree-pt-4175
Base: origin/main
Date: 2026-07-17
Review model: Claude Opus 4.8 (1M context)
Files changed: 45 (28 authored source files, plus regenerated
lib/papi-dts/papi.d.tsandlib/platform-bible-react/dist/**build output)Overview
PT-4175 lays the foundation for the simple-mode first-run setup wizard: a persisted
platform.firstRunCompleteflag and a startup state machine that, in simple mode, gates the app behind a non-dismissable modal until onboarding completes. It ships the shell, the gate, and four placeholder steps (Language / Identify / Sync consent / Sync progress) that the sibling tickets PT-4176/77/78/79 will replace by swapping entries in the shell'sstepComponentsmap. The state machine handles the existing-user migration (silently marks complete, no wizard), the resume-to-sync flow after the registration relaunch, and a bounded registration-validity check with a Retry/error affordance. Startup auto-sync is gated on the flag so a fresh user never syncs before consenting.The four analysis passes (API/correctness, style/patterns, coverage/compliance, UX) found no Critical or Important issues. The change is additive and backward-compatible, has thorough unit coverage for the reducer, store, resolver, and startup gate, routes all user-facing text through localization, and follows the established store/component patterns. Minor findings were resolved or consciously deferred during the interview (below).
API Changes
@papi/core(papi-shared-types→papi.d.ts): new user setting'platform.firstRunComplete': boolean(defaultfalse,isHidden: true). Additive, backward-compatible.platform-bible-react: new exportZ_INDEX_FIRST_RUN(= 700). Additive.src/renderer/hooks/use-interface-mode.hook.ts:INTERFACE_MODE_CACHE_KEYchanged module-private → exported (renderer-internal, not a public@papi/platform-bible-reactsurface). Additive.src/extension-host/data/core-settings-info.data.ts: added theplatform.firstRunCompletecontribution entry + validator; widenedbooleanValidator's generic to include the new key (internal, additive).No changes to
platform-bible-utils, no extension*.d.tschanges. Thepapi.d.tsdiff is a regenerated additive entry, not a hand-edit.Findings
Critical — Must address before merge
None.
Important — Should address before merge
None.
Minor — Consider
first-run.reducer.tscomment used a bareWforwizardActive(fixed during review: spelled out aswizardActivein the reducer comment and the two matchingfirst-run-store.test.tsreferences)%firstRun_button_skip%label "Skip" finishes the whole wizard, not one step (fixed during review: relabeled to "Skip setup" to name the outcome)package-lock.jsontop-levelnameflipped to "pt-4175" (worktree artifact) (fixed during review: reverted so the lockfile keeps the canonical package name and produces no diff)(kept — "Finish" is a widely-understood wizard terminal label; PT-4179 owns the real sync-progress step and can revisit copy in context)%firstRun_button_finish%"Finish" is generic; "Finish setup"/"Get started" would be more specific(left as-is — reasonable camelCase segment; renaming for a pure nit isn't worth the churn, and there are no translations yet)%firstRun_stepIndicator%uses a camelCase segment vs thefirstRun_step_*snake segmentsThe four placeholder step components are structurally identical (DRY)(intentional — each is a deliberately temporary placeholder with its own localization key and a JSDoc pointing at its replacement ticket; extracting a shared component would complicate the per-ticket swap)Per-step heading: the shell renders only the product title + "Step X of Y"(informational for the sibling tickets — each real step should supply its own heading; not a placeholder-shell issue)(required by the settings-contribution shape; follows the existing hidden-setting pattern)%settings_platform_firstRunComplete_label%label text never surfaces (setting isisHidden)(pre-existing; not introduced by this change)lib/platform-bible-react/src/index.tsz-index export block isn't fully alphabetized[Author response: Directed the three cheap fixes to be applied during review (bare-letter comment, Skip label, lockfile revert); chose to keep "Finish" and the
stepIndicatorkey name; the remaining minors are informational/no-action.]Template Propagation
Shared Regions Modified
None.
Extension Config Changes
None.
Positive Observations
decideFirstRun) + an idempotent renderer store + the gate/shell — good separation and consistency with the existingworkspace-updating-storepattern.INTERFACE_MODE_CACHE_KEYis exported and shared (rather than a duplicated literal), preventing a silent startup-routing bug if the key ever changes.role="status"(loading) androle="alert"(error) live regions, visually-hiddenDialogTitle/DialogDescription, and a real focus trap; the non-dismissable gate blocks Escape/outside-click and the close button intentionally.first-run-overlay.stories.tsx: loading/error/wizard;first-run-shell.stories.tsx: all four steps).components/first-run/) and additive, well-documented API surface (Z_INDEX_FIRST_RUN, the hidden setting).Interview Notes
stepIndicatorkey name, and deferred the real-step microcopy/headings to the sibling tickets that own those steps.In-Review Quality Check
Changes made during review: spelled out the
wizardActivecomment/references, relabeled%firstRun_button_skip%→ "Skip setup", reverted thepackage-lock.jsonname artifact. Verification: the affected test files (shell, store, overlay, startup-tasks) pass (36/36); Prettier reports the changed files are correctly formatted; lint/format run on the staged files via the pre-commit hook. No new typecheck errors (a comment + a string-label + a test-name change; nothing type-relevant).Suggested Review Focus
Prioritized areas for the author-reviewer meeting:
(firstRunComplete, wizardActive, registrationValidity, interfaceMode, cache)routing — especially the existing-user migration and the resume-after-relaunch path (both unit-tested). Worth a quick sanity read offirst-run.reducer.ts+first-run-store.ts.Z_INDEX_FIRST_RUN(700). Known, deliberate deferrals: a modal/notification opened during the gate would render behind it (latent — nothing opens one today), and the full-screen CSS override is brittle against a future shadcn upgrade (a dedicated blocking-overlay primitive is the deeper follow-up).platform.restartand keep the registration extension's startup float suppressed; PT-4179 (Sync progress) should trigger its own sync rather than rely on the once-at-startup backstop; real steps supply their own headings and finalize footer copy.AI-assisted — session
This change is