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/check-source-integrity.py

"""Compare the corrected design against v0.2.15 plus the explicit reviewed electrical delta."""
from pathlib import Path
import json,hashlib,sys
root=Path(__file__).resolve().parent.parent

def functional(c):
    components={e['source_component_id']:e for e in c if e['type']=='source_component'}
    ports={e['source_port_id']:(components[e['source_component_id']]['name'],e['pin_number']) for e in c if e['type']=='source_port'}
    nets={e['source_net_id']:e['name'] for e in c if e['type']=='source_net'}
    connected={n:[] for n in nets.values()}
    for e in c:
        if e['type']=='source_trace':
            for n in e['connected_source_net_ids']:
                connected[nets[n]].extend(ports[p] for p in e['connected_source_port_ids'])
    design={n:sorted(set(tuple(p) for p in v)) for n,v in connected.items()}
    parts={e['name']:{k:e[k] for k in ['ftype','manufacturer_part_number','resistance','capacitance','inductance','supplier_part_numbers'] if k in e} for e in components.values()}
    internal=sorted([sorted(ports[p] for p in e['source_port_ids']) for e in c if e['type']=='source_component_internal_connection'])
    return {'nets':design,'parts':parts,'internal':internal}

manifest=json.loads((root/'reports/electrical-fixes/approved-design-delta.json').read_text())
base=json.loads((root/manifest['baseline']).read_text())
expected=json.loads(json.dumps(base))
for key,(before,after) in manifest['reviewedPinMoves'].items():
    ref,pin=key.split('.');pad=[ref,int(pin)]
    assert pad in expected['nets'][before],key
    expected['nets'][before].remove(pad);expected['nets'].setdefault(after,[]).append(pad)
for key,net in manifest['reviewedPinAdditions'].items():
    ref,pin=key.split('.');pad=[ref,int(pin)]
    assert not any(pad in group for group in expected['nets'].values()),key
    expected['nets'].setdefault(net,[]).append(pad)
for group in expected['nets'].values():group.sort()
expected['parts'].update(manifest['reviewedReplacementAndAddedParts'])
circuit_file=root/(sys.argv[1] if len(sys.argv)>1 else 'dist/index/circuit.json')
c=json.loads(circuit_file.read_text());actual=json.loads(json.dumps(functional(c)))
assert actual['nets']==expected['nets'],'Unexpected functional pin-to-net change'
assert actual['internal']==expected['internal'],'Unexpected internal component connection'
assert actual['parts']==expected['parts'],[(name,part,expected['parts'].get(name)) for name,part in actual['parts'].items() if part!=expected['parts'].get(name)]
assert len(actual['nets'])==manifest['expectedFunctionalNets']
assert sum(map(len,actual['nets'].values()))==manifest['expectedFunctionalPads']
assert len(actual['parts'])==manifest['expectedComponents']
assert all(e['layer']=='top' for e in c if e['type']=='pcb_component')
placement=json.loads((root/'flex-placement.json').read_text());oldplacement=json.loads((root/'reports/electrical-fixes/placement-baseline-v0215.json').read_text())
allowed=set(manifest['allowedPlacementChanges'])
for ref,old in oldplacement.items():
    if ref in allowed:continue
    assert ref in placement,ref
    for k,v in old.items():
        assert abs(v-placement[ref][k])<1e-8 if isinstance(v,(float,int)) else v==placement[ref][k],(ref,k)
report={'status':'PASS','functionalNetCount':len(actual['nets']),'requiredFunctionalPads':sum(map(len,actual['nets'].values())),'pcbComponentCount':len(actual['parts']),'reviewedDesignDelta':'reports/electrical-fixes/approved-design-delta.json','unchanged':'Every unlisted part, functional pin-to-net assignment, internal connection and placement matches the proven v0.2.15 release. All162 components remain flat-top.','sourceCircuitFile':str(circuit_file.relative_to(root)),'sourceCircuitSha256':hashlib.sha256(circuit_file.read_bytes()).hexdigest()}
(root/'reports/source-integrity.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report,indent=2))