feat: public feature_flags surface on track/patch (DEV-1214) - #21
Open
devin-ai-integration[bot] wants to merge 1 commit into
Open
feat: public feature_flags surface on track/patch (DEV-1214)#21devin-ai-integration[bot] wants to merge 1 commit into
devin-ai-integration[bot] wants to merge 1 commit into
Conversation
Add an optional feature_flags map (string->string) to the public event surfaces (AiEvent, Event, BeginOptions, PatchOptions, FinishOptions) plus Interaction::set_feature_flags/set_feature_flag. Flags serialize verbatim as a top-level feature_flags object on the wire (sibling of ai_data/properties), matching the JS event-shipper. Additive-only: omitted flags leave the request body byte-identical (skip_serializing_if on the buffer payload). Wire flags through EventPatch buffer + merge (last write wins per key). Declare the events.feature_flags conformance capability and map the harness feature_flags step arg through to the public API. Bump harness pin cf744e9 (#47) -> 1a646e1 (#53): the old pin predated 18 ratcheted scenarios (baseline exit 1) and the feature_flags capability/scenarios; Co-Authored-By: pavel <pavel.y.ivanov@gmail.com> #53 is the SHA this repo's failures.txt is authored against (baseline green).
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an additive, optional
feature_flagsmap to the Rust SDK's public event surfaces (DEV-1214), mirroring the JS event-shipper's publicfeatureFlags.Flags flow through the existing
EventPatchbuffer and serialize verbatim as a top-levelfeature_flagsstring→string object on the wire — a sibling ofai_data/properties, matching the JSevent-shipper.tsshape and dawn ingest'sTrackEventSchema.feature_flags: z.record(z.string()):POST /events/track_partial { "event_id": "…", "user_id": "flags-u1", "event": "chat", "ai_data": { "input": "…", "output": "…", "model": "mock-gpt" }, "properties": { … }, "feature_flags": { "prompt-version": "v2", "locale-label": "café-日本語" }, // ← new, top-level "is_pending": false }Across a
begin→patch→finishlifecycle, flags merge likeproperties(last write wins per key).Conformance driver: declares the
events.feature_flagscapability and maps the harnessfeature_flagsstep arg through to the public API (parsing only string values, as the wire contract isRecord<string,string>).Wire-shape proof (unit tests)
New tests in
tests/wire_format.rs(all green):feature_flags_serialize_as_top_level_string_map— asserts atrack_aicall with flags emits a top-levelfeature_flagsobject with the exact keys/values (UTF-8 multibyte round-trips verbatim), snake_case (notfeatureFlags), and that flags do not leak intoai_dataorproperties.omitted_feature_flags_leave_body_unchanged— the additive-only guarantee: a caller that passes no flags produces a body with nofeature_flagskey at all (asserted both on the parsed JSON and on the raw serialized bytes).feature_flags_merge_across_partial_lifecycle— flags supplied viabegin+set_feature_flag+finishmerge (last-write-wins) onto the final payload.Safety (bounded)
Additive-only; no behavior change for existing callers. The field defaults to an empty
BTreeMap, and the wire payload uses#[serde(skip_serializing_if = "BTreeMap::is_empty")], so an omitted-flags request is byte-identical to before this change (no"feature_flags": {}and nonull). This is proven byomitted_feature_flags_leave_body_unchanged, which asserts the raw request bytes contain nofeature_flagstoken. Existing structs keep compiling via..Default::default().Local verification (all before opening this PR)
Full unit suite + linters on the SDK crate (e2e suite excluded — it hits the live backend, exactly as CI does):
Fault-lane harness proof
Ran the pinned harness fault lane locally against this repo's driver:
Scenario line and final summary (harness
1a646e1, sdkraindrop-rust@0.0.9):Runner exit code: 0 (overall fault lane green).
ratchet-add.txtandratchet-remove.txtwere both empty — no ratchet change requested, soconformance/failures.txtis untouched.What was verified vs. not — read this
feature-flags-request-shape@faultdoes not PASS for this SDK, and it cannot as currently architected — but this is a pre-existing route gap (DEV-1149), not a feature_flags problem. The scenario asserts the request lands on the batchedendpoint: events/track(body_root: array) route. This Rust SDK deliberately ships every track/track_ai as a single-object POST toevents/track_partial, so it records 0 attempts onevents/track— identical totrack-single,track-attachments,track-nested-properties, and every otherevents/trackscenario, all already ratchetedmissing_feature(DEV-1149). The driver did execute the scenario (attempts: 1) and correctly mapped thefeature_flagsarg through; the failure is purely the route assertion. Because the scenario isstatus: experimentalat the pinned harness SHA, it runs report-only and the lane exits 0 with no ratchet entry required. Thefeature_flagswire shape itself is proven directly by the unit tests above on the route this SDK actually uses.Harness pin bump (needs a reviewer's eye)
HARNESS_REFis bumpedcf744e9(#47) →1a646e1(#53). This was necessary and independently correct: the old pin was already broken for this repo — it predated 18 scenarios thatconformance/failures.txtratchets (batching-, size-limit-, unicode-, negative-path-, concurrency-*,hot-path-sustained-track-ai,shutdown-drain-hang-deadline), so a baseline run at the old pin exits 1 with "stale entry" run-failures, and the old pin also lacks theevents.feature_flagscapability this PR's driver advertises (a handshake refusal → exit 2).1a646e1(#53) is the harness SHAfailures.txtis actually authored against: at that SHA all 33 ratcheted scenarios exist, the baseline (pre-this-PR) driver runs green (exit 0), andevents.feature_flags+ the feature_flags scenarios are present (the latter stillexperimental). Bumping the pin follows the workflow's own documented one-line-PR procedure.Link to Devin session: https://app.devin.ai/sessions/2128759db2b0422e99df47a9bca5a82b
Requested by: @pavel-y-ivanov
Note
Medium Risk
Changes public event types and ingest payload shape, but empty flags are omitted and behavior for callers that do not set flags is unchanged; primary risk is incorrect flag merge or wire placement affecting downstream ingest.
Overview
Release 0.0.9 adds an optional
feature_flags: BTreeMap<String, String>onEvent,AiEvent,BeginOptions,PatchOptions, andFinishOptions, plusInteraction::set_feature_flags/set_feature_flag. Flags flow throughEventPatchand serialize as a top-levelfeature_flagsobject onevents/track_partial(omitted when empty so existing callers stay byte-identical).Conformance: the driver advertises
events.feature_flags, maps harness step args (string values only), and CI bumpsHARNESS_REFto the SHA that includes feature-flag scenarios and matchesfailures.txt.Tests: new
wire_formatcases cover top-level shape, omission when unset, and merge across begin/patch/finish (last write wins).Reviewed by Cursor Bugbot for commit 09187c3. Bugbot is set up for automated code reviews on this repo. Configure here.