Skip to content

feat(Flag Dependency): Evaluate flags that depend on other flags in local evaluation - #67

Open
linear-code[bot] wants to merge 2 commits into
mainfrom
linear/sdk-9-enable-flag-dependency-in-the-elixir-server-side-sdk-e957
Open

linear-code[bot] wants to merge 2 commits into
mainfrom
linear/sdk-9-enable-flag-dependency-in-the-elixir-server-side-sdk-e957

Conversation

@linear-code

@linear-code linear-code Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

With local evaluation, flags that depend on other flags were ignored for identity flags. A segment conditioned on $.flags.<feature>.enabled never matched, so the dependent feature kept its default. The legacy engine had no JSONPath support at all, so $.identity.* and $.environment.* conditions never matched either. Identity flags are now evaluated as flagsmith-engine 11.1.1 and the Edge API do.

Changes

  • Identity flags that depend on other flags, directly or transitively, now match the engine and Edge API. Identity overrides count as part of the dependency chain.
  • Circular dependencies are cut, and segments that rely on them don't match, as in the engine.
  • Segment conditions on $.identity.* and $.environment.* JSONPath properties now work. The environment document's name is now parsed.
  • The SDK runs all 220 engine-test-data v3.12.1 cases in CI. This supersedes deps: update dependency test/support/engine-test-data to v3 #66. The submodule now uses HTTPS.
  • The v1 environment fixture is kept under test/data/, so the existing 101-identity regression suite still runs. It passes unchanged against the new evaluator.
  • Each environment is prepared (mapped, with segment conditions compiled) once per process and reused for every identity. get_identity_segments skips flag evaluation.
  • bench/engine_bench.exs benchmarks identity evaluation through the public API, so the same script runs against older versions.

The new evaluator (Flagsmith.Engine.Evaluator) works on an evaluation context. Flagsmith.Engine.Mappers builds that context from the environment document and the identity, so get_identity_feature_states and get_identity_segments keep their signatures. The old public segment-matching helpers in Flagsmith.Engine (trait_match/3, traits_match_segment_rule/4, etc.) are left untouched but are no longer used by identity evaluation.

The prepared environment is kept in the process dictionary, alongside the environment it was prepared from. It is reused only when the environment passed in matches it exactly (^env match), so a changed environment is always prepared again; a test covers this. Each process holds at most one prepared environment. In the SDK, local identity evaluation runs in the poller process, so an environment is prepared once per refresh.

To check the suite can fail: with flag resolution disabled, 13 of the 19 flag-dependency cases fail.

The minor release goes through release-please and needs a maintainer to merge the release PR.

Performance

Baseline is main at 77b5e9a, before flag dependency. Both sides ran the same script and fixture, interleaved, for 3 rounds of 5 s per workload. Setup: Elixir 1.15.2, OTP 26, 1 CPU.

git worktree add /tmp/baseline 77b5e9a
mkdir -p /tmp/baseline/bench /tmp/baseline/test/data
cp bench/engine_bench.exs /tmp/baseline/bench/
cp test/data/environment_n9fbf9h3v4fFgH3U3ngWhb.json /tmp/baseline/test/data/
(cd /tmp/baseline && mix deps.get && mix run bench/engine_bench.exs 5)
mix run bench/engine_bench.exs 5

Times below are the median of the 3 per-round medians, per batch: 101 identities for v1, 100 for synthetic. Lower is better.

Workload Baseline This PR Change
v1 fixture (5 features, 4 segments), feature states 1.38 ms 1.17 ms 15% faster
v1 fixture, segments 0.55 ms 0.51 ms 8% faster
synthetic (100 features, 50 segments with nested rules, multivariate, identity overrides), feature states 72.9 ms 33.3 ms 54% faster
synthetic, segments 28.3 ms 19.3 ms 32% faster
synthetic, equal copy of the environment per call 80.1 ms 41.6 ms 48% faster
v1 fixture, cold (prepared environment dropped before every call) 1.39 ms 2.64 ms 1.9× slower
synthetic, cold 71.8 ms 89.0 ms 1.24× slower
synthetic with a 10-deep $.flags.<f>.enabled dependency chain n/a 37.4 ms +12% vs the same environment without it

Limitations:

  • Cold path: every first evaluation of an environment version in a process is slower than baseline, by about 14 µs for the v1 fixture and 0.56 ms for the synthetic environment. This pays for itself after about 7 evaluations for v1 and 2 for synthetic. Callers that use Flagsmith.Engine directly from a new short-lived process each time get the cold numbers.
  • Copied environments: an environment that is equal but a different term, e.g. copied from another process, costs one full comparison per call. The "equal copy" row measures this.
  • Dependency chain: baseline can't evaluate dependencies; it treats $.flags.* as a missing trait. Its time for that workload (65.2 ms) isn't comparable, so the table compares against this PR's own non-dependent run.
  • Noise and coverage: this is a shared single-CPU machine, and individual runs varied by about ±10%. Workloads are synthetic apart from the v1 fixture. I didn't measure memory use.

Contributes to https://linear.app/flagsmith/issue/SDK-9/enable-flag-dependency-in-the-elixir-server-side-sdk

Review effort: 4/5

…ocal evaluation

Port flagsmith-engine's context evaluator, including flag dependency, and
run identity flags through it. Bump engine-test-data to v3.12.1 and run
all of its test cases.

Generated with [Linear](https://linear.app/flagsmith/agent-session/51c26f09-5fe3-44a8-8e3d-be2cf9ac50ff)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@linear-code
linear-code Bot requested a review from a team as a code owner October 21, 2026 17:22
@linear-code
linear-code Bot requested review from khvn26 and removed request for a team October 21, 2026 17:22
Split the evaluator into a prepare step for the environment, with segment
conditions compiled, and a per identity evaluation step. The prepared
environment is kept per process for the environment last evaluated, and
segments are evaluated without flags when only segments are asked for.

Add a benchmark comparing identity evaluation across SDK versions.

Generated with [Linear](https://linear.app/flagsmith/agent-session/51c26f09-5fe3-44a8-8e3d-be2cf9ac50ff)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 7291d8ac-23f9-4c44-8362-d5387832fb19

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
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant