import assert from 'node:assert/strict' import {readFileSync,writeFileSync} from 'node:fs' import {createHash} from 'node:crypto' const dir='.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/negative-estate-pilot/',pilot=JSON.parse(readFileSync(dir+'seated-whitelist-plan.json')),gate=JSON.parse(readFileSync(dir+'quality-gate.json')),recommend=JSON.parse(readFileSync(dir+'export-recommendation.json')),cfg=JSON.parse(readFileSync('public/cockpit/config.json')),lib=JSON.parse(readFileSync('tools/city-massing/house-library/library.json')),fit=JSON.parse(readFileSync('tools/city-massing/asset-fit.json')) assert.equal(pilot.buildings.length,4);assert.equal(new Set(pilot.buildings.map(b=>b.id)).size,4);assert.equal(pilot.modelChanged,false);assert.equal(gate.pilotNotGenerated,true);assert.equal(recommend.doNotRun,true) assert.equal(cfg.map.tilesets[0].regionManifest,'/gis/cad-bim/city-regions-v7/manifest.json');assert.equal(pilot.parentPlanSha256,createHash('sha256').update(readFileSync('tools/city-massing/city/cad-bim/seated-plan.json')).digest('hex')) const archetypes=new Map(lib.archetypes.map(a=>[a.id,a])),rows=[] for(const b of pilot.buildings){assert.ok(b.sampleIndices.length>=4&&Number.isFinite(b.heightM)&&b.terrainRelief<=3.2);const row=gate.rows.find(x=>x.id===b.id);assert.ok(row);if(b.archetype){const a=archetypes.get(b.archetype);assert.ok(a);const limits=fit.variants[b.archetype];const sx=b.width/a.nominal_footprint_m[0],sy=b.depth/a.nominal_footprint_m[1];assert.ok(sx>=limits.minScale[0]&&sx<=limits.maxScale[0]&&sy>=limits.minScale[1]&&sy<=limits.maxScale[1]);assert.equal(row.qualityPath,'approved-asset');assert.ok(a.source_objects.includes(`SRC_${b.archetype}__Windows`)||a.source_objects.includes('SRC_slab__Windows'));rows.push({id:b.id,path:'asset',archetype:b.archetype,fitScale:[sx,sy],triangles:a.validation.triangles,closedShells:a.validation.closed_shells})}else{assert.equal(row.qualityPath,'surveyed-outline-massing');assert.equal(row.acceptance.forbidRectangleSubstitution,true);rows.push({id:b.id,path:'massing',exactOutline:true,forbidRectangleSubstitution:true})}} const out={passed:true,rows,sourcePlanSha256:pilot.parentPlanSha256,globalRegionManifest:cfg.map.tilesets[0].regionManifest,caps:{pilot:pilot.caps,quality:gate.caps},blenderArgs:recommend.blenderArgs,doNotRun:true,configurationChanged:false,unverified:['GLB geometry/LOD actual output','single-building runtime visibility','browser/FPS/visual acceptance']} writeFileSync(dir+'round28-static-quality-gate.json',JSON.stringify(out,null,2));console.log(JSON.stringify(out))