Skip to content

Document fail-closed AND flag gating - #314

Merged
kirich1409 merged 2 commits into
developfrom
fea-20-and-flag-gating
Nov 6, 2026
Merged

kirich1409 merged 2 commits into
developfrom
fea-20-and-flag-gating

Conversation

@kirich1409

@kirich1409 kirich1409 commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Closes #296

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Chore / refactor

Checklist

  • Tests added or updated
  • Docs updated (KDoc, README, CHANGELOG)
  • ./gradlew spotlessCheck passes
  • CHANGELOG.md updated

Notes for reviewers

Issue #296 asks how to enable a feature only when a local gate and a remote rollout are both explicitly true. ValueResolutionStrategy already expresses that. This does not add a combinator, flag container, or DSL, and it does not change ValueResolutionStrategy.Default.

The published recipe is fail-closed and per-param. A selected boolean is true only when localValue?.value == true && remoteValue?.value == true. A missing, failed, or false side stays false. defaultValue is not the client gate, so a flag whose default is false can still become true when both provider values are true. Other keys delegate to ValueResolutionStrategy.Default and keep that candidate's source.

The combined result, true or false, is ConfigValue.Source.UNKNOWN, chosen by the strategy. The library does not stamp a combined source. getValue writes every non-DEFAULT source into the snapshot, so getValueCached sees UNKNOWN.

Two generated flags with the same name are not the AND. Same-name isolation is a separate task (#294). The build already rejects a duplicate key in localFlags and remoteFlags.

README already links the wiki, so this does not paste a second copy of the sample there.

Wiki commit with the same recipe, source, and two-flag statement: https://github.com/AndroidBroadcast/Featured.wiki/commit/215d77d3b6500c8048bfe72d1ec92cd6a6a28680

./gradlew :core:test is not a task on this KMP module. Ran :core:jvmTest --tests dev.androidbroadcast.featured.ValueResolutionStrategyTest (21 tests, 0 failures), :core:koverVerify (line coverage 98.5437%, gate 90%), and spotlessCheck.

Replace the kill-switch sample, which could enable a flag from one side, with
the fail-closed per-param recipe. The combined result source is UNKNOWN, chosen
by the strategy. Two generated flags with the same name are not this mechanism.
No API change.
Keep the fail-closed recipe and put the two-flag statement in one place so
callers do not treat a duplicate key as the gating mechanism.
@kirich1409
kirich1409 marked this pull request as ready for review November 6, 2026 22:44
Copilot AI balanced review requested due to automatic review settings November 6, 2026 22:44
@kirich1409
kirich1409 merged commit 02f82ee into develop Nov 6, 2026
8 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The release warning omits localFlags with default = true, whose generated R8 assumptions can bypass the remote gate, and should recommend remoteFlags to preserve runtime AND gating.

1 open issue
What changed in this PR

Documents how to use the existing ValueResolutionStrategy for per-flag, fail-closed local AND remote gating, addressing #296 without changing runtime APIs or default resolution.

Changes:

  • Replaces the previous gating example with a selected-key recipe requiring both provider values to be explicitly true.
  • Adds tests for missing and false values, combined-source caching, and delegation to default resolution.
  • Records the documentation clarification and distinguishes it from same-name flag isolation.
File Description
core/​src/​commonTest/​kotlin/​dev/​androidbroadcast/​featured/​ValueResolutionStrategyTest.kt Tests the AND recipe, caching, and default delegation.
core/​src/​commonMain/​kotlin/​dev/​androidbroadcast/​featured/​ValueResolutionStrategy.kt Documents the recipe, source semantics, and usage constraints.
CHANGELOG.md Records the guidance update without an API change.

Review effort: Balanced

Comment on lines +37 to +39
* the build rejects that duplicate. Do not AND two accessors. If the guarded client code must
* remain in release binaries, do not declare that one flag as a `localFlags` boolean with
* `default = false`: those flags are release-stripped.
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.

2 participants