fix(featureFlags): resolve linearToggleEnabled through resolveFlag - #15135
Conversation
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1812 passed, 0 failed · 7 flaky📊 Browser Reports
📦 Bundle: 8.85 MB gzip ⚪ 0 BDetailsSummary
Category Glance App Entry Points — 3.71 kB (baseline 3.71 kB) • ⚪ 0 BMain entry bundles and manifests Status: 1 unchanged Graph Workspace — 1.37 MB (baseline 1.37 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration Status: 3 unchanged Views & Navigation — 124 kB (baseline 124 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces Status: 17 unchanged Panels & Settings — 566 kB (baseline 566 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens Status: 26 unchanged User & Accounts — 27.7 kB (baseline 27.7 kB) • ⚪ 0 BAuthentication, profile, and account management bundles Status: 11 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors Status: 8 unchanged UI Components — 67.1 kB (baseline 67.1 kB) • ⚪ 0 BReusable component library chunks Status: 14 unchanged Data & Services — 3.52 MB (baseline 3.52 MB) • ⚪ 0 BStores, services, APIs, and repositories Status: 17 unchanged Utilities & Hooks — 550 kB (baseline 550 kB) • ⚪ 0 BHelpers, composables, and utility bundles Status: 38 unchanged Vendor & Third-Party — 16.8 MB (baseline 16.8 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 18 unchanged Other — 14.2 MB (baseline 14.2 MB) • ⚪ 0 BBundles that do not match a named category Status: 285 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-17T23:22:03.799Z",
"gitSha": "5e97777ebf66810a18ae0adaffed3335e03cfc45",
"branch": "matt/be-7192-linear-toggle-resolve-flag",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2087.9249999999843,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.084000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 543.553,
"heapDeltaBytes": -2791716,
"heapUsedBytes": 58399504,
"domNodes": -281,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 7.759,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-idle",
"durationMs": 2039.354000000003,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.206,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 488.42500000000007,
"heapDeltaBytes": -1652536,
"heapUsedBytes": 58891868,
"domNodes": -281,
"jsHeapTotalBytes": 4448256,
"scriptDurationMs": 7.2,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1917.250000000024,
"styleRecalcs": 76,
"styleRecalcDurationMs": 45.211,
"layouts": 12,
"layoutDurationMs": 6.135,
"taskDurationMs": 927.703,
"heapDeltaBytes": 1698068,
"heapUsedBytes": 62086796,
"domNodes": -282,
"jsHeapTotalBytes": 4710400,
"scriptDurationMs": 108.631,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1830.9689999999819,
"styleRecalcs": 74,
"styleRecalcDurationMs": 36.763,
"layouts": 12,
"layoutDurationMs": 3.686,
"taskDurationMs": 853.06,
"heapDeltaBytes": 595240,
"heapUsedBytes": 61576588,
"domNodes": -281,
"jsHeapTotalBytes": 5234688,
"scriptDurationMs": 105.52,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1731.1530000000062,
"styleRecalcs": 30,
"styleRecalcDurationMs": 17.997999999999998,
"layouts": 6,
"layoutDurationMs": 0.68,
"taskDurationMs": 355.7710000000001,
"heapDeltaBytes": 2807316,
"heapUsedBytes": 62817912,
"domNodes": 75,
"jsHeapTotalBytes": 5242880,
"scriptDurationMs": 9.898,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1736.799000000019,
"styleRecalcs": 32,
"styleRecalcDurationMs": 18.576,
"layouts": 6,
"layoutDurationMs": 0.672,
"taskDurationMs": 355.711,
"heapDeltaBytes": 3102064,
"heapUsedBytes": 63786020,
"domNodes": 79,
"jsHeapTotalBytes": 4456448,
"scriptDurationMs": 10.122,
"eventListeners": 21,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "dom-widget-clipping",
"durationMs": 601.6949999999497,
"styleRecalcs": 10,
"styleRecalcDurationMs": 6.655000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 374.936,
"heapDeltaBytes": 10698968,
"heapUsedBytes": 71054288,
"domNodes": 16,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 52.638,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 565.5029999999215,
"styleRecalcs": 11,
"styleRecalcDurationMs": 6.931,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 359.776,
"heapDeltaBytes": 10434080,
"heapUsedBytes": 70731344,
"domNodes": 18,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 52.56,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2071.8610000000126,
"styleRecalcs": 9,
"styleRecalcDurationMs": 7.761999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 635.652,
"heapDeltaBytes": 2303096,
"heapUsedBytes": 76376732,
"domNodes": -260,
"jsHeapTotalBytes": -1839104,
"scriptDurationMs": 15.89,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-idle",
"durationMs": 2048.930000000041,
"styleRecalcs": 7,
"styleRecalcDurationMs": 6.346000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 601.0490000000001,
"heapDeltaBytes": 2358264,
"heapUsedBytes": 76526376,
"domNodes": -267,
"jsHeapTotalBytes": -1576960,
"scriptDurationMs": 18.416999999999994,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 2153.2440000000292,
"styleRecalcs": 68,
"styleRecalcDurationMs": 14.206000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1181.7150000000001,
"heapDeltaBytes": 2435820,
"heapUsedBytes": 77525192,
"domNodes": -267,
"jsHeapTotalBytes": -1089536,
"scriptDurationMs": 329.418,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2097.3960000000034,
"styleRecalcs": 65,
"styleRecalcDurationMs": 11.569000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1104.4260000000002,
"heapDeltaBytes": 17098828,
"heapUsedBytes": 78437556,
"domNodes": 6,
"jsHeapTotalBytes": 225280,
"scriptDurationMs": 305.00500000000005,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-zoom",
"durationMs": 3182.372999999984,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.43,
"layouts": 60,
"layoutDurationMs": 8.806000000000001,
"taskDurationMs": 1430.9,
"heapDeltaBytes": -11376936,
"heapUsedBytes": 64906168,
"domNodes": -286,
"jsHeapTotalBytes": 6025216,
"scriptDurationMs": 391.571,
"eventListeners": -183,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3147.950000000037,
"styleRecalcs": 62,
"styleRecalcDurationMs": 13.262000000000002,
"layouts": 60,
"layoutDurationMs": 8.142999999999999,
"taskDurationMs": 1344.0639999999999,
"heapDeltaBytes": 14578016,
"heapUsedBytes": 76389400,
"domNodes": -276,
"jsHeapTotalBytes": 0,
"scriptDurationMs": 387.91700000000003,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2024.9169999999594,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.639000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 603.4300000000002,
"heapDeltaBytes": -13233628,
"heapUsedBytes": 62045420,
"domNodes": -281,
"jsHeapTotalBytes": 2879488,
"scriptDurationMs": 14.501000000000003,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2076.1099999999715,
"styleRecalcs": 7,
"styleRecalcDurationMs": 8.019000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 620.688,
"heapDeltaBytes": -6189720,
"heapUsedBytes": 74491308,
"domNodes": -272,
"jsHeapTotalBytes": 3997696,
"scriptDurationMs": 14.584000000000003,
"eventListeners": -147,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 583.8449999999966,
"styleRecalcs": 45,
"styleRecalcDurationMs": 9.693,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 390.022,
"heapDeltaBytes": 11095060,
"heapUsedBytes": 71680836,
"domNodes": 16,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 120.81299999999999,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 591.6889999999739,
"styleRecalcs": 46,
"styleRecalcDurationMs": 10.032,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 384.06600000000003,
"heapDeltaBytes": 11556856,
"heapUsedBytes": 72746884,
"domNodes": 18,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 117.658,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2008.831999999984,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.728,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 486.579,
"heapDeltaBytes": 4109648,
"heapUsedBytes": 64276228,
"domNodes": -281,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 6.714000000000001,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2046.4040000000523,
"styleRecalcs": 9,
"styleRecalcDurationMs": 13.094000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 487.46999999999997,
"heapDeltaBytes": 2087644,
"heapUsedBytes": 62356108,
"domNodes": -280,
"jsHeapTotalBytes": 4710400,
"scriptDurationMs": 6.795000000000003,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1760.340000000042,
"styleRecalcs": 76,
"styleRecalcDurationMs": 39.751000000000005,
"layouts": 16,
"layoutDurationMs": 4.751,
"taskDurationMs": 836.484,
"heapDeltaBytes": -1778528,
"heapUsedBytes": 58462232,
"domNodes": -280,
"jsHeapTotalBytes": 4972544,
"scriptDurationMs": 87.843,
"eventListeners": -151,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1719.6539999999914,
"styleRecalcs": 74,
"styleRecalcDurationMs": 37.69799999999999,
"layouts": 16,
"layoutDurationMs": 4.706,
"taskDurationMs": 800.137,
"heapDeltaBytes": 13230968,
"heapUsedBytes": 74096176,
"domNodes": -283,
"jsHeapTotalBytes": 5758976,
"scriptDurationMs": 86.78800000000001,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1383.8980000000447,
"styleRecalcs": 19,
"styleRecalcDurationMs": 30.418,
"layouts": 14,
"layoutDurationMs": 13.454,
"taskDurationMs": 904.5609999999997,
"heapDeltaBytes": -4247292,
"heapUsedBytes": 90448168,
"domNodes": 13673,
"jsHeapTotalBytes": 11272192,
"scriptDurationMs": 17.051,
"eventListeners": 2375,
"totalBlockingTimeMs": 124,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8234.563000000036,
"styleRecalcs": 250,
"styleRecalcDurationMs": 43.108999999999995,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4154.527,
"heapDeltaBytes": 7777136,
"heapUsedBytes": 81989176,
"domNodes": -260,
"jsHeapTotalBytes": -2138112,
"scriptDurationMs": 985.446,
"eventListeners": -135,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8191.927999999962,
"styleRecalcs": 250,
"styleRecalcDurationMs": 44.509,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4114.728,
"heapDeltaBytes": 7757628,
"heapUsedBytes": 81914864,
"domNodes": -264,
"jsHeapTotalBytes": -1351680,
"scriptDurationMs": 971.573,
"eventListeners": -131,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 18670.61799999999,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17563.728000000003,
"heapDeltaBytes": -42159380,
"heapUsedBytes": 163368496,
"domNodes": -8312,
"jsHeapTotalBytes": -9904128,
"scriptDurationMs": 134.58700000000002,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 18877.266000000076,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 18089.708000000002,
"heapDeltaBytes": -28280716,
"heapUsedBytes": 177182468,
"domNodes": -8312,
"jsHeapTotalBytes": -13836288,
"scriptDurationMs": 121.67599999999999,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.890000000000025,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 22326.571999999942,
"styleRecalcs": 178,
"styleRecalcDurationMs": 20.29500000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21722.051,
"heapDeltaBytes": -35024300,
"heapUsedBytes": 183884252,
"domNodes": -8312,
"jsHeapTotalBytes": -13115392,
"scriptDurationMs": 414.401,
"eventListeners": -16381,
"totalBlockingTimeMs": 107,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-pan",
"durationMs": 22226.504999999976,
"styleRecalcs": 176,
"styleRecalcDurationMs": 23.68999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21568.206,
"heapDeltaBytes": -15276948,
"heapUsedBytes": 190912028,
"domNodes": -8312,
"jsHeapTotalBytes": -14659584,
"scriptDurationMs": 532.961,
"eventListeners": -16379,
"totalBlockingTimeMs": 210,
"frameDurationMs": 17.780000000000047,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 471.339999999941,
"styleRecalcs": 18,
"styleRecalcDurationMs": 23.714,
"layouts": 3,
"layoutDurationMs": 1.5050000000000001,
"taskDurationMs": 120.21200000000002,
"heapDeltaBytes": 5276668,
"heapUsedBytes": 66015480,
"domNodes": 150,
"jsHeapTotalBytes": 0,
"scriptDurationMs": 11.380999999999998,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 450.8820000000924,
"styleRecalcs": 12,
"styleRecalcDurationMs": 17.308999999999997,
"layouts": 3,
"layoutDurationMs": 0.642,
"taskDurationMs": 100.87800000000001,
"heapDeltaBytes": 4927856,
"heapUsedBytes": 65856836,
"domNodes": 121,
"jsHeapTotalBytes": 262144,
"scriptDurationMs": 6.953000000000001,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
}
]
} |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: 0 reviews are currently available. Based on recent review activity, included reviews refill at 1 per hour. 📝 WalkthroughWalkthroughThe Linear nightly flag now uses ChangesLinear nightly toggle
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This localized change preserves nightly behavior by default while allowing explicit overrides to disable the linear toggle; no actionable merge-blocking risk remains after normal checks and review. Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 inconclusive)
✅ Passed checks (6 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🔍 Cursor Review — Consolidated panel
Triggered by @mattmillerai.
Found 4 finding(s).
| Severity | Count |
|---|---|
| 🟢 Low | 3 |
| ⚪ Nit | 1 |
Panel: 8/8 reviewers contributed findings.
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #15135 +/- ##
==========================================
+ Coverage 78.97% 80.87% +1.90%
==========================================
Files 2209 1882 -327
Lines 111780 109943 -1837
Branches 33649 34539 +890
==========================================
+ Hits 88275 88919 +644
+ Misses 23057 20625 -2432
+ Partials 448 399 -49
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 412 files with indirect coverage changes 🚀 New features to boost your workflow:
|
christian-byrne
left a comment
There was a problem hiding this comment.
Can you fix the merge conflicts?
…oggle-resolve-flag # Conflicts: # src/composables/useFeatureFlags.test.ts
98d77dc
|
Merged |
ELI-5
Nightly builds always turned the linear toggle on, no matter what. That "always on" check ran before the code that looks at
?ff=URL overrides,ff:localStorage overrides, remote config, and the server flag — so on nightly none of those could ever turn it off. Now nightly is the default value fed into the normal resolution chain, so it stays on unless something explicitly says otherwise.Summary
linearToggleEnabledshort-circuited withif (isNightly) return trueabove itsresolveFlag(...)call, so the session-override and dev-override layers (which live insideresolveFlag) were silently ignored on nightly builds. PassingisNightlyasresolveFlag's default instead keeps nightly on by default while letting every override layer work.Changes
linearToggleEnablednow resolves throughresolveFlag(LINEAR_TOGGLE_ENABLED, remoteConfig.value.linear_toggle_enabled, isNightly)with no short-circuit. Tests updated for the new nightly behavior plus three new cases (remote-configfalse, server-servedfalse, session overridefalseover an enabled remote config).isNightlyisfalse, which is byte-identical to the previousfalsedefault — production and stable behavior is unchanged.Review Focus
Two intentional behavior deltas, both nightly-only: (1)
?ff=linear_toggle_enabled:falseand theff:localStorage dev override now change the flag, so an employee can reproduce the non-nightly experience; (2) an explicitly-servedfalsefrom remote config or the server flag now wins over the built-in nightly on. When nothing is served,getServerFeature(LINEAR_TOGGLE_ENABLED, true)returns thetruedefault, so nightly stays on.The default is deliberately
isNightlyalone, notisNightly || import.meta.env.DEVas in the neighbouringnodeLibraryEssentialsEnabledgetter — this flag has never defaulted on in dev and that is preserved.Judgment calls: the first existing test asserted
expect(api.getServerFeature).not.toHaveBeenCalled(), which pinned the removed short-circuit; it is rewritten to assert the flag still resolvestrueand thatgetServerFeatureis called with(LINEAR_TOGGLE_ENABLED, true).isNightly = falsewas added to thesession override precedenceblock'safterEachso the new nightly case there cannot leak into the auth-gated tests that follow.Verification: all four new/changed tests were confirmed red against the pre-change getter and green after (41 passed in
useFeatureFlags.test.ts, 23 inuseWorkflowActionsMenu.test.ts— the only non-test consumer).pnpm typecheck, oxfmt and eslint ran clean via the pre-commit hook.