Targeting & Context — Attributes, Segments, Rules & Precedence
Targeting answers who gets a variant: attributes on the evaluation context, reusable segments, and ordered rules with a clear precedence. Bad targeting causes support chaos and biased experiments. This lesson shows a minimal rules engine, how segments are composed, and how exposure differs from authorization.
- 1Gist
- 2Maps
- 3Q&A
- 4Sandbox
Voice readout needs Web Speech Synthesis in this browser.
Question ladder
L1
What is an evaluation context?
Answer
The attributes the SDK evaluates: user, tenant, device, and sometimes the request. Multi-kind context is normal. The bucketing key is one stable field inside it.
L2
What is a segment?
Answer
A named predicate over context, reused across flags. Internal staff, beta tenants, and a minimum app version are segments. A million user-key rows are not.
L3
What order do rules run?
Answer
Disabled or default-off, then ops force or kill, then individual targets, then segments, then percentage on the remainder, then the fallthrough default.
L4
Why does that order matter?
Answer
First match and most-specific match select different people when two rules could hit. An undocumented order is nondeterministic product behavior.
L5
Can a flag replace RBAC?
Answer
No. A flag chooses an experience. Authorization chooses whether the action is allowed. Beta access still enforces the policy on the server.
L6
What do you check when a user does not see the feature?
Answer
Context attributes, segment membership, rule order, the percentage bucket, and snapshot freshness. Read the reason code.
L7
What must never ship inside a client rules snapshot?
Answer
Raw emails, secrets, and sensitive allowlists. Prefer a segment id resolved on the server, or a hash of membership. Treat the mobile client as hostile.
Failure modes
Ambiguous precedence
Two rules match and nobody wrote which one wins. Users see a coin flip that is not even sticky.
Email as the bucketing key
The hash input is personal data, and a typo or a new address reshuffles the user.
Allowlist of a million keys
Individual targeting that should have been a segment. Evaluation and the console both get heavy.
Client snapshot full of PII
The mobile app downloaded the staff list. Assume that payload is public.
Misconceptions
A region flag enforces data residency.
A region attribute can change UX. Legal hold and residency belong in the data plane, not in a toggle.
First matching rule and most specific rule are the same idea.
They pick different winners when rules overlap. Publish one precedence and stick to it.
GitOps means you do not need a kill switch.
Reviewed defaults are right for ordinary changes. An incident still needs an audited emergency override.
Interviewer traps
Design a full RBAC model for the beta.
The flag exposes a capability the policy already allows. Point at the authorization page and keep this answer on context and rule order.
Put the user id in every analytics dimension.
High-cardinality attributes explode segment and analytics cost. Keep them out of unbounded targeting dimensions.
Design scenario
Same prompt for every reader.
Requirements
Typed context, reusable segments, first-match rules in a written order, and a reason code. No raw emails in the client payload.
Traffic / scale
Staff is a small segment. Beta tenants are an attribute. The percentage applies only to whoever fell through.
Latency
Segment membership for a large audience is an attribute or a server-side segment id, not a scan of a million keys on the client.
Consistency
The same context and the same ordered rules produce the same variant and the same reason.
Availability
If the snapshot is stale, say so in the debug reason. Do not guess.
Failure assumptions
- Two rules can match one user.
- The client can read whatever the SDK downloaded.
- A support agent will ask why, not whether the hash was clever.
Constraints
- Do not rebuild authorization policy.
- Do not put percentage math ahead of the kill rule.
Prompt
A checkout beta should be on for staff, on for beta-tier tenants, and on for 10 percent of everyone else, unless the kill switch is set. You must explain a user who does not see it.
API
What fields are on the context, and which field is the bucketing key?
Data
Which predicate is a segment, and which match is an individual target?
Architecture
Where is the source of truth for ordinary edits, and what is the emergency override?
Staff should see the beta before everyone else
Prefer
A segment, then rules
internal_staff is a named predicate. The flag references it. The reason code says why this user matched.
- The same audience can gate several flags.
- Membership is reviewable.
- Support can read TARGET_MATCH, RULE_MATCH, FALLTHROUGH, or OFF.
Alternative
A boolean plus a private allowlist
Emails copied into the client payload, or a million user keys on one flag.
- Fast to type once.
- The list leaks, and it does not reuse.
- Nobody can say which rule won.
From request to reason
Teach this order. Vendors rename the steps. The priority is the contract.
- 1
Build context
User key, email domain, plan, country, tenant tier, OS, app version. A request path is optional and high cardinality. Be careful with it. - 2
Match segments
Named predicates such as internal staff, enterprise tenants, iOS at or above a version, or a country in a region. - 3
Walk rules in order
Kill and force, then individual targets, then segments, then the sticky percentage, then the default. - 4
Return variant and reason
TARGET_MATCH, RULE_MATCH, FALLTHROUGH, or OFF. Debug reasons stay in a secure mode, not in a public response.
Overview
Targeting answers who gets a variant. The inputs are attributes on the evaluation context, reusable segments, and ordered rules. Get the order wrong and support cannot explain the beta. Get the audience wrong and the experiment is biased before anyone looks at a metric.
The hash from the types page still runs. Targeting decides whether that user is in the population the hash applies to.
Flow
- 1
1. Incoming request
- next2. Build context
- 2
2. Build context
- next3. Match segments
- 3
3. Match segments
- next4. Walk ordered rules
- 4
4. Walk ordered rules
- next5. Variant plus reason
- 5
5. Variant plus reason
Lesson map
Targeting & Context — Attributes, Segments, Rules & Precedence
Targeting answers who gets a variant: attributes on the evaluation context, reusable segments, and ordered rules with a clear precedence. Bad targeting causes support chaos and biased experiments. This lesson shows a minimal rules engine, how segments are composed, and how exposure differs from authorization.
Architecture. Architecture
Select a node to see why it exists, or an edge to see the protocol, direction, effect, and consequence.
Mermaid export
flowchart TB req["1. Incoming request"] ctx["2. Build context"] seg["3. Match segments"] rules["4. Walk ordered rules"] req -->|1. Incoming request| ctx ctx -->|2. Build context to 3. Match segments| seg seg -->|3. Match segments| rules
Context
Modern SDKs pass multi-kind attributes. LaunchDarkly calls them contexts. OpenFeature calls them the evaluation context. A useful shape is:
- User: key, email domain, plan, country.
- Tenant: key, tier, region.
- Device: operating system, app version.
- Request: path, and only if you accept the cardinality.
The bucketing key should be stable and should not be personal data when you can avoid it. A user key or account key is the hash input. Email and domain can be targeting attributes without being that input. Hashing the email means a changed address is a new person, and the address is now in your assignment logs.
Segments
A segment is a named predicate over context. You write it once and several flags reference it.
| Segment | Example rule | Use |
|---|---|---|
| internal_staff | Email domain is the company domain | Dogfood |
| enterprise_tenants | Plan equals enterprise | A feature the plan allows. Still enforce authorization |
| mobile_ios | OS is iOS and the app version is high enough | A client capability |
| eu_users | Country is in the EU set | Regional UX |
A region flag that changes copy is not a legal hold and not data residency. Those controls live in the data plane. Say that out loud if the interviewer slides from "EU users" into "EU data."
Individual targeting is fine for a dogfood list. A large audience is a segment or an attribute, not millions of user-key rows on one flag.
Precedence
This order is the teaching model. Products rename it. Write the one you run:
- Disabled flag returns the default off.
- Ops force or kill returns a fixed variant.
- Individual targets allow or deny specific user keys.
- Segment rules match. First match wins, or a published priority list wins. Pick one.
- Percentage rollout applies to the traffic that is still left.
- Fallthrough default.
Reason codes make the support call short: TARGET_MATCH, RULE_MATCH, FALLTHROUGH, OFF. Many SDKs expose "why" only in a secure debug mode. Do not print the whole context into a client log.
If two rules can match and you have not said whether first-match or most-specific wins, the product is nondeterministic. That is the bug, not the hash.
A tiny ordered evaluator
The sketches below are educational. They are not a production rules engine. Kill is first, then staff, then beta tenants, then a precomputed bucket below 10, then fallthrough off. Staff with a high bucket still matches staff, because that rule is earlier than the percentage.
ProblemKill, staff, beta, then a 10 percent bucket, then fallthrough. Staff wins even when the bucket would miss.
Expectedexample.com returns on/staff. Bucket 3 returns on/pct10. Bucket 50 returns off/FALLTHROUGH.
Edge cases
- A kill flag forces off before staff.
- An empty context falls through.
- Bucket 100 is the missing-bucket default and does not match pct10.
- Test: staff beats the percentage
v == 'on' and why == 'staff' - Test: low bucket matches percent
v2 == 'on' and why2 == 'pct10' - Test: everyone else falls through
v3 == 'off' and why3 == 'FALLTHROUGH' - Test: kill wins over staff
evaluate({'kill_checkout': True, 'email_domain': 'example.com'}, rules) == ('off', 'kill')
Press Run. Snippets must be self-contained — no network, files, or native modules.
ProblemFirst match wins. Staff with bucket 50 is still staff. Bucket 3 is the percentage. Kill beats staff.
ExpectedThe three cases return staff, pct10, and the off variant for a killed staff user.
Edge cases
- A missing bucket is treated as 100 and misses pct10.
- Fallthrough is the string FALLTHROUGH.
- Test: staff beats the percentage
v === 'on' && why === 'staff' - Test: low bucket matches percent
v2 === 'on' && why2 === 'pct10' - Test: kill wins over staff
evaluate({ kill_checkout: true, email_domain: 'example.com' }, rules)[0] === 'off' - Test: kill reason is kill
evaluate({ kill_checkout: true, email_domain: 'example.com' }, rules)[1] === 'kill'
Press Run. Snippets must be self-contained — no network, files, or native modules.
Flags versus authorization
| Concern | Feature flag | Authorization |
|---|---|---|
| Question | Which experience? | Are you allowed? |
| Failure | Wrong UX | Security incident |
| Enforcement | Often advisory on the client | Server-side and authoritative |
| Change speed | Product and ops | Security-reviewed |
Use a flag to roll out a capability the policy already allows. Do not make the flag the only gate on an admin API. The policy models are Authorization. A permission toggle that overlaps a role still has to pass that check.
Client snapshots and PII
Client SDKs download rules. Do not embed raw emails or a sensitive allowlist in that payload. Prefer a segment id resolved on the server, or a hash of membership. Assume a mobile client is hostile for security purposes. Secrets never belong in the snapshot. The architecture page repeats the placement rule. This page owns the content of the rules.
GitOps, the console, and the emergency hatch
| Model | Strength | Cost |
|---|---|---|
| Flag definitions in Git | Reviewable changes, closer env parity | A slow kill unless you have an escape hatch |
| Remote console | Fast ops response | Needs audit, IAM, and dual-control |
| Code defaults plus a remote overlay | Safe behavior while offline | You must document which source wins |
Many teams keep defaults in Git and allow an emergency remote override with paging and an audit record. The pipeline that promotes the Git change is CI/CD Pipelines. Who may flip production, and the break-glass path, is the progressive delivery page. Do not leave the production console open to everyone.
Interview Q&A
What is a segment?
Answer
A reusable named audience. It is a predicate over context, applied by reference from more than one flag. Internal staff and a minimum app version are segments. A one-off user id on a single flag is individual targeting, not a segment.
Why does precedence matter?
Answer
First-match and most-specific match choose different winners when rules overlap. If the order is ambiguous, the product behavior is not deterministic. Publish the order: kill, individual, segment, percentage, default.
Can flags replace RBAC?
Answer
No. Flags manage exposure. Authorization manages permission. A beta segment can decide who is invited. The server still has to allow the action. Overlap on "beta access" is a reason to keep both, not to drop the policy.
What is wrong with high-cardinality attributes?
Answer
Unbounded ids as targeting dimensions explode segment size and analytics cost. A request path or a raw user id on every rule is how the console and the warehouse get expensive. Keep the bucketing key stable and the rule attributes coarse.
How do you debug a user who does not see the feature?
Answer
Read the context you actually sent, segment membership, rule order, the percentage bucket, and whether the SDK snapshot is fresh. The reason code is the short version of that list. Guessing from the console without the context is how the ticket stays open.
When is individual targeting the wrong scale?
Answer
A dogfood list is fine. A large audience is a segment or an attribute. Millions of user-key rows on one flag are slow to evaluate and impossible to review.
What leaks if the client downloads rules?
Answer
Whatever you put in the payload. Raw emails and sensitive allowlists become public. Resolve membership on the server or send a segment id. Do not treat the client rule set as a secret.
GitOps or a console for a production kill?
Answer
Git for reviewed defaults. A console or API for the incident, with IAM and an audit trail. Pure GitOps is often too slow when the checkout path is on fire. The hatch has to be rarer than the pull request, and it has to be logged.
Pitfalls
- Hashing an email address because it was the only stable-looking field.
- Putting two overlapping segments on a flag and never writing which one wins.
- Using a country flag as if it were a residency control.
- Copying the staff list into the mobile SDK payload.
- Targeting on request path and then wondering why the analytics bill moved.
- Debugging "user does not see it" from memory instead of from the reason code.
Pick a user on the enterprise plan whose bucket is 50. Say which rule should have matched, which reason you expect, and the one attribute you would print in a secure debug log. Then say what you will not print.
Go deeper
- LaunchDarkly contexts and Flagsmith segments are the product shapes of multi-kind attributes and reusable audiences.
- Unleash activation strategies show constraints on top of a rollout.
- Martin Fowler on feature toggles separates a release toggle from a permission toggle, which is the authorization boundary on this page.
- The OpenFeature specification defines the evaluation context those SDKs pass in.
Next: Experimentation & A/B.