diff --git a/skill/scripts/live-browser.js b/skill/scripts/live-browser.js index 918dfe093..69d227b0a 100644 --- a/skill/scripts/live-browser.js +++ b/skill/scripts/live-browser.js @@ -4902,6 +4902,13 @@ saveSession(); } + function completeParameterGenerationIfReady() { + if (expectedVariants <= 0 || arrivedVariants < expectedVariants) return; + if (parameterGenerationState === 'pending' || parameterGenerationState === 'loading') { + completeParameterPublication(); + } + } + function toggleTunePopover() { if (pendingApplyInFlight) { showManualApplyBusyToast(); return; } if (tuneOpen) { closeTunePopover(); return; } @@ -5796,7 +5803,7 @@ setLiveState('CYCLING'); showOrUpdateCyclingBar(); saveSession(); - if (parameterGenerationState === 'loading') completeParameterPublication(); + completeParameterGenerationIfReady(); return; } @@ -5884,7 +5891,7 @@ refreshParamsPanel(); positionBar(); saveSession(); - if (parameterGenerationState === 'loading') completeParameterPublication(); + completeParameterGenerationIfReady(); console.log('[impeccable] Mounted ' + arrivedVariants + ' ' + manifest.framework + ' component variants.'); } catch (err) { console.error('[impeccable] Failed to mount component-preview variants:', err); @@ -6329,7 +6336,7 @@ refreshParamsPanel(); positionBar(); saveSession(); - if (parameterGenerationState === 'loading') completeParameterPublication(); + completeParameterGenerationIfReady(); console.log('[impeccable] Injected ' + arrivedVariants + ' variants from source file.'); }) .catch(err => { @@ -6836,6 +6843,7 @@ const expected = parseInt(wrapper.dataset.impeccableVariantCount || '0'); if (expected > 0) expectedVariants = expected; + completeParameterGenerationIfReady(); if (arrivedVariants > 0) { setLiveState('CYCLING'); diff --git a/tests/live-browser-regression.test.mjs b/tests/live-browser-regression.test.mjs index bcd26bd71..6be47eea7 100644 --- a/tests/live-browser-regression.test.mjs +++ b/tests/live-browser-regression.test.mjs @@ -1032,6 +1032,15 @@ describe('live-browser.js regression guards', () => { /case 'variant_progress':[\s\S]{0,120}?if \(msg\.publicationKind === 'params'\) parameterGenerationState = 'loading';/, 'a params-only publication must mark Tune controls loading even though the variant count is unchanged', ); + assert.match( + SOURCE, + /function completeParameterGenerationIfReady\(\) \{[\s\S]{0,240}?arrivedVariants < expectedVariants[\s\S]{0,160}?parameterGenerationState === 'pending'[\s\S]{0,120}?completeParameterPublication\(\);/, + 'the completed variants publication must resolve pending Tune controls even when no params publication follows', + ); + assert.ok( + (SOURCE.match(/completeParameterGenerationIfReady\(\);/g) || []).length >= 4, + 'every DOM, source, and component-preview completion path must resolve pending Tune controls', + ); assert.match(SOURCE, /revisionDomain: 'browser'/, 'browser checkpoints must use their own revision domain'); });