Skip to content

feat(Segments): Write rules as plain JSON - #8245

Draft
emyller wants to merge 14 commits into
mainfrom
feat/segments-rules-json
Draft

feat(Segments): Write rules as plain JSON#8245
emyller wants to merge 14 commits into
mainfrom
feat/segments-rules-json

Conversation

@emyller

@emyller emyller commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Closes #7815

This is the first step towards getting rid of SegmentRule and Condition models, and the tree complexity they have brought upon us thus far.

We achieve:

  • The Segment model earns a new rules_data attribute
    • Creating / updating segments will snapshot clean JSON rules to rules_data
    • Cloning / evolving segments carry JSON rules along with other attributes.
    • Importing segments (e.g. from LaunchDarkly) also stores rules_data.
    • All active segments are backfilled with rules_data.
  • Existing tests interacting with old models are marked for deletion — most are replaced with new surviving tests.
  • Code paths interacting with old models are marked for deletion.

Unplanned things we also achieve:

  • Overall test code and coverage improvements.
  • Segments API will now reject rules nested more than two levels deep.
    • We used to accept them, before we started to ignore them.
    • Unfortunately, active segments with more than two levels of rules exist, and all conditions are evaluated recursively, despite the front-end being unable to represent them visually in full.
  • Fix some leaking writable segment fields, now read-only.

Chose not to achieve:

Deleted LoC will look great in #7818!

How did you test this code?

Exhaustive unit testing. The migration was also benchmarked and optimised.

Important

This includes a data migration to backfill active segments with JSON rules. The migration code was exhaustively tested and tweaked. On a very limited Postgres local container (1 CPU, 2 GB memory), it took ~16s to rasterise rules of 100K segments with varying depth of rules.

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Aug 11, 2026 9:53pm
flagsmith-frontend-preview Ignored Ignored Preview Aug 11, 2026 9:53pm
flagsmith-frontend-staging Ignored Ignored Preview Aug 11, 2026 9:53pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fa4b3767-1510-4886-a2c6-f400a5039902

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds typed, persisted rules_data for segments. It introduces recursive validation and serialisation for segment writes, plus a migration that backfills active rules in batches. Rollout and LaunchDarkly integrations now populate the structured data while retaining legacy records. Tests cover validation, migration, cloning, rollout rules, LaunchDarkly imports, fallbacks, and large snapshots. Observability documentation now points to updated event source locations.

Estimated code review effort: 4 (Complex) | ~60 minutes

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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.

@emyller emyller self-assigned this Aug 8, 2026
@github-actions github-actions Bot added api Issue related to the REST API docs Documentation updates feature New feature or request and removed docs Documentation updates labels Aug 8, 2026
@emyller
emyller force-pushed the feat/segments-rules-json branch from e997681 to d1b4523 Compare August 8, 2026 01:01
@github-actions github-actions Bot added feature New feature or request docs Documentation updates and removed feature New feature or request docs Documentation updates labels Aug 8, 2026
@khvn26
khvn26 marked this pull request as ready for review August 8, 2026 10:53
@khvn26
khvn26 requested review from a team as code owners August 8, 2026 10:53
@khvn26
khvn26 requested review from khvn26 and removed request for a team August 8, 2026 10:53
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-8245 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api-test:pr-8245 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-8245 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api:pr-8245 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8245 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8245 Finished ✅ Results

@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: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 405482df-5f69-4b7d-b284-074ab96f0eb7

📥 Commits

Reviewing files that changed from the base of the PR and between eeac6b3 and e9e27b2.

📒 Files selected for processing (15)
  • api/segments/migrations/0031_add_segment_rules_data.py
  • api/segments/models.py
  • api/segments/serializers.py
  • api/segments/services.py
  • api/segments/types.py
  • api/segments/validators.py
  • api/tests/conftest.py
  • api/tests/types.py
  • api/tests/unit/segments/conftest.py
  • api/tests/unit/segments/test_unit_segments_models.py
  • api/tests/unit/segments/test_unit_segments_services.py
  • api/tests/unit/segments/test_unit_segments_views.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md
  • mcp/src/flagsmith_mcp/openapi.json
  • openapi.yaml

Comment thread api/segments/serializers.py
Comment thread api/segments/validators.py Outdated
Comment thread api/segments/validators.py Outdated
Comment thread api/tests/unit/segments/conftest.py Outdated
Comment thread api/tests/unit/segments/test_unit_segments_views.py
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
✅ private-cloud · depot-ubuntu-latest-16 — run #19219 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  35.9 seconds
commit  2904c84
info  🔄 Run: #19219 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19219 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  37.1 seconds
commit  2904c84
info  🔄 Run: #19219 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19219 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.3 seconds
commit  2904c84
info  🔄 Run: #19219 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19220 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  46.3 seconds
commit  c68ad3c
info  🔄 Run: #19220 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19219 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  41.1 seconds
commit  2904c84
info  🔄 Run: #19219 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19220 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  34.5 seconds
commit  c68ad3c
info  🔄 Run: #19220 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19218 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  48.2 seconds
commit  9eff8a3
info  🔄 Run: #19218 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19216 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  35.7 seconds
commit  ef93dd7
info  🔄 Run: #19216 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #19216 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  59.7 seconds
commit  ef93dd7
info  🔄 Run: #19216 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #19217 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  3 passed

Details

stats  3 tests across 3 suites
duration  41.4 seconds
commit  04b05a6
info  🔄 Run: #19217 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #19218 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  40 seconds
commit  9eff8a3
info  🔄 Run: #19218 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #19216 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.4 seconds
commit  ef93dd7
info  🔄 Run: #19216 (attempt 1)

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

@emyller
emyller marked this pull request as draft August 8, 2026 14:02
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 11, 2026

@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: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 316a442d-abe2-48f0-8658-5ed94d52184c

📥 Commits

Reviewing files that changed from the base of the PR and between e9e27b2 and ef573e1.

📒 Files selected for processing (10)
  • api/integrations/launch_darkly/services.py
  • api/segments/migrations/0031_add_segment_rules_data.py
  • api/segments/models.py
  • api/segments/serializers.py
  • api/tests/unit/integrations/launch_darkly/snapshots/test_process_import_request__large_segments__correctly_imported__rules_data.json
  • api/tests/unit/integrations/launch_darkly/test_services.py
  • api/tests/unit/segments/conftest.py
  • api/tests/unit/segments/test_unit_segments_migrations.py
  • api/tests/unit/segments/test_unit_segments_views.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md

Comment thread api/integrations/launch_darkly/services.py Outdated
Comment thread api/segments/migrations/0031_add_segment_rules_data.py Outdated
@emyller
emyller force-pushed the feat/segments-rules-json branch from ef573e1 to ef93dd7 Compare August 11, 2026 20:30
@github-actions github-actions Bot added docs Documentation updates feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 11, 2026
@emyller
emyller force-pushed the feat/segments-rules-json branch from ef93dd7 to 04b05a6 Compare August 11, 2026 20:32
@github-actions github-actions Bot added docs Documentation updates feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 11, 2026

@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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f8878c4-fd1a-4a42-af9c-99b117204a52

📥 Commits

Reviewing files that changed from the base of the PR and between ef573e1 and 9eff8a3.

📒 Files selected for processing (7)
  • api/integrations/launch_darkly/services.py
  • api/segments/migrations/0031_add_segment_rules_data.py
  • api/segments/serializers.py
  • api/segments/types.py
  • api/tests/conftest.py
  • api/tests/unit/segments/test_unit_segments_migrations.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md
💤 Files with no reviewable changes (1)
  • api/tests/conftest.py

Comment on lines +511 to +516
rules = segment.rules_data or [ # LaunchDarkly environments share the segment
{"type": constants.ALL_RULE, "conditions": [], "rules": []}
]
rules[0]["rules"] += subrules
segment.rules_data = rules
segment.save(update_fields=["rules_data"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 12 \
  'process_import_request|_create_feature_segment_from_clauses|_create_segment_rule_for_segment|transaction\.atomic' \
  api --glob '*.py'

Repository: Flagsmith/flagsmith

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- transaction imports and uses ---'
rg -n '(^|[^[:alnum:]_])transaction|def _complete_import_request|with _complete_import_request|def _import_segments|_create_feature_segment_from_clauses' api/integrations/launch_darkly/services.py

printf '%s\n' '--- services.py imports and transaction context ---'
sed -n '1,90p' api/integrations/launch_darkly/services.py
sed -n '1180,1285p' api/integrations/launch_darkly/services.py

printf '%s\n' '--- segment import caller ---'
sed -n '1040,1165p' api/integrations/launch_darkly/services.py

Repository: Flagsmith/flagsmith

Length of output: 11928


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- _complete_import_request implementation ---'
sed -n '75,145p' api/integrations/launch_darkly/services.py

printf '%s\n' '--- process_import_request body ---'
sed -n '1230,1415p' api/integrations/launch_darkly/services.py

printf '%s\n' '--- transaction.atomic references in the LaunchDarkly integration ---'
rg -n -C 3 'transaction\.atomic|atomic\(' api/integrations/launch_darkly --glob '*.py'

Repository: Flagsmith/flagsmith

Length of output: 5918


Wrap the JSON and relational writes in one transaction.

_complete_import_request does not use transaction.atomic(). If _create_segment_rule_for_segment or a later Condition write fails, rules_data can persist without matching relational rows.

Source: Learnings

@emyller
emyller force-pushed the feat/segments-rules-json branch from 9eff8a3 to 2904c84 Compare August 11, 2026 21:51
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request docs Documentation updates labels Aug 11, 2026
@emyller
emyller marked this pull request as draft August 11, 2026 21:52
@github-actions github-actions Bot added the docs Documentation updates label Aug 11, 2026

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
api/integrations/launch_darkly/services.py (1)

1195-1198: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Persist root_rule instead of undefined subrules.

Line 1196 references subrules, but _create_segments_from_ld only defines root_rule. Every imported non-deleted LaunchDarkly segment reaches this statement and raises NameError. The import can then leave legacy rows without rules_data.

Proposed fix
-        segment.rules_data = [
-            {"type": constants.ALL_RULE, "conditions": [], "rules": subrules}
-        ]
+        segment.rules_data = [root_rule]

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ea285ce1-bc5a-44bb-9fdd-b9ceeba0171a

📥 Commits

Reviewing files that changed from the base of the PR and between 9eff8a3 and c68ad3c.

📒 Files selected for processing (7)
  • api/experimentation/services.py
  • api/integrations/launch_darkly/services.py
  • api/segments/types.py
  • api/tests/unit/experimentation/test_services.py
  • api/tests/unit/integrations/launch_darkly/test_services.py
  • api/tests/unit/segments/test_unit_segments_views.py
  • docs/docs/deployment-self-hosting/observability/_events-catalogue.md



def test_update_segment__rules_and_conditions_with_ids__ignores_ids(
admin_client: APIClient,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use admin_client_original for this single-client test.

admin_client is deprecated and will change its execution model. This test needs one client only. Replace it with admin_client_original.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API docs Documentation updates feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Store segment rule JSON alongside existing models

2 participants