build-roof-imagery-manual-review-gate.py 1.6 KB

123456789101112
  1. import json
  2. from pathlib import Path
  3. stats=json.loads(Path('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/roof-imagery-quality/roof-imagery-statistics.json').read_text())
  4. thresholds={'manualReviewDarkFraction':0.30,'manualReviewSeamMeanRgbRms':10.0,'manualReviewSeamP95RgbRms':30.0}
  5. rows=[]
  6. for x in stats['roofCrops']:
  7. d=x['roofCrop']['darkPixelFractionLumaUnder55']; rows.append({'id':x['id'],'darkFraction':d,'darkRisk':d>=thresholds['manualReviewDarkFraction'],'sourceTileCount':x['sourceTileCount']})
  8. for x in stats['adjacentTileSeams']:
  9. x['manualReviewRisk']=x['meanRgbRmsDelta']>=thresholds['manualReviewSeamMeanRgbRms'] or x['p95RgbRmsDelta']>=thresholds['manualReviewSeamP95RgbRms']
  10. report={'generatedAt':'2026-10-15','decision':'manual-review-required','thresholds':thresholds,'roofCropRows':rows,'seamRows':stats['adjacentTileSeams'],'automaticIntegrationAllowed':False,'reason':['Statistics cover crop rectangles, not only roof UV pixels.','Darkness can be shadow, roof material, occlusion or non-roof pixels.','Tile edge deltas can cross different land cover.','Only maintainer cockpit review can accept visual naturalness.'],'candidateUnchanged':True,'runtimeConfigChanged':False}
  11. Path('.scratch/cockpit-shell-panel-layout/verify/artifacts/t35/roof-imagery-quality/manual-review-gate.json').write_text(json.dumps(report,indent=2))
  12. print(json.dumps({'passed':True,'decision':report['decision'],'roofCropsRequiringReview':sum(x['darkRisk'] for x in rows),'seamsRequiringReview':sum(x['manualReviewRisk'] for x in report['seamRows']),'automaticIntegrationAllowed':False}))