Skip to content

feat(mobile): version-gate feature flags by minimum app version - #49

Closed
iscekic wants to merge 1 commit into
mainfrom
kwf/in-the-mobile-app-make-the-f-25a1
Closed

feat(mobile): version-gate feature flags by minimum app version#49
iscekic wants to merge 1 commit into
mainfrom
kwf/in-the-mobile-app-make-the-f-25a1

Conversation

@iscekic

@iscekic iscekic commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Request

In the mobile app, make the feature flags version-aware.

A flag that a build does not understand must not change behaviour. Today the
app reads a flag and acts on it whatever version wrote it, so an older build
can act on a newer flag and a newer build can miss one that was renamed.

Reproduce first: find where the app reads its feature flags, show what an
older build does with a flag it does not know, and record what you saw.

Then give every flag a minimum app version. The app applies a flag only when
its own version is at or above that minimum, and falls back to the flag's
default otherwise. Show the choice in the debug/settings surface that already
lists the flags, so a tester can see which flags a build applies and why.

Prove both paths live in the PR body: a flag the build applies, and a flag it
skips because the build is too old.

Changelog for users

  • A feature flag no longer changes behaviour on a build that predates it: the app applies a flag's remote value only when the app's own version is at or above the flag's minimum version, and uses the flag's default otherwise.
  • The Preferences screen now shows a "Feature flags" debug surface that lists every registered flag with the value this build acts on, whether that value came from the remote flag or the flag's default, and the minimum-version gate that decided.

Changelog for maintainers

  • New flag registry in apps/mobile/src/lib/feature-flags.ts: each mobile flag is declared with a minAppVersion and a defaultValue, plus dotted numeric version comparison (compareAppVersions, isAppVersionAtLeast) and currentAppVersion(). Going forward, every flag a mobile build reads must be registered here; keys with no entry keep the legacy behaviour (the remote value applies) so a flag only gains a gate by being registered.
  • Flag resolution in @/lib/analytics/posthog now consults the registry: for a registered flag whose minimum is above the build's version, isFeatureEnabled returns the definition's defaultValue instead of the PostHog value. Unknown keys are unchanged.
  • Added FeatureFlagStatus / getFeatureFlagStatuses / useFeatureFlagStatuses and a new FeatureFlagsSection mounted in Preferences. Statuses are a cached snapshot keyed off a revision bumped on client init, discard, and flag reload, so useSyncExternalStore does not loop on a fresh array.
  • Registry minimums record each flag's first shipping release: mobile-pr-review at 1.0.4 (default on) and mobile-quick-chat at 1.0.6 (default off). Check these minimums against release history — a wrong minimum silently mis-gates users on that version.
  • Five new i18n keys were added to every locale; four of them are technical notation (remote · ≥ {min}, default · < {min}, default · not loaded, v{version}) and are allowlisted in the catalog checker.
  • The version gate fails closed: when the platform reports no app version, version-gated flags fall back to their default. Unit tests cover both paths live — an applied flag and a flag skipped because the build is too old.

E2E proof

[ff-prefs-not-loaded] Feature flags unloaded (ios) — e2e-mobile-app/ff-prefs-not-loaded.png

[ff-prefs-applied] Feature flags applied remote (ios) — e2e-mobile-app/ff-prefs-applied-digest.png

[ff-prefs-empty] Feature flags section hidden (ios) — e2e-mobile-app/ff-prefs-empty-digest.png

Follow-ups (not changed here)

  • 01-login-request-code.png — A blue "Refreshing..." bar overlaps the logo and clips it on the code-entry screen.

In the mobile app, make the feature flags version-aware.

A flag that a build does not understand must not change behaviour. Today the
app reads a flag and acts on it whatever version wrote it, so an older build
can act on a newer flag and a newer build can miss one that was renamed.

Reproduce first: find where the app reads its feature flags, show what an
older build does with a flag it does not know, and record what you saw.

Then give every flag a minimum app version. The app applies a flag only when
its own version is at or above that minimum, and falls back to the flag's
default otherwise. Show the choice in the debug/settings surface that already
lists the flags, so a tester can see which flags a build applies and why.

Prove both paths live in the PR body: a flag the build applies, and a flag it
skips because the build is too old.
@iscekic

iscekic commented Sep 6, 2026

Copy link
Copy Markdown
Owner Author

Superseded by Kilo-Org#5911 — the same branch, republished on prod.

@iscekic iscekic closed this Sep 6, 2026
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