Skip to content

feat: auto-set anonymous for contexts without keys at build time#249

Open
kinyoklion wants to merge 4 commits intomainfrom
devin/1773183728-anon-context-key-docs
Open

feat: auto-set anonymous for contexts without keys at build time#249
kinyoklion wants to merge 4 commits intomainfrom
devin/1773183728-anon-context-key-docs

Conversation

@kinyoklion
Copy link
Member

@kinyoklion kinyoklion commented Mar 10, 2026

Requirements

  • I have added test coverage for new or changed functionality — Existing tests pass; no new unit tests added yet for the auto-anonymous logic. Reviewer should decide if additional coverage is needed.
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

#222

Describe the solution you've provided

This PR makes a behavioral change to LDAttributesBuilder._build() so that a context created without a key is automatically set to anonymous at build time (instead of being treated as invalid). The SDK will then generate and persist a stable UUID key during start() or identify().

This means LDContextBuilder().kind('user').build() now produces a valid anonymous context rather than an invalid one.

Behavioral logic in _build():

  • No key + anonymous never explicitly set → auto-anonymous (via local effectiveAnonymous, no builder mutation)
  • No key + .anonymous(false) explicitly called → invalid context (returns null)
  • No key + .anonymous(true) explicitly called → anonymous as before

An _anonymousExplicitlySet flag tracks whether .anonymous() was ever called, so _build() can distinguish "default false" from "explicitly set to false". The builder state is never mutated by _build().

Contract test compatibility: Instead of suppressing contract tests, the contract test service (_flattenedListToContext) now explicitly calls anonymous(false) when deserializing JSON contexts that don't have anonymous: true. This preserves the existing contract test expectations (keyless JSON contexts remain invalid) while reserving the auto-anonymous behavior for the builder API.

Documentation updates in four places:

  1. LDAttributesBuilder.anonymous() — Explains auto-anonymous behavior when no key is provided, with code examples for both explicit and automatic anonymous contexts.
  2. LDContextBuilder.kind() — Corrected doc to explain that omitting the key makes the context automatically anonymous at build time.
  3. LDClient.start() — Notes that anonymous contexts without keys get auto-generated keys during startup.
  4. LDClient.identify() — Notes that anonymous contexts without keys get auto-generated keys before identify.

Items for reviewer attention:

  • Semantic change: LDContextBuilder().kind('user').build() previously returned an invalid context; it now returns a valid anonymous context. Any code relying on this being invalid will behave differently.
  • No new unit tests: The _anonymousExplicitlySet logic paths (auto-anonymous, explicit false + no key = invalid) are not covered by dedicated tests. Should tests be added?
  • mergeContext path: mergeContext calls anonymous(attributes.anonymous) which will set _anonymousExplicitlySet = true. This means reconstructing a context from an existing one will always have anonymous explicitly set — verify this is acceptable.
  • Contract test service logic: The if (attributes['anonymous'] != true) check may call anonymous(false) redundantly after setValue already processed it. This is harmless but could be cleaner.

Describe alternatives you've considered

  • Originally this was docs-only, but per reviewer feedback the builder implementation was updated to auto-set anonymous for keyless contexts.
  • Considered mutating _anonymous directly in _build(), but per Bugbot and reviewer feedback, switched to a local effectiveAnonymous computation to avoid side effects.
  • Initially suppressed 4 contract tests that expected keyless contexts to be invalid. Per reviewer feedback, switched to explicitly setting anonymous(false) in the contract test service's JSON conversion path instead.

Additional context

Verification was performed by:

  • All existing unit tests pass (ld_context_test.dart: 35 pass, anonymous_context_modifier_test.dart: 6 pass).
  • Running the example app with LDContextBuilder().kind('user').build() (no explicit .anonymous(true)) against LaunchDarkly — the SDK successfully generated a UUID key and connected, confirming the auto-anonymous behavior works end-to-end.
  • Contract tests now pass without suppressions (CI confirmed all checks pass).

Note

Medium Risk
Behavioral change in core context validation/anonymous handling can alter analytics/indexing and any code that previously relied on keyless contexts being invalid; no new tests were added for the new branching logic.

Overview
Keyless contexts built via LDContextBuilder.kind(...).build() now become valid by default: if no key is provided and anonymous was never explicitly set, _build() treats the context as anonymous=true so the SDK can later generate/persist a stable UUID key during start()/identify().

To preserve JSON conversion semantics, the contract test service now explicitly applies anonymous(false) when deserializing contexts unless the JSON set anonymous: true, preventing accidental auto-anonymous during JSON->builder reconstruction. Docs were updated on LDAttributesBuilder.anonymous, LDContextBuilder.kind, and LDClient.start/identify to describe the new behavior.

Written by Cursor Bugbot for commit 0615292. This will update automatically on new commits. Configure here.

Update documentation on LDAttributesBuilder.anonymous(), LDContextBuilder.kind(),
LDClient.start(), and LDClient.identify() to explain that the SDK automatically
generates and persists stable keys for anonymous contexts without keys.

Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.com>
@devin-ai-integration
Copy link
Contributor

🤖 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. Add '(aside)' to your comment to have me ignore it.
  • 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 and CI monitoring

@kinyoklion kinyoklion marked this pull request as ready for review March 10, 2026 23:05
@kinyoklion kinyoklion requested a review from a team as a code owner March 10, 2026 23:05
When a context kind is added without a key, the context is now
automatically set to anonymous at build time. This means
LDContextBuilder().kind('user').build() produces a valid anonymous
context rather than an invalid one. The SDK will generate and persist
a stable key for the context during start() or identify().

Updated documentation on anonymous(), kind(), start(), and identify()
to explain this behavior.

Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Address review feedback: _build() no longer mutates _anonymous as a
side effect. Instead, an _anonymousExplicitlySet flag tracks whether
anonymous() was called. When no key is provided and anonymous was not
explicitly set, the context is automatically anonymous. When
anonymous(false) was explicitly called with no key, the context
remains invalid.

Suppress 4 contract tests that expect invalid contexts for inputs
without keys, as these now produce valid anonymous contexts per the
new auto-anonymous behavior.

Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.com>
@devin-ai-integration devin-ai-integration bot changed the title docs: clarify anonymous context key generation behavior feat: auto-set anonymous for contexts without keys at build time Mar 10, 2026
Instead of suppressing contract tests, explicitly set anonymous(false)
in _flattenedListToContext when the input doesn't have anonymous=true.
This ensures the contract tests pass as before (keyless contexts without
explicit anonymous=true remain invalid during JSON conversion), while
the builder API auto-anonymous behavior is preserved for users who
simply call kind() without a key.

Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.com>
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.

1 participant