Skip to content

feat: Re-land local flag overrides using dev server, with filter reset fix - #851

Merged
nieblara merged 3 commits into
mainfrom
cursor/reland-local-flag-overrides-9ca3
Oct 28, 2026
Merged

nieblara merged 3 commits into
mainfrom
cursor/reland-local-flag-overrides-9ca3

Conversation

@nieblara

@nieblara nieblara commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

This PR re-lands #837. It also fixes the UI bug that caused the revert in #850. The branch also has a merge of main.

What changes

A local flag is an override for a flag key that is not in the source environment. Before this change, the dev server returned "flag not found" for such an override. Now the dev server accepts it and serves it to SDKs like a synced flag.

  • model.UpsertOverride no longer returns an error when the flag is not in the project.
  • GetFlagStateWithOverridesForProject adds each active override for a flag that is not in the project.
  • When model.DeleteOverride removes a local flag, it sends a full sync event. The SDKs then drop the flag.
  • UpdateProject deletes an override only if its flag was in the previous flag state and is not in the new one. A sync no longer deletes local flags.

The UI shows local flags in the flag list with the synced flags. If local flags exist, an "Only show local flags" filter appears. If no overrides exist, the "Only show flags with overrides" filter is greyed out.

Commits

  1. 9244fe31: A revert of the revert commit 9197f92 from fix: Add local flag overrides using dev server (#837) #850. This brings back the full change from feat: Add local flag overrides using dev server #837.
  2. 2e64a54a: A fix for the filter bug.
  3. 54ae71c0: A merge of main.

The bug

#837 removed the useEffect that reset the filter state in internal/dev_server/ui/src/Flags.tsx. The checkbox showed onlyShowOverrides && overridesPresent, but the stored state did not reset. Only "Remove all overrides" cleared it.

To see the bug:

  1. Tick "Only show flags with overrides".
  2. Remove the last override with "Remove override".
  3. Add a new override.

The filter turned on again and hid the other flags. "Only show local flags" had the same problem.

The fix

Two effects in Flags.tsx reset each filter when it no longer applies:

  • onlyShowOverrides resets when no overrides exist.
  • onlyShowLocal resets when no local flags exist. The effect skips this reset until flags loads.

The effects watch the data, not one handler. They cover "Remove override", "Remove all overrides", and changes to overrides from outside the component.

Merge with main

The merge fixes the conflicts with the UI analytics change in #855.

  • Flags.tsx had one conflict in its imports. The merge keeps sortFlags from this PR and the uiAnalytics imports from main.
  • internal/dev_server/ui/dist/index.html is rebuilt from the merged source with npm ci and npm run build. It is not merged by hand.

Local flags use the same updateOverride, removeOverride, and removeAllOverrides functions as synced flags. They send the same analytics events with the same property values. The allowlist in internal/dev_server/ui_analytics.go accepts all of these values, so this PR does not change it. The local filter sends no analytics event.

FDv2 polling and streaming from #764 read flags through GetFlagStateWithOverridesForProject and the same override and sync events. FDv2 SDKs get local flags with no other change.

Tests

  • db/sqlite_test.go, model/override_test.go, and model/project_test.go have tests for local flags.
  • src/__tests__/Flags.test.tsx has eight tests. Four of them cover the filter bug with a stateful wrapper and a mocked fetch. Without the two effects, all four fail.

What ran after the merge

  • In internal/dev_server/ui: npm ci, npm test -- --run (20 passed), npm run lint, npx prettier --check src, npx tsc -b, and npm run build. All passed. After the build, git status showed no changes.
  • go build ./..., go vet ./internal/dev_server/..., and go test ./... passed.
  • golangci-lint v2.9.0 on ./internal/dev_server/... reported 0 issues.
  • A smoke test of the built dev server with an imported project. An override for a new flag key returned HTTP 200. /sdk/latest-all and the FDv2 /sdk/poll served the local flag. After the override was removed, the payload no longer had the flag. /ui-analytics returned HTTP 204 for each payload that local flag actions send.

Verification video

pr851_local_flags_and_filter_fix_verification.mp4

The video compares three builds of the dev server: main at 7f647177, the reverted #837 at 9244fe31, and this PR at 54ae71c0.

  • main rejects an override for a flag key that is not in the project. This PR accepts it, serves it to SDKs, keeps it after a project sync, and removes it with the override.
  • On feat: Add local flag overrides using dev server #837, the "Only show flags with overrides" filter turns on again by itself and hides the other flags. On this PR, the filter stays off and all flags show.
  • The "Only show local flags" filter shows only the local flag. When the last local flag goes away, the filter goes away too.
  • The UI analytics events from feat(dev-server): send UI analytics through the local server #855 still arrive from the merged UI.

In the video, "Remove all overrides" fails with HTTP 404, and the last override comes back. The same failure occurs on main, so this PR does not cause it. The cause is in DeleteOverrides in internal/dev_server/model/override.go. It loops over all override rows, also the rows that "Remove override" made inactive. For an inactive row, DeactivateOverride returns "not found", and the loop stops before the active rows.

Open in Web Open in Cursor 

cursoragent and others added 2 commits October 5, 2026 21:08
The filter state stayed set after the last override went away. A new
override then turned the filter on again and hid other flags. Two
effects now reset each filter when its condition is false.

Add tests for both filters.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
@nieblara
nieblara marked this pull request as ready for review October 6, 2026 03:37
@nieblara
nieblara requested a review from a team as a code owner October 6, 2026 03:37
Merge origin/main to fix the conflicts with the UI analytics change in #855.

Flags.tsx had one conflict in its imports. The merge keeps sortFlags for
the local flags list and keeps the uiAnalytics imports from main. The
override analytics calls and the local flag filters now work together.

The merge rebuilds ui/dist/index.html from the merged source with
npm ci and npm run build.

Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com>
@nieblara
nieblara merged commit c9b4bd5 into main Oct 28, 2026
11 checks passed
@nieblara
nieblara deleted the cursor/reland-local-flag-overrides-9ca3 branch October 28, 2026 20:30
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.

3 participants