From 572e59dc79296a652a928a402f15d01c482294c0 Mon Sep 17 00:00:00 2001 From: Tyler Potter Date: Tue, 3 Nov 2026 18:55:36 -0600 Subject: [PATCH] Add precomputed dependent flag fixtures Model ordered dependency evaluation telemetry and assignment presence on top of the current shared fixture corpus. Co-Authored-By: Codex GPT-5 Environment: Datadog workspace Co-authored-by: tyler.potter --- precomputed-assignments/README.md | 8 + .../cases/emissions/dependent-flags.json | 187 ++++++++++++++++++ schemas/precomputed-assignment.schema.json | 5 + 3 files changed, 200 insertions(+) create mode 100644 precomputed-assignments/cases/emissions/dependent-flags.json diff --git a/precomputed-assignments/README.md b/precomputed-assignments/README.md index d67a0fe0..a81134af 100644 --- a/precomputed-assignments/README.md +++ b/precomputed-assignments/README.md @@ -78,6 +78,7 @@ exposure and evaluation events. ```json "expectations": { "noUnmatchedEvents": true, + "orderedEvents": true, "exposures": [ {"_count": 1, "flag": "my-flag"} ], @@ -106,6 +107,13 @@ When `true`, the test runner asserts that all received events (both exposures and evaluations) are consumed by matchers. No extra events allowed. Applies to both event types. +### `orderedEvents` + +When `true`, the test runner also asserts that events are emitted in matcher +order. This is useful when dependency evaluations or exposures must precede the +root flag's event. Runners that do not support ordered assertions may ignore the +field unless the fixture includes that platform explicitly. + ### Control fields All fields prefixed with `_` are control fields, not match fields: diff --git a/precomputed-assignments/cases/emissions/dependent-flags.json b/precomputed-assignments/cases/emissions/dependent-flags.json new file mode 100644 index 00000000..c057ce57 --- /dev/null +++ b/precomputed-assignments/cases/emissions/dependent-flags.json @@ -0,0 +1,187 @@ +{ + "name": "dependent-flags", + "description": "A successful dependency graph emits all reached evaluations and exposures; a graph with a missing node returns the caller default, emits the missing and propagated ancestor evaluations, and emits no exposures.", + "_include": [ + { + "platform": "web" + } + ], + "context": { + "targetingKey": "dependent-subject", + "attributes": { + "plan": "pro" + } + }, + "response": { + "data": { + "attributes": { + "createdAt": "2026-10-21T00:00:00Z", + "flags": { + "fixture.dependent.success": { + "allocationKey": "allocation-success-root", + "variationKey": "success-on", + "variationType": "boolean", + "variationValue": true, + "reason": "TARGETING_MATCH", + "doLog": true, + "dependencyEvaluations": [ + { + "flagKey": "fixture.dependent.success.leaf", + "isPresentInAssignment": true + }, + { + "flagKey": "fixture.dependent.success.parent", + "isPresentInAssignment": true + } + ] + }, + "fixture.dependent.success.leaf": { + "allocationKey": "allocation-success-leaf", + "variationKey": "leaf-on", + "variationType": "boolean", + "variationValue": true, + "reason": "TARGETING_MATCH", + "doLog": true + }, + "fixture.dependent.success.parent": { + "allocationKey": "allocation-success-parent", + "variationKey": "parent-on", + "variationType": "boolean", + "variationValue": true, + "reason": "TARGETING_MATCH", + "doLog": true + }, + "fixture.dependent.failure": { + "reason": "ERROR", + "errorCode": "FLAG_NOT_FOUND", + "dependencyEvaluations": [ + { + "flagKey": "fixture.dependent.failure.leaf", + "isPresentInAssignment": false + }, + { + "flagKey": "fixture.dependent.failure.missing", + "reason": "ERROR", + "errorCode": "FLAG_NOT_FOUND" + }, + { + "flagKey": "fixture.dependent.failure.parent", + "reason": "ERROR", + "errorCode": "FLAG_NOT_FOUND" + } + ] + }, + "fixture.dependent.failure.leaf": { + "allocationKey": "allocation-failure-leaf", + "variationKey": "leaf-on", + "variationType": "boolean", + "variationValue": true, + "reason": "TARGETING_MATCH", + "doLog": true + } + } + } + } + }, + "evaluations": [ + { + "flag": "fixture.dependent.success", + "variationType": "boolean", + "defaultValue": false, + "expectedResult": { + "value": true, + "reason": "TARGETING_MATCH", + "errorCode": null, + "variantKey": "success-on" + } + }, + { + "flag": "fixture.dependent.failure", + "variationType": "boolean", + "defaultValue": false, + "expectedResult": { + "value": false, + "reason": "ERROR", + "errorCode": "FLAG_NOT_FOUND", + "variantKey": null + } + } + ], + "expectations": { + "noUnmatchedEvents": true, + "orderedEvents": true, + "exposures": [ + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success.leaf" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success.parent" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success" + } + } + ], + "evaluationEvents": [ + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success.leaf" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success.parent" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.success" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.failure.leaf" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.failure.missing" + }, + "error": { + "message": "FLAG_NOT_FOUND" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.failure.parent" + }, + "error": { + "message": "FLAG_NOT_FOUND" + } + }, + { + "_count": 1, + "flag": { + "key": "fixture.dependent.failure" + }, + "error": { + "message": "FLAG_NOT_FOUND" + } + } + ] + } +} diff --git a/schemas/precomputed-assignment.schema.json b/schemas/precomputed-assignment.schema.json index 822a6413..829f7e9c 100644 --- a/schemas/precomputed-assignment.schema.json +++ b/schemas/precomputed-assignment.schema.json @@ -285,6 +285,11 @@ "default": false, "description": "When true, assert that all received events (exposures and evaluations) are consumed by matchers. No extra events allowed." }, + "orderedEvents": { + "type": "boolean", + "default": false, + "description": "When true, assert that exposure and evaluation events are emitted in the order declared by their matcher lists." + }, "exposures": { "type": "array", "items": {