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/verify-warning-invariants.py

"""Prove warning cleanup preserves the released electrical graph and solid assembly."""
from pathlib import Path
from collections import Counter
import hashlib,json,runpy
root=Path(__file__).resolve().parent.parent
old=json.loads((root/'baseline-v0216/index.circuit.json').read_text());new=json.loads((root/'dist/index/circuit.json').read_text())
rename={'R60':'L4','L6':'LRX'}
name=lambda n:rename.get(n,n)
components=lambda c:{e['source_component_id']:e for e in c if e['type']=='source_component'}
oldc,newc=components(old),components(new)
assert set(oldc)==set(newc) and len(newc)==162
changes={'Q3':'simple_mosfet','Q4':'simple_mosfet','D1':'simple_diode',**{n:'simple_connector' for n in ['J1','J2','J3','J4','J5','J6','J7','J8']},**{n:'simple_push_button' for n in ['SW1','SW2','SW3']},**{f'TP{i}':'simple_test_point' for i in range(1,7)}}
for ident,e in oldc.items():
 n=newc[ident];assert name(n['name'])==e['name'];assert n['ftype']==changes.get(e['name'],e['ftype'])
 for k in ['manufacturer_part_number','supplier_part_numbers','resistance','capacitance','inductance','frequency','load_capacitance']:assert n.get(k)==e.get(k),(e['name'],k)
def electrical(c):
 cs=components(c);ps={e['source_port_id']:(name(cs[e['source_component_id']]['name']),e['pin_number']) for e in c if e['type']=='source_port'}
 ns={e['source_net_id']:e['name'] for e in c if e['type']=='source_net'}
 graph={n:set() for n in ns.values()}
 for e in c:
  if e['type']=='source_trace':
   for n in e['connected_source_net_ids']:graph[ns[n]].update(ps[p] for p in e['connected_source_port_ids'])
 internal=sorted(sorted(ps[p] for p in e['source_port_ids']) for e in c if e['type']=='source_component_internal_connection')
 return graph,internal
a,b=electrical(old),electrical(new);assert a==b,'Changed a physical pin assignment or internal switch connection'
assert len(b[0])==94 and sum(map(len,b[0].values()))==500
# These are actual native geometry, not bounding-box approximations.
physical=['pcb_board','pcb_bend','pcb_stiffener','pcb_keepout','pcb_cutout','pcb_port','pcb_smtpad','pcb_plated_hole','pcb_hole','pcb_via','cad_component']
for typ in physical:assert [e for e in old if e['type']==typ]==[e for e in new if e['type']==typ],typ
clean=lambda e:{k:v for k,v in e.items() if k not in ['cable_insertion_center','insertion_direction']}
assert [clean(e) for e in old if e['type']=='pcb_component']==[clean(e) for e in new if e['type']=='pcb_component']
assert all(e['layer']=='top' for e in new if e['type']=='pcb_component')
cache=json.loads((root/'routing/final/cache.json').read_text());base=json.loads((root/'baseline-v0216/cache.json').read_text())
assert cache['input']==base['input'],'Changed routing inputs or design rules'
allowed=set(json.loads((root/'reports/warning-cleanup/style-changes.json').read_text())['changedTraces'])
oled_check=root/'scripts/verify-oled-clock-invariants.py'
if oled_check.exists():allowed.add('source_net_57_grid11170_material_0')
actual=[]
for t,u in zip(base['traces'],cache['traces'],strict=True):
 assert {k:v for k,v in t.items() if k!='route'}=={k:v for k,v in u.items() if k!='route'}
 assert t['route'][0]==u['route'][0] and t['route'][-1]==u['route'][-1]
 assert [p for p in t['route'] if p['route_type']=='via']==[p for p in u['route'] if p['route_type']=='via']
 if t['route']!=u['route']:actual.append(t['pcb_trace_id']);assert t['pcb_trace_id'] in allowed
assert set(actual)==allowed and len(actual)<=(4 if oled_check.exists() else 3)
if oled_check.exists():runpy.run_path(str(oled_check),run_name='__main__')
# All enclosure/assembly assets are unchanged from the published release.
provenance=json.loads((root/'release-provenance.json').read_text());assets={p:h for p,h in provenance['sha256'].items() if p.startswith('mechanical/') and p.endswith(('.ts','.glb','.stl'))}
derived={'mechanical/upright-pcb.glb','mechanical/upright-pcb.ts','mechanical/upright-watch.glb'} if oled_check.exists() else set()
for p,h in assets.items():
 if p not in derived:assert hashlib.sha256((root/p).read_bytes()).hexdigest()==h,p
if derived:assert json.loads((root/'reports/warning-cleanup/mesh-invariants.json').read_text())['status']=='PASS'
r={'status':'PASS','functionalNets':94,'functionalPads':500,'topComponents':162,'referenceRenames':rename,'nativeTypesCorrected':changes,'padsPortsViasComponentPositionsBoardBendsAndCadIdentical':True,'routingInputAndManufacturingRulesByteEquivalent':True,'changedTraceIds':actual,'allTraceEndpointsAndViasPreserved':True,'unchangedMechanicalAssets':len(assets),'baseline':'Published0.2.16','newSourceSha256':hashlib.sha256((root/'dist/index/circuit.json').read_bytes()).hexdigest()}
(root/'reports/warning-cleanup/invariants.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))