Skip to content

feat: onboarding turns on automatic inference for the areas it creates#3574

Merged
matthiasn merged 3 commits into
mainfrom
feat/onboarding-enables-automatic-inference
Jul 25, 2026
Merged

feat: onboarding turns on automatic inference for the areas it creates#3574
matthiasn merged 3 commits into
mainfrom
feat/onboarding-enables-automatic-inference

Conversation

@matthiasn

@matthiasn matthiasn commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #3568: areas created during onboarding start with automatic inference on. Every other creation path still leaves it off.

  • CategoryRepository.createCategory gains an optional automaticInferenceEnabled
  • OnboardingWelcomeModal._continue passes true for areas it creates, and fills in a null on reused areas — but never overwrites an explicit false

Why

#3568 made automatic transcription and image analysis an explicit per-category opt-in, defaulting to off everywhere. That left onboarding in an incoherent state, which I only spotted when tracing the onboarding path end to end:

  • onboarding_welcome_modal.dart:527 binds each area to a seeded profile (onboardingSeededProfileId) plus Laura as the task-agent template
  • the flow then has the user record a first capture and watch it become a task
  • but the areas it created had automation off, so the same gesture the next day did nothing

Onboarding was teaching a behaviour the app then withheld until the user found the switch.

What is and isn't affected — verified, not assumed

Onboarding's own capture never depended on the gate. onboarding_first_task_step.dart:126 uses captureControllerProvider, and capture_controller.dart:105 transcribes through AudioTranscriptionService directly. That is an explicit user action and never passed through ProfileAutomationService. So the onboarding "aha" worked before this change and works after.

What was broken is everything after onboarding. Task-linked recordings go recorder_controller.dart:401AutomaticPromptTriggertryTranscribe (automatic_prompt_trigger.dart:46), which is gated. That is the path this change fixes.

Why this isn't the implicit enablement #3568 removed

The audit's objection was that selecting a profile silently enabled automation — a side effect of a configuration choice, with seeded profiles arriving pre-automated. Onboarding is different in kind: the user connects a provider, picks areas, and records a capture, all deliberately, in a flow that is explicitly about setting up AI. That is consent in context.

The boundary is kept narrow on purpose:

  • only the onboarding flow passes true; the category create modal and every other caller leave it null
  • reused categories only get the value filled in when it is null. An existing false is the user having switched automation off, and onboarding leaves it standing — otherwise the flow would be a back door around the switch

Verification

  • fvm flutter analyze lib test — no issues found
  • fvm flutter test test/features/onboarding/ test/features/categories/ — 716 passed
  • new tests: create-path default stays null, explicit opt-in persists, onboarding creates areas with automation on, and reuse respects an explicit opt-out
  • CategoryTestUtils.createTestCategory gained the field so the opt-out fixture is expressible

Note on version numbering

This branch is cut from main and claims 0.9.1067, the same number as the open #3573. Whichever merges second needs a rebase and a renumber — flagging it so it is not a surprise.

Summary by CodeRabbit

  • New Features
    • After consent, onboarding-created areas start with AI transcription and image analysis enabled.
  • Changed
    • AI automation stays disabled for categories created outside onboarding (including later category creation).
    • Reusing a category preserves prior automation choice, including explicit opt-outs; onboarding auto-enables only when the prior state was undecided.
  • Bug Fixes
    • Re-running onboarding now restores bundled provider profiles if they were previously removed.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a748784f-65cf-4f0d-882f-7b5ecb57a0a0

📥 Commits

Reviewing files that changed from the base of the PR and between 896509a and e325531.

📒 Files selected for processing (3)
  • lib/features/categories/README.md
  • lib/features/onboarding/ui/onboarding_welcome_modal.dart
  • test/features/onboarding/ui/onboarding_welcome_modal_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/features/onboarding/ui/onboarding_welcome_modal.dart
  • test/features/onboarding/ui/onboarding_welcome_modal_test.dart

📝 Walkthrough

Walkthrough

Onboarding-created categories now enable automatic inference, while ordinary creation remains unset. Reused categories preserve explicit opt-outs. Reconnecting providers clears seeded-profile tombstones so bundled profiles can be restored. Tests, documentation, release metadata, and versioning were updated.

Changes

Onboarding setup behavior

Layer / File(s) Summary
Category creation contract and persistence
lib/features/categories/repository/categories_repository.dart, test/features/categories/repository/categories_repository_test.dart, test/features/categories/test_utils.dart
createCategory accepts and persists automaticInferenceEnabled; tests cover default and explicit enabled values.
Onboarding automation flow
lib/features/onboarding/ui/onboarding_welcome_modal.dart, test/features/onboarding/ui/onboarding_welcome_modal_test.dart, lib/features/categories/README.md
New categories receive the onboarding default, reused categories fill only null, and explicit false values remain unchanged.
Seeded profile revival
lib/features/ai/state/seed_tombstone_provider.dart, lib/features/ai/util/seed_tombstone_store.dart, lib/features/onboarding/ui/widgets/*, test/features/onboarding/ui/widgets/*, test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart, test/mocks/mocks.dart
A provider exposes tombstone storage, mutations are serialized per database, and provider connection clears tombstones before setup so deleted bundled profiles can be restored.
Release and behavior documentation
CHANGELOG.md, flatpak/com.matthiasn.lotti.metainfo.xml, pubspec.yaml
Release metadata describes the behavior and profile restoration fix, and the version advances to 0.9.1068+4249.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OnboardingWelcomeModal
  participant CategoryRepository
  participant OnboardingApiKeyPanel
  participant SeedTombstoneStore
  participant ProviderSetup
  User->>OnboardingWelcomeModal: Continue onboarding
  OnboardingWelcomeModal->>CategoryRepository: Create or update category automation setting
  CategoryRepository->>CategoryRepository: Persist automaticInferenceEnabled
  User->>OnboardingApiKeyPanel: Connect provider
  OnboardingApiKeyPanel->>SeedTombstoneStore: Clear revived profile tombstone
  OnboardingApiKeyPanel->>ProviderSetup: Run FTUE setup
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: onboarding now enables automatic inference for areas it creates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/onboarding-enables-automatic-inference

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.14%. Comparing base (9e51d70) to head (e325531).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3574   +/-   ##
=======================================
  Coverage   99.14%   99.14%           
=======================================
  Files        1782     1783    +1     
  Lines      130431   130441   +10     
=======================================
+ Hits       129319   129329   +10     
  Misses       1112     1112           
Flag Coverage Δ
glados 14.12% <0.00%> (-0.01%) ⬇️
standard 98.89% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Automatic transcription and image analysis are opt-in per category and default
to off. Onboarding, though, binds a seeded profile and Laura to every area it
creates and then has the user record a first capture — so the flow demonstrated
speech becoming a task while the same gesture the next day would do nothing
until the user found the category switch.

Onboarding's first capture itself is unaffected either way: it runs through
CaptureController -> AudioTranscriptionService, an explicit user action that
never passed through ProfileAutomationService. What breaks without this is
everything after onboarding, where task-linked recordings go through
RecorderController -> AutomaticPromptTrigger -> tryTranscribe, which is gated.

Connecting a provider, choosing areas, and recording on purpose is the consent
the gate asks for, so areas created in that flow start with automation on.
Every other creation path still leaves the preference null (off).

Reuse is the one case where the user may already have answered: onboarding
fills in a null but leaves an explicit false alone, so the flow cannot become
a back door around the switch.
Follow-up to the seed tombstones merged in #3573, which introduced this gap.

Onboarding binds each area to a well-known seeded profile id unconditionally.
Once deletions are remembered, a user who had deleted that bundled profile and
later re-ran onboarding got a category pointing at a row seeding now refuses to
recreate: _resolveModel returns noModel and the first task degrades to
title-only. Onboarding is re-runnable from the maintenance page and the
onboarding settings panel, so this is reachable rather than theoretical.

The key step now clears that provider's tombstone before running the FTUE
setup, so the seeding it triggers can recreate the profile. Deliberately
setting the provider up again is the 'bring it back' signal the store's forget
was built for; every other path still honors the deletion.

Exposes the store as seedTombstoneStoreProvider rather than reaching into
getIt from a widget, which also lets tests substitute one.

Also fixes a defect in the tombstone serialization from that same PR: the
mutation queue was a single static, so it was shared across every database in
the isolate. In tests one stalled mutation against a discarded database wedged
every later write, and the onboarding flow hung mid-connect. The queue is now
keyed by settings database, which is both what the serialization actually needs
and test-safe.
@matthiasn
matthiasn force-pushed the feat/onboarding-enables-automatic-inference branch from f669a93 to 896509a Compare July 25, 2026 11:36
@matthiasn

Copy link
Copy Markdown
Owner Author

Rebased onto main now that #3573 has merged, renumbered to 0.9.1068 (the collision I flagged), and folded in the onboarding regression #3573 introduced.

What #3573 broke. Onboarding binds each area to a well-known seeded profile id unconditionally (onboarding_welcome_modal.dart:527). Once deletions are remembered, a user who had deleted that bundled profile and later re-ran onboarding — reachable from the maintenance page and the onboarding settings panel — got a category pointing at a row seeding now refuses to recreate. _resolveModel returns noModel and the first task degrades to title-only. The key step now clears that provider's tombstone before the FTUE setup runs, so the seeding it triggers can recreate the profile. Deliberately setting the provider up again is exactly what forget() was built for; every other path still honors the deletion.

A defect in #3573 itself, found while testing this. The tombstone mutation queue was a single static shared across every database in the isolate. In tests, one stalled mutation against a discarded database wedged every later write — the onboarding flow hung mid-connect, which is how I found it. The queue is now keyed by settings database, which is both what the serialization actually needs (two different databases have nothing to serialize against) and test-safe. Worth knowing that the version merged in #3573 has that flaw.

Also exposes the store as seedTombstoneStoreProvider instead of reaching into getIt from a widget, so tests can substitute one.

Verification: fvm flutter analyze lib test clean; fvm flutter test test/features/onboarding/ test/features/ai/ test/features/categories/ — 5053 passed.

@matthiasn

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart (1)

6-17: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restore the Override imports used by mock helpers.

Both tests type extraOverrides as List<Override> and expand provider overrides before running them. Add import 'package:flutter_riverpod/misc.dart' show Override; so the test files resolve before the analyzer is run.

  • test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart
  • test/features/onboarding/ui/widgets/onboarding_api_key_panel_test.dart
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart`
around lines 6 - 17, Add the flutter_riverpod misc import exposing Override in
both test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart
(lines 6-17) and
test/features/onboarding/ui/widgets/onboarding_api_key_panel_test.dart (lines
10-22), so their extraOverrides declarations and provider override expansion
resolve correctly.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart`:
- Around line 6-17: Add the flutter_riverpod misc import exposing Override in
both test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart
(lines 6-17) and
test/features/onboarding/ui/widgets/onboarding_api_key_panel_test.dart (lines
10-22), so their extraOverrides declarations and provider override expansion
resolve correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 750564b3-c312-42ad-a702-fa98c722b5b5

📥 Commits

Reviewing files that changed from the base of the PR and between f669a93 and 896509a.

📒 Files selected for processing (15)
  • CHANGELOG.md
  • flatpak/com.matthiasn.lotti.metainfo.xml
  • lib/features/ai/state/seed_tombstone_provider.dart
  • lib/features/ai/util/seed_tombstone_store.dart
  • lib/features/categories/README.md
  • lib/features/categories/repository/categories_repository.dart
  • lib/features/onboarding/ui/onboarding_welcome_modal.dart
  • lib/features/onboarding/ui/widgets/onboarding_api_key_panel.dart
  • pubspec.yaml
  • test/features/categories/repository/categories_repository_test.dart
  • test/features/categories/test_utils.dart
  • test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart
  • test/features/onboarding/ui/onboarding_welcome_modal_test.dart
  • test/features/onboarding/ui/widgets/onboarding_api_key_panel_test.dart
  • test/mocks/mocks.dart
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/features/categories/repository/categories_repository_test.dart
  • test/features/categories/test_utils.dart
  • test/features/onboarding/ui/onboarding_welcome_modal_test.dart
  • lib/features/onboarding/ui/onboarding_welcome_modal.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/features/categories/README.md`:
- Around line 32-37: Update the consent wording in the categories documentation
to match the implementation: provider connection/onboarding category setup
triggers automaticInferenceEnabled: true when profileId is present, before any
first-capture recording is verified. Do not describe recording a first capture
as part of the consent boundary unless the onboarding implementation is changed
to enforce that condition.

In `@test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart`:
- Line 6: Add the explicit Override import from flutter_riverpod/misc.dart to
both onboarding_animation_gallery_page_test.dart (lines 6-6) and
onboarding_api_key_panel_test.dart (lines 10-13), so their List<Override> helper
signatures resolve correctly.

In `@test/features/onboarding/ui/onboarding_welcome_modal_test.dart`:
- Around line 89-91: Track whether setUp registered the SettingsDb mock,
distinguishing it from an existing suite-provided registration, and have the
teardown around the SettingsDb cleanup unregister only when this test owns that
registration. Preserve existing registrations for later tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b5a1693f-7a11-4035-94da-04efc7255fb8

📥 Commits

Reviewing files that changed from the base of the PR and between 9e51d70 and 896509a.

📒 Files selected for processing (15)
  • CHANGELOG.md
  • flatpak/com.matthiasn.lotti.metainfo.xml
  • lib/features/ai/state/seed_tombstone_provider.dart
  • lib/features/ai/util/seed_tombstone_store.dart
  • lib/features/categories/README.md
  • lib/features/categories/repository/categories_repository.dart
  • lib/features/onboarding/ui/onboarding_welcome_modal.dart
  • lib/features/onboarding/ui/widgets/onboarding_api_key_panel.dart
  • pubspec.yaml
  • test/features/categories/repository/categories_repository_test.dart
  • test/features/categories/test_utils.dart
  • test/features/onboarding/ui/onboarding_animation_gallery_page_test.dart
  • test/features/onboarding/ui/onboarding_welcome_modal_test.dart
  • test/features/onboarding/ui/widgets/onboarding_api_key_panel_test.dart
  • test/mocks/mocks.dart

Comment thread lib/features/categories/README.md
Comment thread test/features/onboarding/ui/onboarding_welcome_modal_test.dart Outdated
…teardown

Review follow-up.

The README and the code comment both said the consent was 'connecting a
provider and recording a first capture', but the flag is written at the
category step, before onStartCapture hands control to the capture. Reworded to
the gesture that actually triggers it — connecting a provider and choosing
those areas — rather than one that happens afterwards.

The welcome-modal test preserved an existing SettingsDb registration but its
tearDown removed it unconditionally, which would have deleted a suite-provided
registration for every later test. It now tracks whether this setUp owns the
registration and only unregisters its own.
@matthiasn
matthiasn merged commit 22395ba into main Jul 25, 2026
29 of 32 checks passed
@matthiasn
matthiasn deleted the feat/onboarding-enables-automatic-inference branch July 25, 2026 12:19
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.

1 participant