Skip to content

feat: support semantic version conditions - #365

Merged
greghuels merged 3 commits into
mainfrom
greg.huels/FFL-2921/semver-node
Aug 13, 2026
Merged

feat: support semantic version conditions#365
greghuels merged 3 commits into
mainfrom
greg.huels/FFL-2921/semver-node

Conversation

@greghuels

@greghuels greghuels commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add SEMVER evaluation to @datadog/flagging-core.
  • Support SEMVER_EQ, SEMVER_NEQ, SEMVER_LT, SEMVER_LTE, SEMVER_GT, and SEMVER_GTE.
  • Run all shared FFE evaluation cases through DatadogNodeServerProvider.
  • Add focused core SemVer unit coverage.
  • Pin ffe-system-test-data to aaa97e4, which has the SEMVER system tests.

Why uint64-safe string comparison

The evaluator keeps SemVer core components as decimal strings instead of converting them to JavaScript Number values.

  • Compatibility: The FFE SemVer behavior is shared across SDKs. The Go/Rust-compatible implementation accepts uint64-bounded core components, including values above Number.MAX_SAFE_INTEGER, so narrowing JavaScript to Number.MAX_SAFE_INTEGER would create cross-SDK differences.
  • Performance: Length-plus-digit string comparison avoids Number parsing on every evaluation and is faster than converting the component strings to numbers at comparison time. It also avoids precision loss for large valid versions.

@greghuels
greghuels force-pushed the greg.huels/FFL-2921/semver-node branch from 49f2b5f to 797e813 Compare August 13, 2026 11:24
@greghuels
greghuels marked this pull request as ready for review August 13, 2026 11:26
@greghuels
greghuels requested a review from a team as a code owner August 13, 2026 11:26
@greghuels greghuels changed the title feat: add SEMVER flag evaluation feat: SEMVER flag evaluations Aug 13, 2026
@greghuels
greghuels force-pushed the greg.huels/FFL-2921/semver-node branch from 797e813 to b5d8726 Compare August 13, 2026 11:29
@greghuels greghuels changed the title feat: SEMVER flag evaluations feat: support semantic version conditions Aug 13, 2026
allocation.splits.every((split) => Array.isArray(split.shards)) &&
(allocation.rules === undefined ||
(Array.isArray(allocation.rules) && allocation.rules.every((rule) => isValidRule(rule))))
Array.isArray(allocation.rules) && allocation.rules.some((rule) => hasInvalidSemverComparand(rule))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor: shall this be moved to isValidRule?

}

const value = version.slice(start, end)
if (value.length > MAX_UINT64.length || (value.length === MAX_UINT64.length && value > MAX_UINT64)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

minor: why do we artificially limit the max value?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

For parity with implementation in other dd-trace libraries. It shouldn't matter too much either way, since this won't be a real-world use case.

* Core identifiers are limited to uint64; numeric prerelease identifiers may
* be arbitrarily large.
*/
export function parseSemver(version: unknown): ParsedSemver | null {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nitpick: the current implementation seems to be verbose and likely slow'ish

I have a feeling that a regex could be faster and shorter. Another option is to split on . and - and validate components afterwards

@greghuels greghuels Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Screenshot 2026-08-13 at 9 11 00 AM

I had an LLM run through some benchmarks on the 2 implementations you suggested along with the current implementation. It looks like the current implementation is still the fastest.

@greghuels
greghuels merged commit 2e1d524 into main Aug 13, 2026
4 checks passed
@greghuels
greghuels deleted the greg.huels/FFL-2921/semver-node branch August 13, 2026 13:13
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.

2 participants