You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/commands/add-feature-flag.md
+8-5Lines changed: 8 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,15 +31,18 @@ Critically, **none of this is expressible in code** — gating (especially `admi
31
31
32
32
## Steps
33
33
34
-
1.**Register the flag.** Add an entry to `FEATURE_FLAG_FALLBACKS`in `apps/sim/lib/core/config/feature-flags.ts`, mapping the flagname (kebab-case) to the secret consulted when AppConfig isn't the source of truth. A truthy secret turns the flag on globally:
34
+
1.**Define the flag.** Add one entry to the `FEATURE_FLAGS` registry in `apps/sim/lib/core/config/feature-flags.ts`. Each entry is the flag's whole definition — name (kebab-case key), `description`, and the `fallback`secret consulted when AppConfig isn't the source of truth (truthy ⇒ on globally):
35
35
36
36
```ts
37
-
const FEATURE_FLAG_FALLBACKS = {
38
-
'<flag-name>': () =>env.<FLAG_SECRET>,
37
+
const FEATURE_FLAGS = {
38
+
'<flag-name>': {
39
+
description: '<what this gates>',
40
+
fallback: () =>env.<FLAG_SECRET>,
41
+
},
39
42
}
40
43
```
41
44
42
-
Add `<FLAG_SECRET>` to `apps/sim/lib/core/config/env.ts` (and the deployment's secret store). Do **not** add any org/user/admin defaults here — that gating exists only in AppConfig.
45
+
Add `<FLAG_SECRET>` to `apps/sim/lib/core/config/env.ts` (and the deployment's secret store). Do **not** add org/user/admin defaults here — that gating exists only in AppConfig. Adding the entry makes `<flag-name>` a valid `FeatureFlagName`.
43
46
44
47
2.**Gate the call site.** Call `isFeatureEnabled` with whatever ids you have — admin status is resolved internally, so callers never pass it:
45
48
@@ -59,7 +62,7 @@ Critically, **none of this is expressible in code** — gating (especially `admi
59
62
60
63
4.**Test.** Add a case to `apps/sim/lib/core/config/feature-flags.test.ts`: use `withAppConfig({ flags: { ... } })` to cover the gating rule (mock `isPlatformAdmin` for the `admins` clause), and toggle the fallback secret to cover the off-AppConfig path.
61
64
62
-
5.**Clean up after rollout.** When the feature ships to everyone, delete the flagfrom `FEATURE_FLAG_FALLBACKS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
65
+
5.**Clean up after rollout.** When the feature ships to everyone, delete the flag's entry from `FEATURE_FLAGS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
Copy file name to clipboardExpand all lines: .cursor/commands/add-feature-flag.md
+8-5Lines changed: 8 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,15 +26,18 @@ Critically, **none of this is expressible in code** — gating (especially `admi
26
26
27
27
## Steps
28
28
29
-
1.**Register the flag.** Add an entry to `FEATURE_FLAG_FALLBACKS`in `apps/sim/lib/core/config/feature-flags.ts`, mapping the flagname (kebab-case) to the secret consulted when AppConfig isn't the source of truth. A truthy secret turns the flag on globally:
29
+
1.**Define the flag.** Add one entry to the `FEATURE_FLAGS` registry in `apps/sim/lib/core/config/feature-flags.ts`. Each entry is the flag's whole definition — name (kebab-case key), `description`, and the `fallback`secret consulted when AppConfig isn't the source of truth (truthy ⇒ on globally):
30
30
31
31
```ts
32
-
const FEATURE_FLAG_FALLBACKS = {
33
-
'<flag-name>': () =>env.<FLAG_SECRET>,
32
+
const FEATURE_FLAGS = {
33
+
'<flag-name>': {
34
+
description: '<what this gates>',
35
+
fallback: () =>env.<FLAG_SECRET>,
36
+
},
34
37
}
35
38
```
36
39
37
-
Add `<FLAG_SECRET>` to `apps/sim/lib/core/config/env.ts` (and the deployment's secret store). Do **not** add any org/user/admin defaults here — that gating exists only in AppConfig.
40
+
Add `<FLAG_SECRET>` to `apps/sim/lib/core/config/env.ts` (and the deployment's secret store). Do **not** add org/user/admin defaults here — that gating exists only in AppConfig. Adding the entry makes `<flag-name>` a valid `FeatureFlagName`.
38
41
39
42
2.**Gate the call site.** Call `isFeatureEnabled` with whatever ids you have — admin status is resolved internally, so callers never pass it:
40
43
@@ -54,7 +57,7 @@ Critically, **none of this is expressible in code** — gating (especially `admi
54
57
55
58
4.**Test.** Add a case to `apps/sim/lib/core/config/feature-flags.test.ts`: use `withAppConfig({ flags: { ... } })` to cover the gating rule (mock `isPlatformAdmin` for the `admins` clause), and toggle the fallback secret to cover the off-AppConfig path.
56
59
57
-
5.**Clean up after rollout.** When the feature ships to everyone, delete the flagfrom `FEATURE_FLAG_FALLBACKS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
60
+
5.**Clean up after rollout.** When the feature ships to everyone, delete the flag's entry from `FEATURE_FLAGS`, the `<FLAG_SECRET>` env entry, the AppConfig document, the call sites, and the test. Leaving dead flags around is the main failure mode of flag systems.
0 commit comments