abse/smartwatch-flex-top-only

Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.

Version
0.2.20
License
unset
Stars
0

scripts/audit-thermal-vias.mjs

import fs from 'node:fs'
import assert from 'node:assert/strict'
import {createHash} from 'node:crypto'
import {copperModel} from './copper-model.mjs'
import {isAuthorizedThermalVia,thermalViaContext,thermalViaSpecification} from './thermal-via-policy.mjs'
const [cacheFile,sourceFile,output='reports/electrical-fixes/thermal-vias.json']=process.argv.slice(2),cache=JSON.parse(fs.readFileSync(cacheFile)),source=JSON.parse(fs.readFileSync(sourceFile)),context=thermalViaContext(source),pad=copperModel(cache,source).find(p=>p.id===context.padId),vias=source.filter(e=>e.type==='pcb_via'&&/^esp32_thermal_escape_/.test(e.pcb_trace_id)),failures=[];
if(vias.length!==thermalViaSpecification.requiredCount)failures.push('Requires exactly nine native thermal vias');
for(const [i,q]of context.sites.entries()){
 const v=vias.find(v=>v.pcb_trace_id==='esp32_thermal_escape_'+i);if(!v||Math.hypot(v.x-q.x,v.y-q.y)>1e-7||!isAuthorizedThermalVia(v,pad,source,cache))failures.push('Invalid or missing thermal site '+i);
 const t=source.find(e=>e.type==='pcb_trace'&&e.pcb_trace_id===v?.pcb_trace_id);if(t?.connection_name!==context.net)failures.push('Thermal via is not on GND '+i);
}
if(source.find(e=>e.type==='pcb_board')?.is_via_in_pad_allowed!==true)failures.push('Native board does not allow declared filled/capped thermal vias');
// Negative checks ensure that the exception does not admit another land, offset,
// net, ordinary trace or drill diameter. Physical clearance remains independently checked.
if(vias[0]){
 const v=vias[0];assert(!isAuthorizedThermalVia({...v,x:v.x+.01},pad,source,cache));assert(!isAuthorizedThermalVia({...v,hole_diameter:.31},pad,source,cache));assert(!isAuthorizedThermalVia({...v,pcb_trace_id:'ordinary_via'},pad,source,cache));assert(!isAuthorizedThermalVia(v,{...pad,id:'different_land'},source,cache));assert(!isAuthorizedThermalVia({...v,net:'wrong_net'},pad,source,cache));
}
const sha=p=>createHash('sha256').update(fs.readFileSync(p)).digest('hex'),report={status:failures.length?'FAIL':'PASS',requiredThermalVias:9,nativeThermalVias:vias.length,specification:thermalViaSpecification,cacheFile,cacheSha256:sha(cacheFile),sourceFile,sourceSha256:sha(sourceFile),negativePolicyChecks:5,failures,qualification:'Layout and exception enforcement only. Fabricator must confirm resin fill, copper caps, planarity and flex process before ordering.'};fs.writeFileSync(output,JSON.stringify(report,null,2)+'\n');console.log(report.status,report.nativeThermalVias,'filled/capped U1 exposed-pad vias;',failures);if(failures.length)process.exitCode=1;