Skip to content

Allow deployments to pin the Conductor feature flags - #4205

Merged
RichDom2185 merged 5 commits into
masterfrom
conductor-deployment-config
Jul 30, 2026
Merged

Allow deployments to pin the Conductor feature flags#4205
RichDom2185 merged 5 commits into
masterfrom
conductor-deployment-config

Conversation

@sayomaki

Copy link
Copy Markdown
Contributor

Description

Move conductor feature flag and directory flags into env/constants so that it can be set up deployment wide. Also lock the conductor enable feature if the REACT_APP_CONDUCTOR_ENABLE is set to TRUE, and locked to disabled if set to FALSE, and unset allows toggling of the feature flag, like how it currently works (tri-state).

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Code quality improvements

How to test

Added some simple tests by Claude, not carefully checked yet, but they do pass.

Checklist

  • [?] I have tested this code
  • I have updated the documentation

The Conductor and directory feature flags could only be set per-browser,
via /features, so a deployment had no way to configure them for every
user.

Feature flags can now carry a lockedValue supplied by build-time
configuration, which takes precedence over both the persisted user
override and the flag's default. Locked flags are read-only on /features
and cannot be written back into persisted state.

REACT_APP_CONDUCTOR_ENABLE (TRUE/FALSE/unset) pins conductor.enable;
while it is TRUE, REACT_APP_LANGUAGE_DIRECTORY_URL,
REACT_APP_PLUGIN_DIRECTORY_URL and REACT_APP_MODULES_DIRECTORY_URL pin
the corresponding directory URLs. Leaving them unset preserves today's
behaviour exactly.

The SICP JS override in selectConductorEnable still wins over a pinned
flag, since Source is not in the Language Directory yet and a forced-on
Conductor would break the textbook's runnable snippets.

Also replaces LanguageDirectorySaga's duplicate copy of the default
directory URL with the flag's own defaultValue, so pinning the URL to
that same public value keeps using the bundled npm copy instead of
silently starting a network fetch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@sayomaki
sayomaki requested a review from RichDom2185 July 30, 2026 15:15
@sayomaki sayomaki self-assigned this Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c549628b-188a-44dd-8a6a-a886023cd48f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: pinning Conductor feature flags for deployments.
Description check ✅ Passed All required sections are present and the change summary, type, testing notes, and checklist are filled in.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@RichDom2185 RichDom2185 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks!

@RichDom2185
RichDom2185 enabled auto-merge (squash) July 30, 2026 15:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/new_routes/features.tsx (1)

28-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exclude persisted overrides from locked-state styling.

If a user previously modified a flag, isModified remains true after deployment pinning. The pinned Boolean value can appear selected/bold, and the pinned Number value can show a modification asterisk even though neither is user-controlled.

Use !flag.isLocked && modifiedFlag !== undefined for both cards.

Proposed fix
-  const isModified = modifiedFlag !== undefined;
+  const isModified = !flag.isLocked && modifiedFlag !== undefined;

Also applies to: 49-70

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/new_routes/features.tsx` around lines 28 - 45, Update the isModified
styling condition in both feature-flag card render paths to require
!flag.isLocked alongside modifiedFlag !== undefined. Keep locked flags from
rendering selected/bold or modification markers, while preserving existing
user-modification styling for unlocked flags.
🧹 Nitpick comments (1)
src/features/directory/flagDirectoryModulesUrl.ts (1)

7-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete coverage for the deployment configuration matrix.

  • src/features/directory/flagDirectoryModulesUrl.ts#L7-L13: test that enable: true pins the configured URL, while unset/false preserves normal defaults and overrides.
  • src/commons/sagas/LanguageDirectorySaga.ts#L66-L76: test that the default URL uses bundled languages without fetch, while a custom URL loads remote JSON.
  • src/features/conductor/flagConductorEnable.test.ts#L9-L30: add enable: false and unset cases, especially verifying locked false beats a user override.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/directory/flagDirectoryModulesUrl.ts` around lines 7 - 13,
Complete deployment-matrix test coverage across the affected sites: in
src/features/directory/flagDirectoryModulesUrl.ts lines 7-13, verify enabled
configuration pins the configured URL while unset or false preserves default
behavior and user overrides; in src/commons/sagas/LanguageDirectorySaga.ts lines
66-76, verify the default URL uses bundled languages without fetch and a custom
URL fetches remote JSON; in src/features/conductor/flagConductorEnable.test.ts
lines 9-30, add unset and false configuration cases, including that locked false
overrides user values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 63-64: Update the earlier conductor.enable toggle instructions in
README.md to clarify that users may toggle it back to true only when
REACT_APP_CONDUCTOR_ENABLE is not deployment-pinned; note that setting it to
FALSE makes the control read-only.
- Around line 52-61: Add a language identifier, preferably text, to the fenced
code block containing the directory URL configuration entries in README.md,
without changing its contents.

In `@src/commons/featureFlags/index.ts`:
- Around line 22-24: Update the reducer handling both setFlag and resetFlag so
locked feature flags return without modifying persisted user state. Preserve
existing behavior for unlocked flags, and add a regression test covering
resetFlag on a locked flag.

---

Outside diff comments:
In `@src/new_routes/features.tsx`:
- Around line 28-45: Update the isModified styling condition in both
feature-flag card render paths to require !flag.isLocked alongside modifiedFlag
!== undefined. Keep locked flags from rendering selected/bold or modification
markers, while preserving existing user-modification styling for unlocked flags.

---

Nitpick comments:
In `@src/features/directory/flagDirectoryModulesUrl.ts`:
- Around line 7-13: Complete deployment-matrix test coverage across the affected
sites: in src/features/directory/flagDirectoryModulesUrl.ts lines 7-13, verify
enabled configuration pins the configured URL while unset or false preserves
default behavior and user overrides; in
src/commons/sagas/LanguageDirectorySaga.ts lines 66-76, verify the default URL
uses bundled languages without fetch and a custom URL fetches remote JSON; in
src/features/conductor/flagConductorEnable.test.ts lines 9-30, add unset and
false configuration cases, including that locked false overrides user values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58ba4496-ed07-432b-8cec-d21485535a2e

📥 Commits

Reviewing files that changed from the base of the PR and between 9fd144b and 324e653.

📒 Files selected for processing (18)
  • .env.example
  • README.md
  • src/commons/featureFlags/FeatureFlag.ts
  • src/commons/featureFlags/featureSelector.test.ts
  • src/commons/featureFlags/featureSelector.ts
  • src/commons/featureFlags/index.test.ts
  • src/commons/featureFlags/index.ts
  • src/commons/featureFlags/selectFeatureSaga.test.ts
  • src/commons/featureFlags/useFeature.test.tsx
  • src/commons/featureFlags/useFeature.ts
  • src/commons/sagas/LanguageDirectorySaga.ts
  • src/commons/utils/Constants.ts
  • src/features/conductor/flagConductorEnable.test.ts
  • src/features/conductor/flagConductorEnable.ts
  • src/features/directory/flagDirectoryLanguageUrl.ts
  • src/features/directory/flagDirectoryModulesUrl.ts
  • src/features/directory/flagDirectoryPluginUrl.ts
  • src/new_routes/features.tsx

Comment thread README.md
Comment thread README.md
Comment on lines +63 to +64
A deployment can pin these instead of leaving them to each user's browser. Set `REACT_APP_CONDUCTOR_ENABLE` to `TRUE` or `FALSE` in `.env` to fix `conductor.enable` for everyone; while it is `TRUE`, the three `REACT_APP_*_DIRECTORY_URL` variables likewise pin the directory URLs. Pinned flags are shown read-only on the Feature Flags page, and take precedence over anything a user has previously set there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Qualify the earlier toggle instructions for pinned deployments.

When REACT_APP_CONDUCTOR_ENABLE=FALSE, conductor.enable is read-only, so the earlier instruction to toggle it back to true cannot be followed. State that the toggle applies only when the flag is not deployment-pinned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 63 - 64, Update the earlier conductor.enable toggle
instructions in README.md to clarify that users may toggle it back to true only
when REACT_APP_CONDUCTOR_ENABLE is not deployment-pinned; note that setting it
to FALSE makes the control read-only.

Comment on lines +22 to +24
if (action.payload.featureFlag.isLocked) {
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Guard resets for locked flags too.

setFlag is blocked, but resetFlag can still delete a persisted override for a locked flag. Guard both reducer actions so deployment-pinned flags cannot modify persisted user state, and add a regression test.

Proposed fix
     resetFlag<T>(state: FeatureFlagsState, action: { payload: { featureFlag: FeatureFlag<T> } }) {
+      if (action.payload.featureFlag.isLocked) {
+        return;
+      }
       delete state.modifiedFlags[action.payload.featureFlag.flagName];
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commons/featureFlags/index.ts` around lines 22 - 24, Update the reducer
handling both setFlag and resetFlag so locked feature flags return without
modifying persisted user state. Preserve existing behavior for unlocked flags,
and add a regression test covering resetFlag on a locked flag.

@RichDom2185
RichDom2185 disabled auto-merge July 30, 2026 15:28
@RichDom2185
RichDom2185 force-pushed the conductor-deployment-config branch from 4e37262 to 324e653 Compare July 30, 2026 15:32
@RichDom2185
RichDom2185 enabled auto-merge (squash) July 30, 2026 15:37
@RichDom2185
RichDom2185 disabled auto-merge July 30, 2026 15:37
sayomaki and others added 3 commits July 30, 2026 23:40
A deployment-pinned flag could still have its persisted override deleted
via resetFlag, even though setFlag was already blocked. Guard both
reducer actions so a locked flag never modifies persisted user state.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@RichDom2185
RichDom2185 merged commit 783ee4f into master Jul 30, 2026
10 checks passed
@RichDom2185
RichDom2185 deleted the conductor-deployment-config branch July 30, 2026 15:53
@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 30558636208

Coverage increased (+0.1%) to 43.98%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 16 of 16 lines across 9 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 14467
Covered Lines: 6813
Line Coverage: 47.09%
Relevant Branches: 7734
Covered Branches: 2951
Branch Coverage: 38.16%
Branches in Coverage %: Yes
Coverage Strength: 29.77 hits per line

💛 - Coveralls

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.

3 participants