Repository navigation
fix(flags): reject empty variant keys for new variants - #118803
Conversation
|
😎 Merged successfully - details. |
🤖 CI report
|
|
Risk: No findings This change adds the empty string to the reserved variant-key set, so API/MCP/Terraform writes can no longer create a Sentinel reviewed |
There was a problem hiding this comment.
Approved.
The change enters API-contract and write-path territory, with owning-team authorship providing the required assurance. No unresolved substantive concerns or other refusal grounds were found.
- Author wrote 52% of the modified lines and has 47 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 19L, 2F substantive, 74L/5F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (74L, 5F, two-areas, fix) |
| stamphog 2.6.0 | .stamphog/policy.yml @ 440f01f · reviewed head 440f01f |
Problem
""variant key shows that variant's traffic as "no response" in flag calls charts, breakdowns and SQL.flag_evaluationsstores''for both a""variant and a missing response.''as NULL on a materialized events column, and fix(flags): read flag_evaluations response sentinels as NULL #117930 does the same forflag_evaluations.""variant.Changes
""variant key now fails with "Variant keys can't be empty. Enter a key for each variant.""null"the same way:""joinsRESERVED_NEW_VARIANT_KEYS."". An update rejects it only when the stored flag lacks a""variant, so existing flags with one stay editable." "does not read as NULL, so it stays allowed.reserved_variant_keycode. No client branches on it, and the fix is the same: choose another key. Only the message differs, because "The variant key is reserved" reads wrong.Note
The held-key exception holds only while the #50084 validation rollout leaves
structural.multivariate.variants[].key.blankunenforced, as production does today. Once that rule or*is enforced, the structural tier rejects every""key, including one the stored flag already has. That rule has no stored-flag context. It is out of scope here.Decisions that need no code change:
""to the shared set changes nothing there.validateFeatureFlagVariantKeyalready rejects an empty key with "Please set a key", with no exception for a saved flag. The UI already cannot save a flag that has a""variant. That predates this PR and stays as is.Mechanical: four API tests used
""as their example of a key that fails the structural tier but passes the serde guard. Three now use a 401-character key. The fourth needs two key violations, so it PATCHes a stored flag that already holds"".docs/internal/feature-flags/api-writes.mdcovers the new rule.How did you test this code?
Ran
test_filters_validation.py,test_feature_flag_config_v2_updates.py, and theTestFeatureFlagFiltersEnforcementandTestFeatureFlagFiltersMetricsclasses locally. Did not run the fulltest_feature_flag.py; CI covers it.Test rationale: Extended
TestReservedVariantKey, the parameterized cases #118224 added for"null". New""rows cover rejection on create (log-only and full enforcement), rejection when an update adds"", and acceptance when an update keeps a stored""(log-only). The rejection rows also check the new message. With the old reserved set, three of the new rows fail. No new test file.Release status
Docs update
Internal doc only (
docs/internal/feature-flags/api-writes.md).🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Opus 5.5 (
claude-opus-5-5)/gopipeline with/simplifyand/comment-cleanup. Invoked/improving-drf-endpoints,/writing-user-facing-copy,/writing-tests,/writing-code-commentsand/writing-pr-descriptions.gh pr list --state open --search "empty variant key"and"reserved variant key") found no PR that already does this.https://claude.ai/code/session_01PRnR48WeQWBNhWDPGLNcNL