Remove FlagRegistry; make FeatureFlagsDebugScreen UI-agnostic#199
Conversation
FeatureFlagsDebugScreen now takes an explicit registry: List<ConfigParam<*>> parameter instead of reading the global FlagRegistry singleton. Pass GeneratedFeaturedRegistry.all (from the new dev.androidbroadcast.featured .application plugin) or build the list inline. Removed: - featured-registry module (FlagRegistry + expect/actual FlagRegistryDelegate) - generateFlagRegistrar task + FlagRegistrarGenerator + GenerateFlagRegistrarTask - LocalFlagEntry.kotlinReference (dead with the registrar generator) - registerSampleFlags() from sample Sample wires the debug UI via SampleFeatureFlags.all. Featured does not keep API compatibility; this is a direct breaking change with no @deprecated shims.
LaunchedEffect uses identity equality on the registry parameter. A caller passing a freshly-allocated list each recomposition would restart the effect every frame. Spell out the stable-reference requirement in the KDoc so callers do not stumble into a silent recomposition loop.
After the FlagRegistry removal, `val params = registry` became a pure rename with no semantic value. Reference the registry parameter directly in the LaunchedEffect body.
- Drop stale :featured-registry:koverVerify from CI workflow; the module no longer exists and Gradle would error on missing project at job start. - Correct FeatureFlagsDebugScreen KDoc: LaunchedEffect compares keys via Any.equals (structural), not identity. Practical guidance unchanged. - Document the key-uniqueness invariant on the registry parameter so callers know a duplicate ConfigParam.key trips LazyColumn at runtime. - Replace "No feature flags registered." empty-state copy with "No feature flags to display." — the global FlagRegistry that the old phrasing referenced no longer exists.
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
There was a problem hiding this comment.
Pull request overview
PR C of a 4-PR redesign that removes the legacy global FlagRegistry runtime singleton and its Gradle-side generateFlagRegistrar codegen, and makes FeatureFlagsDebugScreen take an explicit List<ConfigParam<*>> registry parameter instead of pulling from the singleton. The sample app is updated to pass SampleFeatureFlags.all directly.
Changes:
- Deletes the
featured-registrymodule (singleton + expect/actual delegate + tests) and unwires it fromfeatured-bom,featured-debug-ui,sample/shared, andsettings.gradle.kts. - Removes
GenerateFlagRegistrarTask,FlagRegistrarGenerator, thegenerateFlagRegistrarplugin wiring, the now-deadLocalFlagEntry.kotlinReferenceproperty, and the corresponding tests; CI no longer runs:featured-registry:koverVerify. - Adds
registry: List<ConfigParam<*>>parameter toFeatureFlagsDebugScreen(breaking) with stability/uniqueness KDoc, and addsSampleFeatureFlags.allas the single source of truth for the sample.
Reviewed changes
Copilot reviewed 29 out of 29 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle.kts | Drops :featured-registry from the build. |
| sample/shared/.../SampleFeatureFlags.kt | Adds all: List<ConfigParam<*>> aggregate. |
| sample/shared/.../SampleApp.kt | Removes registerSampleFlags() helper that populated the singleton. |
| sample/shared/build.gradle.kts | Drops dependency on :featured-registry. |
| sample/android-app/.../MainActivity.kt | Passes SampleFeatureFlags.all to the debug screen. |
| featured-registry/** | Module deleted (sources, tests, README, CLAUDE.md, build.gradle.kts). |
| featured-gradle-plugin/.../FeaturedPlugin.kt | Removes generateFlagRegistrar registration and constant. |
| featured-gradle-plugin/.../GenerateFlagRegistrarTask.kt, FlagRegistrarGenerator.kt | Deleted. |
| featured-gradle-plugin/.../LocalFlagEntry.kt | Drops dead kotlinReference getter. |
| featured-gradle-plugin/.../ResolveFlagsTask.kt | KDoc updated to drop reference to the removed task. |
| featured-gradle-plugin/src/test/.../LocalFlagEntryTest.kt | New trimmed test covering remaining isLocal behavior. |
| featured-gradle-plugin/src/test/.../LocalFlagEntryKotlinReferenceTest.kt, FlagRegistrarGeneratorTest.kt, GenerateFlagRegistrarTaskRegistrationTest.kt | Deleted along with the code they covered. |
| featured-gradle-plugin/CLAUDE.md | Drops the row for the removed task. |
| featured-debug-ui/.../FeatureFlagsDebugScreen.kt | New registry parameter, updated LaunchedEffect keys, empty-state copy reworded. |
| featured-debug-ui/README.md | Documents both aggregator and inline-list registry sources. |
| featured-debug-ui/build.gradle.kts | Drops dependency on :featured-registry. |
| featured-bom/build.gradle.kts | Drops :featured-registry from the BOM. |
| CHANGELOG.md | Adds Removed + Changed (breaking) entries under Unreleased. |
| .github/workflows/ci.yml | Removes the stale :featured-registry:koverVerify invocation. |
Summary
Completes the 4-PR redesign of Featured's flag registry (PR C of 4).
PR A (#197) added per-module
featured-manifest.jsonproducer; PR B (#198)added the
dev.androidbroadcast.featured.applicationaggregator plugin +GeneratedFeaturedRegistry. This PR removes the legacyFlagRegistryruntimesingleton and the
generateFlagRegistrarGradle codegen pipeline, and makesFeatureFlagsDebugScreenUI-agnostic.What changed
FeatureFlagsDebugScreensignature (breaking):Pass
GeneratedFeaturedRegistry.all(recommended for multi-module apps using theaggregator plugin) or build the list inline. Each
ConfigParam.keymust be uniquewithin the list; the screen documents that the
LaunchedEffectkeys viaequals(structural) and asks callers for a stable reference.
Removed:
featured-registrymodule —FlagRegistryglobal singleton + expect/actualFlagRegistryDelegate.featured-gradle-plugin—generateFlagRegistrartask,FlagRegistrarGenerator,GenerateFlagRegistrarTask. Per-moduleGeneratedFlagRegistrar.ktis no longer generated.LocalFlagEntry.kotlinReference— became dead with the registrar generator.registerSampleFlags()from the sample.Sample wiring:
SampleFeatureFlags.all: List<ConfigParam<*>>— single source of truth.MainActivitypassesregistry = SampleFeatureFlags.allto the debug UI.Docs:
CHANGELOG.md—### Removed+### Changedentries in[Unreleased]..wiki/; will be pushed after this PR merges.featured-debug-ui/README.mdandfeatured-gradle-plugin/CLAUDE.mdupdated.CI:
:featured-registry:koverVerifyGradle invocation from.github/workflows/ci.yml.Why
The previous design coupled the Debug UI to a runtime singleton populated via a
generated
GeneratedFlagRegistrarper module. With the new aggregator plugin(PR B), the consumer-side flow is declarative —
featuredAggregation(project(...))produces a typed
GeneratedFeaturedRegistry.all. The singleton becomes redundant,and the Debug UI can take the list as an explicit parameter, removing the global
state and making the screen testable / reusable.
Featured does not keep API compatibility — direct removal, no
@Deprecatedshims.Status
/simplifyval params = registryalias inlined/finalizeround 10da39c0(Tests & Coverage, Analyze Kotlin, dependency-review, submit-gradle, Build Android, Lint, Build iOS, CodeQL)How to test
Automated (all PASS locally before push):
./gradlew spotlessCheck./gradlew :featured-gradle-plugin:check./gradlew :core:jvmTest+:featured-debug-ui:jvmTest+:featured-compose:jvmTest./gradlew :sample:android-app:assembleDebug./gradlew :sample:shared:jvmJarFlagRegistry|GeneratedFlagRegistrar|featured-registry|registerSampleFlagsin*.kt/*.kts. Only intentional[Unreleased]CHANGELOG entries + historical fixture-report remain in*.md.Manual smoke (recommended pre-merge):
:sample:android-app:assembleDebugon device/emulator, open the «Debug flags» entry, verify all 5 flags appear and togglingmain_button_redpersists.Release notes
Artifacts
swarm-report/pr-c-ui-agnostic-debug-state.mdswarm-report/pr-c-ui-agnostic-debug-finalize.mdChecklist
/finalizePASS — review fixes applied🤖 Generated with Claude Code