Skip to content

feat(feature-flags)!: Evaluate ordered targeting rules - #1717

Open
stanleyphu wants to merge 2 commits into
mainfrom
codex/auth-7097-node-rules
Open

stanleyphu wants to merge 2 commits into
mainfrom
codex/auth-7097-node-rules

Conversation

@stanleyphu

Copy link
Copy Markdown
Contributor

Why

The runtime's enable-only evaluator cannot honor an ordered rule that serves false. I added v2 polling and first-match-wins evaluation, with legacy responses normalized before the cache swap so older APIs and bootstrap data keep working. Unknown rules/operators do not match; unparseable served values use the caller's default.

This changes the configuration returned by getFlag() and change-event snapshots from targets to rules plus off_value. The breaking-change marker and README call out that migration. isEnabled() keeps its existing signature.

Not covered by CI

  • Before the implementation, the new boundary tests failed because polling omitted payload_version=2 and a future bootstrap envelope was cached as two flags. Both pass now.
  • Exercised the built SDK's HTTP polling through a loopback relay to the already-authenticated local flags testing app, with the API on codex/auth-7096-poll-payloads. The relay forwarded live API payloads; credentials stayed inside the testing app.
  • Bootstrapped all four built entry points (Node/worker, ESM/CJS) with actual v1 and v2 API responses. These entry-point checks ran in Node.

Proof

The live poll requested /sdk/feature-flags?payload_version=2 and loaded 16 flags. For the disposable poll-payload-smoke flag, whose user exclusion precedes its organization inclusion:

no matching target        false
matching user             false
matching organization     true
matching user + org       false
same user + org via v1    true

The last result confirms compatibility with v1's enable-only projection. The v2 SDK preserves the exclusion.

Fixes AUTH-7097

@linear-code

linear-code Bot commented Sep 30, 2026

Copy link
Copy Markdown

AUTH-7097

@stanleyphu
stanleyphu marked this pull request as ready for review October 1, 2026 00:21
@stanleyphu
stanleyphu requested review from a team as code owners October 1, 2026 00:21
@stanleyphu
stanleyphu requested a review from mattolson October 1, 2026 00:21
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5 Tier: plus

[Medium impact] The PR appears safe to merge, with a non-blocking gap in the response-type migration notes.

Findings

  1. P2 Response alias breaks indexing ▶
Fix with agent prompt
### Issue 1
src/feature-flags/interfaces/flag-poll-response.interface.ts:undefined-56
`FlagPollResponse` now includes a v2 envelope without a string index signature. Existing TypeScript code that accepts this exported type and indexes it by flag slug will no longer compile. The README describes the `getFlag()` and change-event migration, but not this additional type change, leaving those callers without migration guidance.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds v2 polling and ordered rules, so the first matching rule can serve either true or false. Legacy payloads are converted before entering the cache.

  • Feature flags follow ordered rules that can serve either true or false.
  • The runtime reads v2 flag payloads and converts legacy payloads for local evaluation.
  • Flag lookups and change events expose the normalized v2 configuration.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Poll or bootstrap data] --> B{Recognized payload?}
  B -->|No| C[Keep cached flags]
  B -->|Yes| D[Convert legacy targets to rules]
  D --> E[Replace cached flags]
  E --> F{Flag enabled?}
  F -->|No| G[Serve off_value]
  F -->|Yes| H[Check rules in order]
  H --> I{A rule matches?}
  I -->|Yes| J[Serve first matching value]
  I -->|No| K[Serve default_value]
  G --> L[Use caller default for non-boolean values]
  J --> L
  K --> L
Loading

Reviews (2) · Last reviewed commit: "docs: Update feature flag runtime README" · Reviewed by Greptile

Comment thread src/feature-flags/payload.ts
flags: Record<string, FlagPollEntryV2>;
}

export type FlagPollResponse = FlagPollResponseV1 | FlagPollResponseV2;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Response alias breaks indexing

FlagPollResponse now includes a v2 envelope without a string index signature. Existing TypeScript code that accepts this exported type and indexes it by flag slug will no longer compile. The README describes the getFlag() and change-event migration, but not this additional type change, leaving those callers without migration guidance.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/feature-flags/interfaces/flag-poll-response.interface.ts
Line: 56

Comment:
**Response alias breaks indexing**

`FlagPollResponse` now includes a v2 envelope without a string index signature. Existing TypeScript code that accepts this exported type and indexes it by flag slug will no longer compile. The README describes the `getFlag()` and change-event migration, but not this additional type change, leaving those callers without migration guidance.

**Knowledge Base Used:**
- [Feature flag evaluation](https://app.greptile.com/workos/-/custom-context/knowledge-base/workos/workos-node/-/docs/feature-flags.md)
- [SDK initialization and public entrypoints](https://app.greptile.com/workos/-/custom-context/knowledge-base/workos/workos-node/-/docs/sdk-foundation.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The type change is intentional as part of the major SDK update, but agreed that we’re missing migration guidance here. I’ll add a note to the README’s configuration migration section to use FlagPollResponseV1 for legacy maps, or FlagPollResponseV2 with .flags[slug] for v2.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That migration note addresses the concern. Please make the distinction explicit: legacy flat maps should use FlagPollResponseV1, while v2 consumers should access entries through FlagPollResponseV2.flags[slug]; then callers can update their indexing without relying on the union’s shape.

Comment thread src/feature-flags/payload.ts
@Deborah-Digges
Deborah-Digges removed the request for review from mattolson October 1, 2026 16:06
Comment thread src/feature-flags/evaluator.ts
@Deborah-Digges

Deborah-Digges commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

How do we plan to roll this out? I imagine now that we have the v2 version of the SDK API shipped, we can just ship this without waiting for the full rollout of targeting rules.

disabled v1 targets get dropped since they don’t affect evaluation. We should call this out in the migration notes.

However, this would break existing targeting, so I'm wondering when the right order to ship this SDK change would be

BREAKING CHANGE: getFlag() and change-event snapshots now expose v2 rule entries with off_value and rules instead of legacy targets.
@stanleyphu
stanleyphu force-pushed the codex/auth-7097-node-rules branch from c0860ed to c9ac1cd Compare October 16, 2026 00:14
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@workos-shipyard

Copy link
Copy Markdown

⚓ Shipyard review suggestion

Suggested team: applied-ai, based on recent contributors to the changed files (@nicknisi).

Links open Shipyard for confirmation. Choosing a reviewer overrides availability; “Pick for me” skips known absences.
Comment /tag <team> for a team or /tag to infer one. Tag the same team again to reroll.

Shipyard Analysis

⏳ Generating analysis...

⚓ Explore the analysis in depth in Shipyard · 🔄 Re-run analysis

@workos-shipyard
workos-shipyard Bot requested a review from nicknisi October 16, 2026 23:42
@workos-shipyard

Copy link
Copy Markdown

⚓ Review requested from @nicknisi for team dx, requested by @stanleyphu.

Shipyard Analysis

⏳ Generating analysis...

⚓ Explore the analysis in depth in Shipyard · 🔄 Re-run analysis

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants