open-feature / open-feature/flagd
feat: implement numeric coercion contract (ADR)
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 997
- Forks
- 136
- Avg merge
- 4d 8h
- Merged PRs (30d)
- 11
Description
Tracking issue for implementing the numeric coercion ADR across flagd, flagd-schemas, flagd-testbed, and all flagd providers.
Contract summary
Per docs/architecture-decisions/numeric-coercion.md (merged in #1979):
- Numeric variants are returned through a numeric accessor only when the conversion is lossless; otherwise
TYPE_MISMATCH. - Numeric flag values are constrained to the IEEE-754 safe-integer range,
[-(2^53 - 1), 2^53 - 1], in the flag-definition schema. This is an ordinary schema validation, surfaced like any other schema validation (today flagd logs schema violations as warnings; that behavior is unchanged). Hard-failing a load on schema violations is intentionally out of scope for this work and is tracked separately as its own feature. - The lossless-coercion contract applies identically across gRPC, OFREP, and in-process evaluation.
- Int bounds are relative to the accessor in use. Accessor widths differ by language; the shared testbed treats
Long(int64) as the canonical wide numeric accessor and only encodes language-agnostic assertions, with int32-specific cases behind@int32-bounded.
Per-language accessor widths
| Language | Integer accessor | Long accessor | Notes |
|---|---|---|---|
| Go (flagd-core) | int64 (ResolveIntValue) |
same (int64 is canonical) | no separate Long; Integer is the canonical Long, so Go excludes @int32-bounded |
| Java | int32 (getInteger) |
int64 (getLong, java-sdk#1985) |
Long safe-delegates to int; canonical wide accessor |
| .NET | int32 | int64 (Int64) |
|
| Python | arbitrary-precision int | n/a | effectively wide |
| JS / Web | double | double | no int64; exact up to 2^53 - 1 (the cap) |
Float accessors cap at the safe-integer range.
No wire format changes. AnyFlag.double_value in ResolveAll remains as-is; the ADR intentionally treats the parsed int/float JSON type as non-authoritative, which keeps bulk eval faithful under the same rule.
Breaking change scope
- Callers relying on silent truncation (Go, Java in-process):
3.14viagetIntegerDetailsreturnsTYPE_MISMATCHinstead of3. - Some SDKs flip the other way:
10.0viagetIntegerDetailsreturns10(previouslyTYPE_MISMATCHin Python and .NET). - Config authors: flag definitions with numeric values outside
[-(2^53 - 1), 2^53 - 1]fail schema validation (a load-time warning today, consistent with every other schema validation). They are not hard-rejected at load by this work.
flagd is pre-1.0, so the coercion behavior change ships as a feat!: minor bump with breaking changes called out in release notes.
Testbed rollout
There is no existing numeric-coercion suite to preserve. This work adds a new, opt-in @numeric-coercion tagged suite (following the opt-in @fractional-v1/@fractional-v2 precedent) so providers adopt it as they migrate. Coverage is added to both the provider gherkin/ suite and the self-contained evaluator/ suite. Width-specific expectations sit behind @int32-bounded; wide and boundary values use the canonical Long accessor.
Rollout order
flagd-schemas: add the safe-integer range to numeric variant values (schema validation)flagd-testbed: add ADR-conformant scenarios under@numeric-coercion(both suites), release new tagflagd+ flagd-core (Go): implement the lossless-coercion contract, bump testbed submodule- Providers (in parallel once the testbed tag lands): bump testbed submodule, implement the lossless-coercion contract in each in-process resolver, apply the same lossless check client-side for
AnyFlag.double_value - Coordinated provider releases
Child issues
- flagd-schemas: open-feature/flagd-schemas#219
- flagd-testbed: open-feature/flagd-testbed#379
- flagd (core + Go flagd-core): open-feature/flagd#1996
- go-sdk-contrib: open-feature/go-sdk-contrib#923
- java-sdk-contrib: open-feature/java-sdk-contrib#1822
- js-sdk-contrib: open-feature/js-sdk-contrib#1578
- python-sdk-contrib: open-feature/python-sdk-contrib#402
- dotnet-sdk-contrib: open-feature/dotnet-sdk-contrib#709
- php-sdk-contrib: open-feature/php-sdk-contrib#169
- rust-sdk-contrib: open-feature/rust-sdk-contrib#151
Related
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with docs/architecture-decisions/numeric-coercion.md and the rollout order in this issue, then review the linked child issues for flagd-schemas, flagd-testbed, flagd, and each provider. Done means the child implementations and opt-in test suites are complete, the testbed tag and submodule updates land, and coordinated provider releases ship the contract.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, go, java, javascript, php, python, rust
- Domain
- api, backend, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100