@@ -114,6 +114,58 @@ const calendarHistoryState = {
114114 summaryMeta : null ,
115115} ;
116116
117+ const RANDOMIZE_SEED_STORAGE_KEY = 'cfg.calendar.randomizeSeed' ;
118+ let randomizeSeed = false ;
119+ let randomizeSeedToggle = null ;
120+ let seedIndicatorElement = null ;
121+ let calendarConfigController = null ;
122+
123+ function readRandomizeSeedPreference ( ) {
124+ try {
125+ return localStorage . getItem ( RANDOMIZE_SEED_STORAGE_KEY ) === '1' ;
126+ } catch ( error ) {
127+ return false ;
128+ }
129+ }
130+
131+ function persistRandomizeSeedPreference ( enabled ) {
132+ try {
133+ localStorage . setItem ( RANDOMIZE_SEED_STORAGE_KEY , enabled ? '1' : '0' ) ;
134+ } catch ( error ) {
135+ // ignore storage failures
136+ }
137+ }
138+
139+ function updateRandomizeSeedToggleUI ( ) {
140+ if ( randomizeSeedToggle ) {
141+ randomizeSeedToggle . checked = Boolean ( randomizeSeed ) ;
142+ }
143+ }
144+
145+ function updateSeedIndicator ( seedValue ) {
146+ if ( ! seedIndicatorElement ) {
147+ return ;
148+ }
149+ let value = seedValue ;
150+ if ( typeof value === 'undefined' ) {
151+ if ( calendarConfigState && calendarConfigState . common ) {
152+ value = calendarConfigState . common . seed ;
153+ } else if ( typeof getConfigSnapshot === 'function' ) {
154+ try {
155+ const snapshot = getConfigSnapshot ( ) ;
156+ value = snapshot ?. seed ;
157+ } catch ( error ) {
158+ value = undefined ;
159+ }
160+ }
161+ }
162+ if ( value === null || typeof value === 'undefined' || value === '' ) {
163+ seedIndicatorElement . textContent = '—' ;
164+ return ;
165+ }
166+ seedIndicatorElement . textContent = String ( value ) ;
167+ }
168+
117169function readVisualsLegacyFlag ( ) {
118170 try {
119171 return localStorage . getItem ( VISUALS_LEGACY_FLAG ) === '1' ;
@@ -939,6 +991,13 @@ function renderRunHistory() {
939991 ? ''
940992 : `${ eventCount } event${ eventCount === 1 ? '' : 's' } ` ;
941993 const metaParts = [ `${ timestamp } ` , `Week: ${ week } ` ] ;
994+ const seedDisplay =
995+ entry . seed !== undefined && entry . seed !== null && entry . seed !== ''
996+ ? String ( entry . seed )
997+ : '' ;
998+ if ( seedDisplay ) {
999+ metaParts . push ( `Seed: ${ seedDisplay } ` ) ;
1000+ }
9421001 if ( eventText ) {
9431002 metaParts . push ( eventText ) ;
9441003 }
@@ -1007,6 +1066,12 @@ function addRunHistoryEntry(entry) {
10071066 class : entry . class || 'calendar' ,
10081067 variant : entry . variant || '' ,
10091068 rig : entry . rig || '' ,
1069+ seed :
1070+ typeof entry . seed === 'number'
1071+ ? entry . seed
1072+ : typeof entry . seed === 'string' && entry . seed . trim ( ) . length > 0
1073+ ? entry . seed . trim ( )
1074+ : '' ,
10101075 week_start : typeof entry . week_start === 'string' ? entry . week_start : '' ,
10111076 label : entry . label || '' ,
10121077 payload : clonePayload ( entry . payload ) || entry . payload || { } ,
@@ -2230,6 +2295,15 @@ function setGenerateButtonState(loading) {
22302295 updateGenerateButtonDisabledForRuntime ( ) ;
22312296}
22322297
2298+ function handleRandomizeSeedToggleChange ( ) {
2299+ if ( ! randomizeSeedToggle ) {
2300+ return ;
2301+ }
2302+ randomizeSeed = randomizeSeedToggle . checked ;
2303+ persistRandomizeSeedPreference ( randomizeSeed ) ;
2304+ updateRandomizeSeedToggleUI ( ) ;
2305+ }
2306+
22332307async function handleGenerate ( event ) {
22342308 if ( event && typeof event . preventDefault === 'function' ) {
22352309 event . preventDefault ( ) ;
@@ -2238,18 +2312,39 @@ async function handleGenerate(event) {
22382312 return ;
22392313 }
22402314
2315+ let randomizedSeedText = '' ;
2316+ if ( randomizeSeed ) {
2317+ randomizedSeedText = String ( Math . floor ( Math . random ( ) * 1_000_000_000 ) ) ;
2318+ let appliedSeed = null ;
2319+ if ( calendarConfigController && typeof calendarConfigController . setSeed === 'function' ) {
2320+ appliedSeed = calendarConfigController . setSeed ( randomizedSeedText , {
2321+ markUserEdited : true ,
2322+ persist : true ,
2323+ } ) ;
2324+ if ( typeof appliedSeed === 'string' && appliedSeed . trim ( ) . length > 0 ) {
2325+ randomizedSeedText = appliedSeed . trim ( ) ;
2326+ }
2327+ }
2328+ if ( ! appliedSeed && calendarConfigState && calendarConfigState . common ) {
2329+ calendarConfigState . common . seed = randomizedSeedText ;
2330+ updateSeedIndicator ( randomizedSeedText ) ;
2331+ }
2332+ }
2333+
22412334 const snapshot = typeof getConfigSnapshot === 'function' ? getConfigSnapshot ( ) : { } ;
22422335 const variantId = snapshot . variant || 'mk1' ;
22432336 const rigId = snapshot . rig || 'default' ;
22442337 const config = calendarConfigState || { } ;
22452338 const archetype = config ?. common ?. archetype || '' ;
22462339 const weekStartValue = snapshot . week_start || '' ;
2247- const seedValue = snapshot . seed || '' ;
2340+ const seedValue = snapshot . seed || randomizedSeedText ;
22482341 const budgetText =
22492342 variantId === 'mk2' && rigId === 'workforce'
22502343 ? config ?. mk2 ?. workforce ?. budgetText || ''
22512344 : '' ;
22522345
2346+ updateSeedIndicator ( seedValue ) ;
2347+
22532348 setGenerateButtonState ( true ) ;
22542349 updateVisuals ( null ) ;
22552350 showVisualsOverlay ( 'Generating schedule…' , { loading : true } ) ;
@@ -2352,6 +2447,7 @@ async function handleGenerate(event) {
23522447 ? result . week_start
23532448 : weekStartValue ,
23542449 label : 'Generated schedule' ,
2450+ seed : normalizedSeed ,
23552451 payload : result ,
23562452 inputs : inputsSnapshot ,
23572453 resultSummary : { events : eventsCount } ,
@@ -3170,6 +3266,22 @@ function hydrateGlobalActions() {
31703266 if ( ! ( button instanceof HTMLElement ) ) {
31713267 return ;
31723268 }
3269+ seedIndicatorElement = actionsRoot . querySelector ( '[data-current-seed]' ) || seedIndicatorElement ;
3270+ if ( ! actionsRoot . dataset . randomizeSeedHydrated ) {
3271+ randomizeSeed = readRandomizeSeedPreference ( ) ;
3272+ actionsRoot . dataset . randomizeSeedHydrated = '1' ;
3273+ }
3274+ const toggle = actionsRoot . querySelector ( '#randomize-seed-toggle' ) ;
3275+ if ( toggle !== randomizeSeedToggle ) {
3276+ if ( randomizeSeedToggle ) {
3277+ randomizeSeedToggle . removeEventListener ( 'change' , handleRandomizeSeedToggleChange ) ;
3278+ }
3279+ randomizeSeedToggle = toggle instanceof HTMLInputElement ? toggle : null ;
3280+ if ( randomizeSeedToggle ) {
3281+ randomizeSeedToggle . addEventListener ( 'change' , handleRandomizeSeedToggleChange ) ;
3282+ }
3283+ }
3284+ updateRandomizeSeedToggleUI ( ) ;
31733285 if ( generateButton && generateButton !== button ) {
31743286 generateButton . removeEventListener ( 'click' , handleGenerate ) ;
31753287 }
@@ -3180,6 +3292,7 @@ function hydrateGlobalActions() {
31803292 button . addEventListener ( 'click' , handleGenerate ) ;
31813293 button . dataset . generateBound = '1' ;
31823294 }
3295+ updateSeedIndicator ( ) ;
31833296}
31843297
31853298function hydrateConfigPanel ( ) {
@@ -3365,6 +3478,10 @@ function hydrateConfigPanel() {
33653478 } ,
33663479 } ;
33673480 calendarConfigState = calendarConfig ;
3481+ calendarConfigController = {
3482+ setSeed : ( value , options ) => setCalendarSeed ( value , options ) ,
3483+ getSeed : ( ) => ( calendarConfig . common . seed ? String ( calendarConfig . common . seed ) : '' ) ,
3484+ } ;
33683485
33693486 let commonSeedUserEdited = false ;
33703487 let shouldPersistInitialCommon = false ;
@@ -3521,6 +3638,7 @@ function hydrateConfigPanel() {
35213638 cfg . weekStart = calendarConfig . common . weekStart || '' ;
35223639 cfg . seed = calendarConfig . common . seed ? String ( calendarConfig . common . seed ) : '' ;
35233640 renderSummaryChips ( ) ;
3641+ updateSeedIndicator ( calendarConfig . common . seed ) ;
35243642 } ;
35253643
35263644 const computeDeterministicSeed = ( ) => {
@@ -3545,6 +3663,7 @@ function hydrateConfigPanel() {
35453663 if ( seedInput ) {
35463664 seedInput . value = calendarConfig . common . seed || computeDeterministicSeed ( ) ;
35473665 }
3666+ updateSeedIndicator ( calendarConfig . common . seed ) ;
35483667 } ;
35493668
35503669 const persistCalendarCommon = ( ) => {
@@ -3558,6 +3677,21 @@ function hydrateConfigPanel() {
35583677 persistJsonStorage ( CALENDAR_COMMON_STORAGE_KEY , payload ) ;
35593678 } ;
35603679
3680+ function setCalendarSeed ( nextSeed , { markUserEdited = true , persist = true } = { } ) {
3681+ const parsedSeed = Number . parseInt ( String ( nextSeed ) , 10 ) ;
3682+ if ( ! Number . isFinite ( parsedSeed ) ) {
3683+ return '' ;
3684+ }
3685+ calendarConfig . common . seed = String ( parsedSeed ) ;
3686+ commonSeedUserEdited = Boolean ( markUserEdited ) ;
3687+ if ( persist ) {
3688+ persistCalendarCommon ( ) ;
3689+ }
3690+ syncCommonInputs ( ) ;
3691+ syncCommonStateToChips ( ) ;
3692+ return calendarConfig . common . seed ;
3693+ }
3694+
35613695 const persistCalendarMk2Calendar = ( ) => {
35623696 persistJsonStorage ( CALENDAR_MK2_CALENDAR_STORAGE_KEY , {
35633697 compress : Boolean ( calendarConfig . mk2 . calendar . compress ) ,
@@ -3651,38 +3785,32 @@ function hydrateConfigPanel() {
36513785 seedInput . addEventListener ( 'change' , ( ) => {
36523786 const value = seedInput . value . trim ( ) ;
36533787 if ( ! value ) {
3654- commonSeedUserEdited = false ;
3655- calendarConfig . common . seed = computeDeterministicSeed ( ) ;
3656- seedInput . value = calendarConfig . common . seed ;
3657- } else {
3658- const numericSeed = Number . parseInt ( value , 10 ) ;
3659- if ( ! Number . isFinite ( numericSeed ) ) {
3660- seedInput . value = calendarConfig . common . seed || computeDeterministicSeed ( ) ;
3661- return ;
3662- }
3663- calendarConfig . common . seed = String ( numericSeed ) ;
3664- commonSeedUserEdited = true ;
3788+ setCalendarSeed ( computeDeterministicSeed ( ) , { markUserEdited : false , persist : true } ) ;
3789+ updateDerivedFromFoundation ( ) ;
3790+ return ;
36653791 }
3666- persistCalendarCommon ( ) ;
3792+ const numericSeed = Number . parseInt ( value , 10 ) ;
3793+ if ( ! Number . isFinite ( numericSeed ) ) {
3794+ seedInput . value = calendarConfig . common . seed || computeDeterministicSeed ( ) ;
3795+ updateSeedIndicator ( calendarConfig . common . seed ) ;
3796+ return ;
3797+ }
3798+ setCalendarSeed ( numericSeed , { markUserEdited : true , persist : true } ) ;
36673799 updateDerivedFromFoundation ( ) ;
36683800 } ) ;
36693801 }
36703802
36713803 if ( seedResetButton ) {
36723804 seedResetButton . addEventListener ( 'click' , ( ) => {
3673- commonSeedUserEdited = false ;
3674- calendarConfig . common . seed = computeDeterministicSeed ( ) ;
3675- persistCalendarCommon ( ) ;
3805+ setCalendarSeed ( computeDeterministicSeed ( ) , { markUserEdited : false , persist : true } ) ;
36763806 updateDerivedFromFoundation ( ) ;
36773807 } ) ;
36783808 }
36793809
36803810 if ( seedRandomButton ) {
36813811 seedRandomButton . addEventListener ( 'click' , ( ) => {
36823812 const randomSeed = Math . floor ( Math . random ( ) * 1_000_000_000 ) ;
3683- calendarConfig . common . seed = String ( randomSeed ) ;
3684- commonSeedUserEdited = true ;
3685- persistCalendarCommon ( ) ;
3813+ setCalendarSeed ( randomSeed , { markUserEdited : true , persist : true } ) ;
36863814 updateDerivedFromFoundation ( ) ;
36873815 } ) ;
36883816 }
0 commit comments