Skip to content

feat: public feature_flags surface on track/patch (DEV-1214)#10

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/dev-1214-go-feature-flags
Open

feat: public feature_flags surface on track/patch (DEV-1214)#10
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/dev-1214-go-feature-flags

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Adds the public feature_flags surface to the Go core SDK (DEV-1214), matching the JS event-shipper wire contract. Additive-only: existing callers are unaffected.

  • Public API — a new optional FeatureFlags map[string]string on Event, AIEvent, BeginOptions, PatchOptions, FinishOptions, plus interaction.SetFeatureFlags(map[string]string). Maps are defensively cloned at the boundary.
  • Wire shape — serializes to a top-level feature_flags object (sibling of ai_data/properties/attachments) on the events/track_partial body, exactly the ratified shape (dawn ingest TrackEventSchema: feature_flags: z.record(z.string()).optional(); raindrop-js core event-shipper body[0].feature_flags). Tagged json:"feature_flags,omitempty" and never populated when nil, so omitted → key absent.
  • Partial lifecycle — flags merge across patches like properties (later keys win, earlier keys retained), so flags set on Begin/Patch survive to the finalized flush.
  • Conformance driver — declares the events.feature_flags capability and maps the harness feature_flags step arg (a string→string object; non-string values are refused loudly) through track/track_ai/begin/patch/finish.
  • Harness pin — bumped HARNESS_REF to 6bd23884ce390dd56b29d4ba32277a2d9d9ec0a8 (the main SHA where the feature_flags scenarios are stable); the existing failures.txt is exactly green at this SHA (no unrelated ratchet churn).
  • Version bumped 0.1.50.1.6.

Wire-shape proof

Actual request bodies produced by the SDK's public API (captured from TrackAI):

With FeatureFlags set — top-level feature_flags, multibyte value round-trips unmangled:

{"event_id":"","user_id":"flags-u1","event":"chat","timestamp":"",
 "ai_data":{"input":"How do I enable reasoning?","output":"Toggle it in Settings.","model":"mock-gpt"},
 "properties":{"$context":{}},"attachments":[],
 "feature_flags":{"locale-label":"café-日本語","prompt-version":"v2"},"is_pending":false}

Without FeatureFlags — no feature_flags key at all (byte-identical to pre-change bodies for existing callers):

{"event_id":"","user_id":"flags-u1","event":"chat","timestamp":"",
 "ai_data":{"input":"hello","output":"world","model":"mock-gpt"},
 "properties":{"$context":{}},"attachments":[],"is_pending":false}

Asserted by unit tests in feature_flags_test.go:

  • TestTrackAISerializesFeatureFlags — top-level feature_flags string→string object; multibyte round-trip.
  • TestOmittedFeatureFlagsLeaveBodyUnchanged — omitted flags leave no feature_flags key on the wire.
  • TestInteractionFeatureFlagsMergeAcrossPartials, TestFeatureFlagsClonedFromCaller.

Verification

Unit tests + linters (repo CI checks):

gofmt -l .        → clean
go vet ./...      → OK
go test ./...     → ok  github.com/raindrop-ai/go
go test -race ./... → ok  github.com/raindrop-ai/go

Fault lane (harness 6bd23884…, driver conformance/driver, conformance/failures.txt) — from this PR's fault-lane CI job:

feature-flags-request-shape@fault               expected_fail     11  missing_feature (ratchet)
57 result(s): 34 expected_fail, 4 not_applicable, 11 pass, 8 unsupported

Lane exits 0 (reproduced identically locally).

feature-flags-request-shape@fault does not PASS for this SDK, and cannot: the scenario asserts endpoint: events/track with a JSON array body ($[0].feature_flags…), but the Go SDK ships every event via events/track_partial as a single object. This is the pre-existing DEV-1149 route gap shared by all events/track scenarios (all ratcheted missing_feature), not specific to feature_flags — so it is ratcheted the same way. The feature_flags wire shape itself is correct (top-level string→string object, verified above); only the route/batching differ.

Prod readback (feature-flags-readback@prod) — PASSED in this PR's prod-lane CI job (real production ingest + Query API round-trip):

feature-flags-readback@prod            pass            38881
13 result(s): 2 not_applicable, 10 pass, 1 unsupported

This is the meaningful end-to-end proof that feature_flags set via the public Go API lands in ingest and reads back through the Query API. (A local prod run from this session was blocked by an expired session RAINDROP_WRITE_KEY; CI uses a valid org credential, so the prod round-trip is verified there.)

Safety

Additive-only, no behavior change for existing callers. feature_flags uses json:",omitempty" and is never populated when nil, so callers that don't set it produce byte-identical request bodies — proven by TestOmittedFeatureFlagsLeaveBodyUnchanged (asserts no feature_flags key reaches the wire when omitted). No regressions observed in the full unit suite (incl. -race) or the fault lane (exit 0, zero unrelated ratchet churn); the ratchet file gained exactly one line for the newly-in-corpus feature-flags scenario.

Link to Devin session: https://app.devin.ai/sessions/5298408969504710a5a2e2a9744b6320
Requested by: @pavel-y-ivanov

Add an optional FeatureFlags map[string]string to the public event surfaces
(Event, AIEvent, BeginOptions, PatchOptions, FinishOptions) and
interaction.SetFeatureFlags. It serializes to a top-level feature_flags
string->string object on the events/track_partial body — the ratified wire
shape (dawn ingest TrackEventSchema; raindrop-js core event-shipper). Omitted
flags leave the wire body byte-identical for existing callers (json omitempty;
nil is never populated).

Flip the conformance driver: declare the events.feature_flags capability and
map the harness feature_flags step arg (string-valued object, refused loudly
otherwise) through track/track_ai/begin/patch/finish. Bump HARNESS_REF to the
main SHA where the feature_flags scenarios are stable and ratchet
feature-flags-request-shape@fault as missing_feature (DEV-1149 route gap: the
SDK ships events/track_partial single-object bodies, not the events/track
array batch the scenario asserts).

Bump Version to 0.1.6.

Co-Authored-By: pavel <pavel.y.ivanov@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

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.

0 participants