From eebbf9789492aefe45a681d43b20bfaa3fcbb887 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Sat, 23 May 2026 21:59:17 -0400 Subject: [PATCH 1/2] fix: guard fast mode service tiers --- .../use-is-fast-mode-enabled-CwUgvZ2O.js | 4 +-- desktop/recovered/refresh-manifest.json | 11 ++++++ desktop/scripts/assemble-codex-runtime.mjs | 32 +++++++++++++++++ .../linux/codex-runtime-assembly.test.js | 34 +++++++++++++++++++ .../tests/linux/recovered-bundle.red.test.ts | 33 ++++++++++++++++++ 5 files changed, 112 insertions(+), 2 deletions(-) diff --git a/desktop/recovered/app-asar-extracted/webview/assets/use-is-fast-mode-enabled-CwUgvZ2O.js b/desktop/recovered/app-asar-extracted/webview/assets/use-is-fast-mode-enabled-CwUgvZ2O.js index d5c0b333..0c1f3a72 100644 --- a/desktop/recovered/app-asar-extracted/webview/assets/use-is-fast-mode-enabled-CwUgvZ2O.js +++ b/desktop/recovered/app-asar-extracted/webview/assets/use-is-fast-mode-enabled-CwUgvZ2O.js @@ -1,2 +1,2 @@ -import{ti as e,v as t}from"./app-server-manager-signals-Csopz8aM.js";import{J as n,X as r,xt as i}from"./setting-storage-EK1Te68s.js";import{c as a}from"./config-queries-B7E_1qEk.js";import{n as o}from"./use-auth-BI4R_D9h.js";import{n as s}from"./use-model-settings-DMElur6E.js";import{n as c,t as l}from"./model-queries-DhDk12Mf.js";var u=`fast`;function d(e){return e?.find(e=>p(e)&&!e.hidden)??e?.find(e=>p(e))??null}function f(e,t){let n=s(t,e);return n!=null&&p(n)}function p(t){return e(t)!=null}function m(e){return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0}var h=i();function g(e){let i=r(t),s=e?.hostId??i,c=o(s),{data:l}=n(a,s),u=l?.requirements?.featureRequirements?.fast_mode===!1;return!(c?.authMethod!==`chatgpt`||u)}function _(e){return v(e).canUseFastMode}function v(e){let i=(0,h.c)(13),s=r(t),u=e?.hostId??s,d=o(u),{data:f,isPending:p}=n(a,u),g=f?.requirements?.featureRequirements?.fast_mode===!1,_;i[0]===u?_=i[1]:(_={hostId:u},i[0]=u,i[1]=_);let{data:v,status:y}=c(_);if(d?.authMethod!==`chatgpt`||g){let e;return i[2]===g?e=i[3]:(e={canUseFastMode:!1,isDisabledByRequirement:g,isLoading:!1},i[2]=g,i[3]=e),e}let b;i[4]===v?.models?b=i[5]:(b=v?.models.some(m)??!1,i[4]=v?.models,i[5]=b);let x;i[6]!==p||i[7]!==y?(x=p||!l(y),i[6]=p,i[7]=y,i[8]=x):x=i[8];let S;return i[9]!==g||i[10]!==b||i[11]!==x?(S={canUseFastMode:b,isDisabledByRequirement:g,isLoading:x},i[9]=g,i[10]=b,i[11]=x,i[12]=S):S=i[12],S}export{f as a,d as i,v as n,p as o,g as r,_ as t}; -//# sourceMappingURL=use-is-fast-mode-enabled-CwUgvZ2O.js.map \ No newline at end of file +import{ti as e,v as t}from"./app-server-manager-signals-Csopz8aM.js";import{J as n,X as r,xt as i}from"./setting-storage-EK1Te68s.js";import{c as a}from"./config-queries-B7E_1qEk.js";import{n as o}from"./use-auth-BI4R_D9h.js";import{n as s}from"./use-model-settings-DMElur6E.js";import{n as c,t as l}from"./model-queries-DhDk12Mf.js";var u=`fast`;function d(e){return e?.find(e=>p(e)&&!e.hidden)??e?.find(e=>p(e))??null}function f(e,t){let n=s(t,e);return n!=null&&p(n)}function p(t){return e(t)!=null}function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}var h=i();function g(e){let i=r(t),s=e?.hostId??i,c=o(s),{data:l}=n(a,s),u=l?.requirements?.featureRequirements?.fast_mode===!1;return!(c?.authMethod!==`chatgpt`||u)}function _(e){return v(e).canUseFastMode}function v(e){let i=(0,h.c)(13),s=r(t),u=e?.hostId??s,d=o(u),{data:f,isPending:p}=n(a,u),g=f?.requirements?.featureRequirements?.fast_mode===!1,_;i[0]===u?_=i[1]:(_={hostId:u},i[0]=u,i[1]=_);let{data:v,status:y}=c(_);if(d?.authMethod!==`chatgpt`||g){let e;return i[2]===g?e=i[3]:(e={canUseFastMode:!1,isDisabledByRequirement:g,isLoading:!1},i[2]=g,i[3]=e),e}let b;i[4]===v?.models?b=i[5]:(b=v?.models.some(m)??!1,i[4]=v?.models,i[5]=b);let x;i[6]!==p||i[7]!==y?(x=p||!l(y),i[6]=p,i[7]=y,i[8]=x):x=i[8];let S;return i[9]!==g||i[10]!==b||i[11]!==x?(S={canUseFastMode:b,isDisabledByRequirement:g,isLoading:x},i[9]=g,i[10]=b,i[11]=x,i[12]=S):S=i[12],S}export{f as a,d as i,v as n,p as o,g as r,_ as t}; +//# sourceMappingURL=use-is-fast-mode-enabled-CwUgvZ2O.js.map diff --git a/desktop/recovered/refresh-manifest.json b/desktop/recovered/refresh-manifest.json index 46f778d1..687a905d 100644 --- a/desktop/recovered/refresh-manifest.json +++ b/desktop/recovered/refresh-manifest.json @@ -335,6 +335,17 @@ "modelSettings": { "patched": false, "results": [] + }, + "fastMode": { + "patched": true, + "results": [ + { + "label": "fast mode missing service tiers guard", + "patched": true, + "skipped": false, + "reason": null + } + ] } }, "nativeModuleSummary": { diff --git a/desktop/scripts/assemble-codex-runtime.mjs b/desktop/scripts/assemble-codex-runtime.mjs index 1e2eddf0..d2c46e2f 100644 --- a/desktop/scripts/assemble-codex-runtime.mjs +++ b/desktop/scripts/assemble-codex-runtime.mjs @@ -1024,6 +1024,11 @@ const rendererDesktopGoalsFeaturePatchAlternatives = [ 'computerUse:c.available,computerUseNodeRepl:c.available&&l,control:u,goals:!0,multiWindow:d})', }, ]; +const fastModeModelServiceTiersPatchTarget = + 'return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0'; +const fastModeModelServiceTiersPatchReplacement = + 'return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0'; +const fastModeModelServiceTiersPatchMarker = 'serviceTiers?.length??0'; const composerGoalsSlashCommandPatchMarker = 'id:`goals`,title:`Goals`'; const composerGoalsSlashCommandPatchAlternatives = [ { @@ -2052,6 +2057,32 @@ function patchCodexModelSettingsBundle(extractedAppRoot) { ); } +function patchCodexFastModeBundle(extractedAppRoot) { + const fastModePath = findOptionalExtractedWebviewAsset( + extractedAppRoot, + 'use-is-fast-mode-enabled-', + ); + + if (fastModePath == null) { + return summarizePatchResults([]); + } + + return summarizePatchResults( + applyPatchesToFile(fastModePath, [ + { + label: 'fast mode missing service tiers guard', + alternatives: [ + { + target: fastModeModelServiceTiersPatchTarget, + replacement: fastModeModelServiceTiersPatchReplacement, + }, + ], + marker: fastModeModelServiceTiersPatchMarker, + }, + ]), + ); +} + function patchCodexAppServerHooks(extractedAppRoot) { const appServerHooksPath = findExtractedWebviewAsset(extractedAppRoot, 'app-server-manager-hooks-'); return summarizePatchResults( @@ -2121,6 +2152,7 @@ export function patchExtractedCodexApp(extractedAppRoot) { avatarOverlayRenderer: patchCodexAvatarOverlayRenderer(extractedAppRoot), authWebview: patchCodexAuthWebviewBundles(extractedAppRoot), modelSettings: patchCodexModelSettingsBundle(extractedAppRoot), + fastMode: patchCodexFastModeBundle(extractedAppRoot), }; } diff --git a/desktop/tests/linux/codex-runtime-assembly.test.js b/desktop/tests/linux/codex-runtime-assembly.test.js index ac65a4a1..29bcb37a 100644 --- a/desktop/tests/linux/codex-runtime-assembly.test.js +++ b/desktop/tests/linux/codex-runtime-assembly.test.js @@ -117,6 +117,40 @@ describe('codex runtime assembly guards', () => { ]); }); + test('allows the fast mode service-tier guard to be applied idempotently', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-')); + const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js'); + + fs.writeFileSync( + filePath, + 'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}\n', + 'utf8', + ); + + const result = runAssemblySnippet( + ` + const patchResult = runtime.applyPatchesToFile(${JSON.stringify(filePath)}, [{ + label: 'fast mode missing service tiers guard', + target: 'return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0', + replacement: 'return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0', + marker: 'serviceTiers?.length??0', + }]); + process.stdout.write(JSON.stringify(patchResult)); + `, + tempRoot, + ); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual([ + { + label: 'fast mode missing service tiers guard', + patched: false, + skipped: true, + reason: 'fast mode missing service tiers guard replacement already present', + }, + ]); + }); + test('hydrates lfs pointer files before copying required runtime helpers', () => { const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-lfs-')); const filePath = path.join(tempRoot, 'codex'); diff --git a/desktop/tests/linux/recovered-bundle.red.test.ts b/desktop/tests/linux/recovered-bundle.red.test.ts index bb264d23..0f1e63e7 100644 --- a/desktop/tests/linux/recovered-bundle.red.test.ts +++ b/desktop/tests/linux/recovered-bundle.red.test.ts @@ -140,6 +140,7 @@ describe('Recovered Codex bundle RED contract', () => { const loginRouteBundle = readOutputAsset('login-route-'); const composerBundle = readOutputAsset('composer-'); const appShellBundle = readOutputAsset('app-shell-'); + const fastModeBundle = readOutputAsset('use-is-fast-mode-enabled-'); const pluginsPageBundle = fs.readFileSync( path.join( outputAssetsRoot, @@ -195,7 +196,13 @@ describe('Recovered Codex bundle RED contract', () => { ); expect(loginRouteBundle).toContain('useExternalBrowser:!0'); expect(composerBundle).toContain('threadGoalObjective'); + expect(fastModeBundle).toContain('serviceTiers?.length??0'); expect(summary.patchSummary.modelSettings.results).toEqual([]); + expect(summary.patchSummary.fastMode.results).toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'fast mode missing service tiers guard' }), + ]), + ); expect(pluginsPageBundle).toContain('plugins'); if (pluginInstallFlowBundle != null) { expect(pluginInstallFlowBundle).toContain('open-in-browser'); @@ -344,6 +351,7 @@ describe('Recovered Codex bundle RED contract', () => { pluginsPage?: { results: Array<{ label: string }> }; pluginsCards?: { results: Array<{ label: string }> }; }; + fastMode?: { results: Array<{ label: string }> }; }; }; @@ -379,6 +387,11 @@ describe('Recovered Codex bundle RED contract', () => { expect.objectContaining({ label: 'plugin install browser fallback opens install url' }), ]), ); + expect(manifest.patchSummary?.fastMode?.results).toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'fast mode missing service tiers guard' }), + ]), + ); }); test('webview index resolves the active renderer entry instead of pinning a full-app bundle name', () => { @@ -416,6 +429,26 @@ describe('Recovered Codex bundle RED contract', () => { expect(readRecoveredAsset('use-collaboration-mode-')).toContain('reasoning_effort'); }); + test('fast mode eligibility tolerates older model schemas without service tiers', () => { + const fastModeBundle = readRecoveredAsset('use-is-fast-mode-enabled-'); + const assembleScript = readDesktopFile('scripts/assemble-codex-runtime.mjs'); + const manifest = JSON.parse(readDesktopFile('recovered/refresh-manifest.json')) as { + patchSummary?: { + fastMode?: { results: Array<{ label: string }> }; + }; + }; + + expect(fastModeBundle).toContain('serviceTiers?.length??0'); + expect(fastModeBundle).not.toContain('serviceTiers.length>0'); + expect(assembleScript).toContain('fast mode missing service tiers guard'); + expect(assembleScript).toContain('serviceTiers?.length??0'); + expect(manifest.patchSummary?.fastMode?.results).toEqual( + expect.arrayContaining([ + expect.objectContaining({ label: 'fast mode missing service tiers guard' }), + ]), + ); + }); + test('plugin page menu patch is skipped when the upstream shell no longer needs it', () => { const appShell = readRecoveredAsset('app-shell-'); const manifest = JSON.parse(readDesktopFile('recovered/refresh-manifest.json')) as { From 4aa356a28208bb723af0c91a8025a07487f07a34 Mon Sep 17 00:00:00 2001 From: boggedbrush <90526147+boggedbrush@users.noreply.github.com> Date: Sat, 23 May 2026 22:15:18 -0400 Subject: [PATCH 2/2] test: harden fast mode serviceTiers patch --- desktop/scripts/assemble-codex-runtime.mjs | 56 ++++-- .../linux/codex-runtime-assembly.test.js | 163 +++++++++++++++++- .../tests/linux/recovered-bundle.red.test.ts | 6 + 3 files changed, 202 insertions(+), 23 deletions(-) diff --git a/desktop/scripts/assemble-codex-runtime.mjs b/desktop/scripts/assemble-codex-runtime.mjs index d2c46e2f..1d161c94 100644 --- a/desktop/scripts/assemble-codex-runtime.mjs +++ b/desktop/scripts/assemble-codex-runtime.mjs @@ -1024,11 +1024,10 @@ const rendererDesktopGoalsFeaturePatchAlternatives = [ 'computerUse:c.available,computerUseNodeRepl:c.available&&l,control:u,goals:!0,multiWindow:d})', }, ]; -const fastModeModelServiceTiersPatchTarget = +export const fastModeModelServiceTiersPatchTarget = 'return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0'; -const fastModeModelServiceTiersPatchReplacement = +export const fastModeModelServiceTiersPatchReplacement = 'return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0'; -const fastModeModelServiceTiersPatchMarker = 'serviceTiers?.length??0'; const composerGoalsSlashCommandPatchMarker = 'id:`goals`,title:`Goals`'; const composerGoalsSlashCommandPatchAlternatives = [ { @@ -2057,6 +2056,42 @@ function patchCodexModelSettingsBundle(extractedAppRoot) { ); } +export function patchFastModeServiceTiersGuard(filePath) { + assertExists(filePath, 'Patched extracted asset'); + + const source = fs.readFileSync(filePath, 'utf8'); + if (source.includes(fastModeModelServiceTiersPatchTarget)) { + fs.writeFileSync( + filePath, + source + .split(fastModeModelServiceTiersPatchTarget) + .join(fastModeModelServiceTiersPatchReplacement), + 'utf8', + ); + return [ + { + label: 'fast mode missing service tiers guard', + patched: true, + skipped: false, + reason: null, + }, + ]; + } + + if (source.includes(fastModeModelServiceTiersPatchReplacement)) { + return [ + { + label: 'fast mode missing service tiers guard', + patched: false, + skipped: true, + reason: 'fast mode missing service tiers guard replacement already present', + }, + ]; + } + + throw buildMissingPatchTargetError('fast mode missing service tiers guard', filePath); +} + function patchCodexFastModeBundle(extractedAppRoot) { const fastModePath = findOptionalExtractedWebviewAsset( extractedAppRoot, @@ -2067,20 +2102,7 @@ function patchCodexFastModeBundle(extractedAppRoot) { return summarizePatchResults([]); } - return summarizePatchResults( - applyPatchesToFile(fastModePath, [ - { - label: 'fast mode missing service tiers guard', - alternatives: [ - { - target: fastModeModelServiceTiersPatchTarget, - replacement: fastModeModelServiceTiersPatchReplacement, - }, - ], - marker: fastModeModelServiceTiersPatchMarker, - }, - ]), - ); + return summarizePatchResults(patchFastModeServiceTiersGuard(fastModePath)); } function patchCodexAppServerHooks(extractedAppRoot) { diff --git a/desktop/tests/linux/codex-runtime-assembly.test.js b/desktop/tests/linux/codex-runtime-assembly.test.js index 29bcb37a..16bdddcc 100644 --- a/desktop/tests/linux/codex-runtime-assembly.test.js +++ b/desktop/tests/linux/codex-runtime-assembly.test.js @@ -129,12 +129,7 @@ describe('codex runtime assembly guards', () => { const result = runAssemblySnippet( ` - const patchResult = runtime.applyPatchesToFile(${JSON.stringify(filePath)}, [{ - label: 'fast mode missing service tiers guard', - target: 'return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0', - replacement: 'return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0', - marker: 'serviceTiers?.length??0', - }]); + const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)}); process.stdout.write(JSON.stringify(patchResult)); `, tempRoot, @@ -151,6 +146,162 @@ describe('codex runtime assembly guards', () => { ]); }); + test('replaces the unsafe fast mode service-tier access', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-')); + const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js'); + + fs.writeFileSync( + filePath, + 'function m(e){return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0}\n', + 'utf8', + ); + + const result = runAssemblySnippet( + ` + import fs from 'node:fs'; + const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)}); + process.stdout.write(JSON.stringify({ + patchResult, + source: fs.readFileSync(${JSON.stringify(filePath)}, 'utf8'), + })); + `, + tempRoot, + ); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual({ + patchResult: [ + { + label: 'fast mode missing service tiers guard', + patched: true, + skipped: false, + reason: null, + }, + ], + source: + 'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}\n', + }); + }); + + test('fails loudly when the fast mode service-tier patch shape no longer matches', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-')); + const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js'); + + fs.writeFileSync( + filePath, + 'function m(e){return e.additionalSpeedTiers?.includes(u)===!0}\n', + 'utf8', + ); + + const result = runAssemblySnippet( + ` + try { + runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)}); + process.stdout.write('NO_ERROR'); + } catch (error) { + process.stderr.write(String(error?.message ?? error)); + process.exit(1); + } + `, + tempRoot, + ); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('fast mode missing service tiers guard patch target not found'); + }); + + test('prioritizes replacing unsafe fast mode access when guarded code is also present', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-')); + const filePath = path.join(tempRoot, 'use-is-fast-mode-enabled.js'); + + fs.writeFileSync( + filePath, + [ + 'function m(e){return e.serviceTiers.length>0||e.additionalSpeedTiers?.includes(u)===!0}', + 'function n(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}', + '', + ].join('\n'), + 'utf8', + ); + + const result = runAssemblySnippet( + ` + import fs from 'node:fs'; + const patchResult = runtime.patchFastModeServiceTiersGuard(${JSON.stringify(filePath)}); + process.stdout.write(JSON.stringify({ + patchResult, + source: fs.readFileSync(${JSON.stringify(filePath)}, 'utf8'), + })); + `, + tempRoot, + ); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual({ + patchResult: [ + { + label: 'fast mode missing service tiers guard', + patched: true, + skipped: false, + reason: null, + }, + ], + source: [ + 'function m(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}', + 'function n(e){return(e.serviceTiers?.length??0)>0||e.additionalSpeedTiers?.includes(u)===!0}', + '', + ].join('\n'), + }); + }); + + test('fast mode service-tier guard preserves eligibility semantics', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-patch-')); + + const result = runAssemblySnippet( + ` + const isFastModeEligible = new Function( + 'model', + 'const u = "fast"; const e = model; ' + runtime.fastModeModelServiceTiersPatchReplacement, + ); + const cases = [ + ['serviceTiers omitted', {}, false], + ['serviceTiers null', { serviceTiers: null }, false], + ['serviceTiers empty', { serviceTiers: [] }, false], + ['serviceTiers populated', { serviceTiers: ['priority'] }, true], + [ + 'additionalSpeedTiers fast', + { serviceTiers: null, additionalSpeedTiers: ['fast'] }, + true, + ], + [ + 'additionalSpeedTiers without fast', + { serviceTiers: null, additionalSpeedTiers: ['standard'] }, + false, + ], + ]; + + process.stdout.write(JSON.stringify( + cases.map(([label, model, expected]) => ({ + label, + expected, + actual: isFastModeEligible(model), + })), + )); + `, + tempRoot, + ); + + expect(result.status).toBe(0); + expect(JSON.parse(result.stdout)).toEqual([ + { label: 'serviceTiers omitted', expected: false, actual: false }, + { label: 'serviceTiers null', expected: false, actual: false }, + { label: 'serviceTiers empty', expected: false, actual: false }, + { label: 'serviceTiers populated', expected: true, actual: true }, + { label: 'additionalSpeedTiers fast', expected: true, actual: true }, + { label: 'additionalSpeedTiers without fast', expected: false, actual: false }, + ]); + }); + test('hydrates lfs pointer files before copying required runtime helpers', () => { const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-runtime-lfs-')); const filePath = path.join(tempRoot, 'codex'); diff --git a/desktop/tests/linux/recovered-bundle.red.test.ts b/desktop/tests/linux/recovered-bundle.red.test.ts index 0f1e63e7..25438078 100644 --- a/desktop/tests/linux/recovered-bundle.red.test.ts +++ b/desktop/tests/linux/recovered-bundle.red.test.ts @@ -440,8 +440,14 @@ describe('Recovered Codex bundle RED contract', () => { expect(fastModeBundle).toContain('serviceTiers?.length??0'); expect(fastModeBundle).not.toContain('serviceTiers.length>0'); + expect(fastModeBundle).not.toMatch(/model\.serviceTiers\.(length|some|map|includes)/); + expect(fastModeBundle).not.toMatch(/serviceTiers\.(length|some|map|includes)/); expect(assembleScript).toContain('fast mode missing service tiers guard'); expect(assembleScript).toContain('serviceTiers?.length??0'); + expect(assembleScript).not.toContain('model.serviceTiers.length'); + expect(assembleScript).not.toContain('model.serviceTiers.some'); + expect(assembleScript).not.toContain('model.serviceTiers.map'); + expect(assembleScript).not.toContain('model.serviceTiers.includes'); expect(manifest.patchSummary?.fastMode?.results).toEqual( expect.arrayContaining([ expect.objectContaining({ label: 'fast mode missing service tiers guard' }),