'use strict'; const {app,assert,functionSource,loadAppLogic}=require('./helpers/app-source'); const AppLogic=loadAppLogic(); const placeSource=functionSource('placeChildAtFrontier'),expandSource=functionSource('expandMetaNow'),metaStateSource=functionSource('metaState'),ensureMetaStateSource=functionSource('ensureMetaState'),snapshotSource=functionSource('snapshotForStorage'); for(const forbidden of ['ensureBoards','renderAll','updateHud','nextPaint','save(','rebuildOccupancy'])assert(!placeSource.includes(forbidden),`Child placement still performs ${forbidden}`); assert((expandSource.match(/refreshWorldView\(/g)||[]).length===1,'Expansion does not use one presentation/persistence commit'); for(const forbidden of ['ensureBoards','renderAll','updateHud'])assert(!expandSource.includes(forbidden),`Expansion bypasses the shared view pipeline with ${forbidden}`); assert(!metaStateSource.includes('normalizeState')&&!metaStateSource.includes('markStateDirty')&&ensureMetaStateSource.includes('normalizeState(state)'),'State reads are not pure or explicit state repair is not delegated to normalizeState'); assert(!functionSource('puzzleOf').includes('markMetaDirty')&&functionSource('repairPuzzleDifficulty').includes('markMetaDirty'),'Puzzle reads still dirty metadata or difficulty repair lacks an explicit command boundary'); assert(snapshotSource.includes('metaRowsForStorage()')&&snapshotSource.includes('stateRowsForStorage()'),'Snapshot serialization bypasses shared row serializers'); assert(functionSource('pushCloudPending').includes('cloudRowsForStorage')&&functionSource('cloudRowsForStorage').includes('metaForStorage')&&functionSource('cloudRowsForStorage').includes('stateForStorage'),'Cloud serialization bypasses full-detail row serializers'); assert(functionSource('stateForStorage').includes('AppLogic.stateForStorage'),'State serialization is not delegated to the shared module'); assert(functionSource('collectConnectedLineComponent').includes('AppLogic.collectConnectedLineComponent'),'Connected-line traversal is not delegated to the shared module'); const data={ metas:{A:{id:'A',puzzle:{}},B:{id:'B',puzzle:{}}}, states:{A:{paths:[{startGate:0,endGate:1,cells:[[0,0],[0,1]]}]},B:{paths:[{startGate:0,endGate:1,cells:[[0,0],[1,0],[2,0]]}]}} }; let matchingCalls=0; const environment={ data, metaState:id=>data.states[id], matchingNeighborGate(meta,gate){ matchingCalls++; if(meta.id==='A'&&gate===1)return{meta:data.metas.B,gateIndex:0}; if(meta.id==='B'&&gate===0)return{meta:data.metas.A,gateIndex:1}; return null; } }; const componentCache=new Map(),lengthA=AppLogic.connectedLineLength(data.metas.A,0,componentCache,environment),callsAfterFirst=matchingCalls,lengthB=AppLogic.connectedLineLength(data.metas.B,0,componentCache,environment); assert(lengthA===5&&lengthB===5,'Connected-line component length is incorrect'); assert(matchingCalls===callsAfterFirst,'Connected-line component was traversed again for a cached member'); const widthCache=new Map(),widthA=AppLogic.renderedConnectedLineWidth(data.metas.A,0,widthCache,environment,componentCache),callsAfterWidth=matchingCalls,widthB=AppLogic.renderedConnectedLineWidth(data.metas.B,0,widthCache,environment,componentCache); assert(widthA===widthB&&matchingCalls===callsAfterWidth,'Connected-line width did not reuse the cached component'); const stateRow=AppLogic.stateForStorage({paths:[],specialProgress:{crossings:[]},solved:false,expanded:false,expansionRetryRound:7,solvedBy:null,scoreAwarded:0,scoreVersion:2,store:null,rev:5,transient:'remove'},{scoreVersion:2}); assert(stateRow.rev===5&&stateRow.expansionRetryRound===7&&!('transient' in stateRow),'State serializer lost expansion repair progress or leaked transient fields'); const emptyState=AppLogic.stateForStorage(null,{scoreVersion:3,normalizeState:()=>({paths:[],specialProgress:{crossings:[]},scoreVersion:3})}); assert(emptyState.scoreVersion===3&&Array.isArray(emptyState.paths),'State serializer fallback is invalid'); console.log('Stage 3/4 regression passed: batched expansion, shared traversal, normalization, serialization, and view pipeline');