feat: complete SDK feature flag registry and add drift guard (#316) - #420
Merged
El-swaggerito merged 1 commit intoJul 28, 2026
Conversation
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.
Related Issue
Implementation Scope
What #355 already delivers
DEFAULT_FEATURE_FLAGS(src/config/index.ts:206),resolveFeatureFlags:221,isFeatureEnabled:279,assertFeatureEnabled:292ConfigSourceMetadata, thesourcesmap atsrc/config/index.ts:223-238falseDisabledFeatureError(src/errors/unsupported.ts:255)config.resolvedemitssourcesandfeatureFlags(src/config/index.ts:428);src/diagnostics/report.tsincludes both in the safe snapshottests/feature-flags.test.tsdocs/feature-flags.mdThat includes the specific gap I described when applying — the
config.resolvedevent carrying values but no provenance. #355 added it.
What this PR adds
A registered flag can drift out of the registry, silently.
experimentalVaultLocksgates the vault lock intents added in #274, but it ispassed as
readiness.featureFlag— a variable, not a literal — so it neverappeared in a search of
assertFeatureEnabledcall sites. It was missing fromDEFAULT_FEATURE_FLAGS, fromFeatureFlagKey, and from the documented table.An unregistered flag still resolves to
false, so nothing breaks. That isexactly why it is silent: no consumer can discover the flag, and
config.resolveddiagnostics never report its state — which undercuts theconfig-source metadata this issue asks for.
This PR:
experimentalVaultLocksinDEFAULT_FEATURE_FLAGSandFeatureFlagKey, so it resolves, reports and documents like every other flag.tests/feature-flag-registry.test.ts) that scanssrc/forexperimental*flag keys and fails when one is unregistered orundocumented. Adding a flag without registering it is now a test failure.
experimentalMultiAssetVaultandexperimentalAsyncSignerhave zero references insrc/— they gatenothing. Removing them would break a published union, so the documented table
now distinguishes Active from Reserved rather than implying
capabilities the SDK does not have.
src/config/index.ts(+1 line),src/types/index.ts(+1 line),docs/feature-flags.md,tests/feature-flag-registry.test.ts(new)DEFAULT_FEATURE_FLAGSand one added member of theFeatureFlagKeyunion. No behaviour change: the flag already resolved tofalsewhen unregistered and still does.Tests Added / Changed
tests/feature-flag-registry.test.ts— 7 testsfalse, an unknown flag resolving tofalserather than throwingThe scan matches the
'experimental…'string literal anywhere insrc/,not the call site, precisely because the flag that drifted was passed as a
variable. Written against the current tree the canary failed on
experimentalVaultLocksbefore the registry and docs were updated — it is atest that has actually caught the bug it guards.
Verification
verifychain step by stepRun individually rather than through
npm run verify, because that scriptshells out to
npm runper sub-step and this repository's dependency tree ismanaged with a different package manager locally.
test:coveragewas not run;every other step was:
Baseline measured on a clean
git archiveofupstream/main(aa17377):maintscerrorscheck:circularZero regressions, +7 tests. The 2 type errors and the cycle are both in
src/network/fee.ts, introduced by #415 and present onmain; they areunrelated to this issue and left to that module's author.
CI Status
verify:prgates on the whole suite and the type check, both of which arealready failing on
mainfor the reasons above.Acceptance Criteria Coverage
Each criterion, with honest attribution:
falseDisabledFeatureError)tests/feature-flags.test.ts); this PR adds registry-completeness coveragedocs/feature-flags.md); this PR adds the Active/Reserved distinction and the missing flagReviewer Notes
application has since been built by someone else, and I would rather say so
plainly than present their work as mine. If the maintainers prefer to close
this issue as delivered by feat(config): implement configuration source metadata and feature fla… #355, that is a reasonable call and I have no
objection — the drift fix stands on its own and can be retargeted.
experimentalVaultLockswas introduced in Implement SDK vault capability and action intent system #274, whereI deliberately did not register it in
DEFAULT_FEATURE_FLAGSto avoid editingthe config module while it belonged to this issue. That was the right call for
scope and the wrong outcome for discoverability; this is the correct place to
fix it.
experimentalMultiAssetVaultorexperimentalAsyncSignerwould be a breakingchange to a published union for no functional gain. Labelling them follows the
same reasoning the capability registry applies to
plannedentries: state thestatus rather than imply a capability.
Scope — what was deliberately left out
src/network/fee.ts— unrelated to this issue and another contributor's module.