Skip to content

Commit 8b9db9f

Browse files
authored
docs: clarify custom op edge cases (#1936)
- Custom ops (sem_ver, starts_with/ends_with, fractional) now specify null on error instead of false in specs and flowcharts - Added null error-handling admonition to the custom operations section in flag-definitions.md - Documented semver edge cases (v-prefix stripping, partial version padding, numeric coercion, build metadata ignored) - Documented shared evaluator $ref resolution and nested $ref limitation in both flag-definitions.md and providers.md - Fixed fractional spec Go reference code fallthrough to return nil instead of "" - Fixed dotnet provider README include path Everything here is covered in newly added gherkin tests. Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
1 parent 4b947f7 commit 8b9db9f

8 files changed

Lines changed: 38 additions & 15 deletions

File tree

docs/providers/dotnet.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
## Installation
44

55
{%
6-
include "https://raw.githubusercontent.com/open-feature/dotnet-sdk-contrib/main/src/OpenFeature.Contrib.Providers.Flagd/README.md"
6+
include "https://raw.githubusercontent.com/open-feature/dotnet-sdk-contrib/main/src/OpenFeature.Providers.Flagd/README.md"
77
start="## Install dependencies"
88
%}

docs/reference/custom-operations/semver-operation.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,25 @@ Note that the 'sem_ver' evaluation rule must contain exactly three items:
1515
The `sem_ver` evaluation returns a boolean, indicating whether the condition has been met.
1616

1717
```js
18-
{
19-
"if": [
20-
{
21-
"sem_ver": [{"var": "version"}, ">=", "1.0.0"]
22-
},
23-
"red", null
24-
]
25-
}
18+
// sem_ver property name used in a targeting rule
19+
"sem_ver": [
20+
// Evaluation context property to be evaluated
21+
{"var": "version"},
22+
// Operator to use for comparison
23+
">=",
24+
// Target value to compare against
25+
"1.0.0"
26+
]
2627
```
2728

28-
## Example for 'sem_ver' Evaluation
29+
!!! tip
30+
31+
Version strings may include a `v` or `V` prefix (e.g. `v1.0.0`), which is stripped before comparison.
32+
Partial versions such as `1.0` or `1` are also accepted and padded with `.0` to form a complete version.
33+
Numeric context values (e.g. integer `1`) are coerced to strings before parsing.
34+
Build metadata (e.g. `1.0.0+build`) is ignored during comparison, per the SemVer specification.
35+
36+
## Example
2937

3038
Flags defined as such:
3139

docs/reference/custom-operations/string-comparison-operation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The `starts_with` evaluation returns a boolean, indicating whether the condition
2222
]
2323
```
2424

25-
## Example for 'starts_with' Operation
25+
## Example
2626

2727
Flags defined as such:
2828

docs/reference/flag-definitions.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ Consistent with built-in JsonLogic operators, flagd's custom operators return fa
393393
| `ends_with` | Attribute ends with the specified value | string | Logic: `#!json { "ends_with" : [ "noreply@example.com", "@example.com"] }`<br>Result: `true`<br><br>Logic: `#!json { ends_with" : [ "noreply@example.com", "@test.com"] }`<br>Result: `false`<br>Additional documentation can be found [here](./custom-operations/string-comparison-operation.md). |
394394
| `sem_ver` | Attribute matches a semantic versioning condition | string (valid [semver](https://semver.org/)) | Logic: `#!json {"sem_ver": ["1.1.2", ">=", "1.0.0"]}`<br>Result: `true`<br><br>Additional documentation can be found [here](./custom-operations/semver-operation.md). |
395395

396+
!!! info "Error handling in custom operations"
397+
398+
flagd's custom operations return `null` on invalid or unexpected inputs, consistent with how built-in JsonLogic operations represent no-value returns, for example how `var` treats missing keys.
399+
When used inside an `if`, `null` is falsy, so evaluation falls through to the else branch rather than producing a false positive match.
400+
396401
#### Targeting key
397402

398403
flagd and flagd providers map the [targeting key](https://openfeature.dev/specification/glossary#targeting-key) into the `"targetingKey"` property of the context used in rules.
@@ -487,6 +492,11 @@ Example:
487492
}
488493
```
489494

495+
!!! warning
496+
497+
Shared evaluators do not support references to other shared evaluators (nested `$ref`s).
498+
Each `$evaluator` definition must be self-contained.
499+
490500
## Metadata
491501

492502
Metadata can be defined at both the flag set (as a sibling of [flags](#flags)) and within each flag.

docs/reference/specifications/custom-operations/fractional-operation-spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,6 @@ func FractionalEvaluation(values, data interface{}) interface{} {
227227
}
228228
}
229229

230-
return ""
230+
return nil
231231
}
232232
```

docs/reference/specifications/custom-operations/semver-operation-spec.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The 'sem_ver' evaluation rule contains exactly three items:
2121
1. Target property value: the resolved value of the target property referenced in the targeting rule
2222
2. Operator: One of the following: `=`, `!=`, `>`, `<`, `>=`, `<=`, `~` (match minor version), `^` (match major version)
2323
3. Target value: this needs to resolve to a semantic versioning string. If this condition is not met, the evaluator should
24-
log an appropriate error message and return `false`
24+
log an appropriate error message and return `null`
2525

2626
The `sem_ver` evaluation returns a boolean, indicating whether the condition has been met.
2727

@@ -35,7 +35,7 @@ The following flow chart depicts the logic of this evaluator:
3535
flowchart TD
3636
A[Parse targetingRule] --> B{Is an array containing exactly three items?};
3737
B -- Yes --> C{Is targetingRule at index 0 a semantic version string?};
38-
B -- No --> D[Return false];
38+
B -- No --> D[Return null];
3939
C -- Yes --> E{Is targetingRule at index 1 a supported operator?};
4040
C -- No --> D;
4141
E -- Yes --> F{Is targetingRule at index 2 a semantic version string?};

docs/reference/specifications/custom-operations/string-comparison-operation-spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The following flow chart depicts the logic of this evaluator:
3232
flowchart TD
3333
A[Parse targetingRule] --> B{Is an array containing exactly two items?};
3434
B -- Yes --> C{Is targetingRule at index 0 a string?};
35-
B -- No --> D[Return false];
35+
B -- No --> D[Return null];
3636
C -- Yes --> E{Is targetingRule at index 1 a string?};
3737
C -- No --> D;
3838
E -- No --> D;

docs/reference/specifications/providers.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ In addition to the built-in evaluators provided by JsonLogic, the following cust
239239
- [Semantic version evaluation](../../reference/custom-operations/semver-operation.md)
240240
- [StartsWith/EndsWith evaluation](../../reference/custom-operations/string-comparison-operation.md)
241241

242+
### Shared Evaluator Resolution
243+
244+
Before evaluating a flag's targeting rules, providers resolve any `$ref` references by replacing them with the corresponding entry from the `$evaluators` object defined in the flag set.
245+
Nested references (`$ref` within a `$ref`) are not supported; each shared evaluator must be self-contained.
246+
242247
### Targeting Key
243248

244249
Similar to the flagd daemon, in-process providers map the [targeting-key](https://openfeature.dev/specification/glossary#targeting-key) into a top level property of the context used in rules, with the key `"targetingKey"`.

0 commit comments

Comments
 (0)