Skip to content

fix(local_ai): hard-override to disabled until explicit opt-in (#573)#637

Merged
senamakel merged 8 commits into
tinyhumansai:mainfrom
oxoxDev:feat/573-opt-in-local-ai
Apr 17, 2026
Merged

fix(local_ai): hard-override to disabled until explicit opt-in (#573)#637
senamakel merged 8 commits into
tinyhumansai:mainfrom
oxoxDev:feat/573-opt-in-local-ai

Conversation

@oxoxDev
Copy link
Copy Markdown
Contributor

@oxoxDev oxoxDev commented Apr 17, 2026

Summary

  • Add opt_in_confirmed marker to local AI config; bootstrap hard-overrides enabled=false unless it is true.
  • apply_preset sets the marker on any non-disabled tier (user's explicit choice) and clears it on disabled.
  • Onboarding cloud-default presentation preserved; tests cover opt-in and stale-config override paths.
  • Settings panel continues to render all 5 tier cards (with non-MVP tiers shown as "Coming soon" / non-selectable per PR feat(local_ai): MVP model lockdown — lock selection to 2-4 GB tier (#573) #588) — roadmap visibility is the intended UX.

Problem

PR #588 (MVP model lockdown) clamped selected_tier to the allowlisted range but did not gate enablement. On upgrade, users who already had local_ai.enabled = true with a saved selected_tier (from the pre-MVP default-on era) would still boot with local AI running, bypassing the explicit opt-in the MVP expects.

Reported behaviour: "onboarding flow didn't come for me, but the model selected was for 2-4 GB one, which shouldn't be the case — it should be default cloud, with only a single model available to opt in."

Closes #573

Solution

Close the enablement gap with a config-schema marker + bootstrap gate, defense-in-depth against stale configs and manual edits:

  1. Schema (src/openhuman/config/schema/local_ai.rs): Add opt_in_confirmed: bool with #[serde(default)] → defaults to false for any existing config missing the field.
  2. Bootstrap gate (src/openhuman/local_ai/service/bootstrap.rs): config_with_recommended_tier_if_unselected hard-overrides enabled = false whenever opt_in_confirmed == false, regardless of device RAM or selected_tier. Every pre-MVP upgrade path therefore lands on cloud fallback.
  3. Opt-in write path (src/openhuman/local_ai/schemas.rs): apply_preset is the single source of truth for the marker — any non-disabled tier flips it to true; disabled clears it. Onboarding and Settings already call apply_preset, so no frontend changes are required.

The Settings preset catalog continues to return all_presets() so non-MVP tiers render as "Coming soon" cards (UX established in PR #588), while the existing RPC guard rejects any apply_preset for a non-MVP tier.

Submission Checklist

  • Unit testscargo test --lib -- local_ai::service::bootstrap (6/6 pass, including new bootstrap_overrides_stale_selected_tier_without_opt_in and renamed bootstrap_honors_opt_in_on_* cases); yarn test:unit LocalAIStep (6/6 pass); yarn test:unit localAiBootstrap (2/2 pass)
  • Integrationcargo test --test json_rpc_e2e json_rpc_local_ai_device_profile_and_presets asserts the full 5-preset catalog shape; this PR keeps that contract.
  • Doc comments/// on the new opt_in_confirmed field explaining migration semantics; module-level rationale on the bootstrap gate
  • Inline comments — Bootstrap gate explains why each non-opted-in state (fresh install, pre-MVP upgrade with stale selected_tier, manual config edit) is overridden; apply_preset explains the marker flip as the single source of truth

Impact

Related

🤖 Generated with Claude Code

oxoxDev and others added 7 commits April 18, 2026 00:42
Local AI now defaults to disabled whenever the user has not explicitly
picked a tier, regardless of device RAM. The onboarding flow and
Settings panel remain the only ways to turn it on. Previously the
bootstrap only disabled local AI on <8 GB devices and auto-applied a
recommended preset on larger hosts; this flip completes the MVP goal
of cloud-first defaults with a single, opt-in local model.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…inyhumansai#573)

Flips the LocalAIStep sufficient-RAM screen so the primary button is
"Continue with Cloud" and local AI appears as an explicit opt-in
("Use local AI instead"). This aligns onboarding with the new opt-in
bootstrap: every device now starts on cloud unless the user chooses
local AI. The low-RAM cloud-fallback screen is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…yhumansai#573)

Updates the sufficient-RAM path tests to match the cloud-primary UI:
the default "Continue with Cloud" click advances without triggering
local AI bootstrap, and the secondary "Use local AI instead" opt-in
still starts the recommended-preset bootstrap and propagates errors.
Low-RAM cloud-fallback tests are unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…umansai#573)

Bootstrap will hard-override `enabled=false` unless this marker is true,
ensuring existing installs with a stale `selected_tier` from the pre-MVP
default-on era fall back to cloud until the user explicitly re-opts in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…in (tinyhumansai#573)

Every bootstrap path now returns `enabled=false` unless `opt_in_confirmed`
is true, regardless of device RAM or `selected_tier`. This closes the
regression where upgrading users with a persisted `selected_tier` bypassed
the onboarding opt-in and started local AI without consent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…MVP tier only (tinyhumansai#573)

`apply_preset` is the single source of truth for the opt-in marker: any
non-disabled tier flips it true, `disabled` clears it. The preset RPC now
returns `mvp_presets()` so the Settings UI exposes only the allowlisted
`ram_2_4gb` tier, matching the MVP scope already enforced on the
onboarding path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Warning

Rate limit exceeded

@oxoxDev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 25 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 28 minutes and 25 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 49d942b8-12a4-496e-b401-57f72a468a56

📥 Commits

Reviewing files that changed from the base of the PR and between 5082f3e and c81291a.

📒 Files selected for processing (5)
  • app/src/pages/onboarding/steps/LocalAIStep.tsx
  • app/src/pages/onboarding/steps/__tests__/LocalAIStep.test.tsx
  • src/openhuman/config/schema/local_ai.rs
  • src/openhuman/local_ai/schemas.rs
  • src/openhuman/local_ai/service/bootstrap.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

…ai#573)

Revert the `mvp_presets()` swap in `handle_local_ai_presets`. PR tinyhumansai#588
already renders all 5 tier cards in Settings with non-MVP tiers shown
as "Coming soon" / non-selectable, and that roadmap visibility is the
intended UX. Returning only the MVP tier from the RPC hid the other 4
cards entirely and broke that signal.

The opt-in gate still holds: `apply_preset` remains the single writer
of `opt_in_confirmed`, the RPC guard continues to reject non-MVP
apply_preset calls, and the bootstrap hard-override still clamps
stale configs. This commit only rolls back the UI catalog surface.

Fixes failing `json_rpc_local_ai_device_profile_and_presets` integration
test which expects 5 presets.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@senamakel senamakel merged commit da5fe92 into tinyhumansai:main Apr 17, 2026
8 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
…umansai#573) (tinyhumansai#637)

* refactor(local_ai): default to opt-in on all devices (tinyhumansai#573)

Local AI now defaults to disabled whenever the user has not explicitly
picked a tier, regardless of device RAM. The onboarding flow and
Settings panel remain the only ways to turn it on. Previously the
bootstrap only disabled local AI on <8 GB devices and auto-applied a
recommended preset on larger hosts; this flip completes the MVP goal
of cloud-first defaults with a single, opt-in local model.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* style(local_ai): apply cargo fmt to bootstrap tests (tinyhumansai#573)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(onboarding): present cloud AI as default on sufficient-RAM path (tinyhumansai#573)

Flips the LocalAIStep sufficient-RAM screen so the primary button is
"Continue with Cloud" and local AI appears as an explicit opt-in
("Use local AI instead"). This aligns onboarding with the new opt-in
bootstrap: every device now starts on cloud unless the user chooses
local AI. The low-RAM cloud-fallback screen is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(onboarding): cover opt-in local AI semantics in LocalAIStep (tinyhumansai#573)

Updates the sufficient-RAM path tests to match the cloud-primary UI:
the default "Continue with Cloud" click advances without triggering
local AI bootstrap, and the secondary "Use local AI instead" opt-in
still starts the recommended-preset bootstrap and propagates errors.
Low-RAM cloud-fallback tests are unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(local_ai): add opt_in_confirmed marker to local AI config (tinyhumansai#573)

Bootstrap will hard-override `enabled=false` unless this marker is true,
ensuring existing installs with a stale `selected_tier` from the pre-MVP
default-on era fall back to cloud until the user explicitly re-opts in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(local_ai): hard-override local AI to disabled until explicit opt-in (tinyhumansai#573)

Every bootstrap path now returns `enabled=false` unless `opt_in_confirmed`
is true, regardless of device RAM or `selected_tier`. This closes the
regression where upgrading users with a persisted `selected_tier` bypassed
the onboarding opt-in and started local AI without consent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(local_ai): set opt_in_confirmed on apply_preset and surface MVP tier only (tinyhumansai#573)

`apply_preset` is the single source of truth for the opt-in marker: any
non-disabled tier flips it true, `disabled` clears it. The preset RPC now
returns `mvp_presets()` so the Settings UI exposes only the allowlisted
`ram_2_4gb` tier, matching the MVP scope already enforced on the
onboarding path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* revert(local_ai): keep full preset catalog in presets RPC (tinyhumansai#573)

Revert the `mvp_presets()` swap in `handle_local_ai_presets`. PR tinyhumansai#588
already renders all 5 tier cards in Settings with non-MVP tiers shown
as "Coming soon" / non-selectable, and that roadmap visibility is the
intended UX. Returning only the MVP tier from the RPC hid the other 4
cards entirely and broke that signal.

The opt-in gate still holds: `apply_preset` remains the single writer
of `opt_in_confirmed`, the RPC guard continues to reject non-MVP
apply_preset calls, and the bootstrap hard-override still clamps
stale configs. This commit only rolls back the UI catalog surface.

Fixes failing `json_rpc_local_ai_device_profile_and_presets` integration
test which expects 5 presets.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

MVP: auto-provision local model at startup and lock selection to 2–4 GB only

2 participants