"""Verify the five reviewed EDL NC markers against a compiled pre-change baseline.""" import argparse import json import xml.etree.ElementTree as ET from check_hardware import Board from schematic_maintenance import ROOT from unconnected_inventory import inventory, write_inventory OUT = ROOT / 'out/edl-nc-review' CLI = 'D:/KiCad/bin/kicad-cli.exe' def snapshot(path): root = ET.parse(path).getroot() return ({c.attrib['ref']: ET.tostring(c) for c in root.findall('components/comp')}, {n.attrib['name']: {(p.attrib['ref'], p.attrib['pin']): dict(p.attrib) for p in n.findall('node')} for n in root.findall('nets/net')}) def main(): ap = argparse.ArgumentParser(description=__doc__) ap.add_argument('--baseline', action='store_true') args = ap.parse_args() out = OUT / ('before' if args.baseline else 'after') if args.baseline and out.exists(): raise RuntimeError('Refusing to overwrite the baseline') out.mkdir(parents=True, exist_ok=True) results, rows = {}, [] for number in (1, 2): b = Board(number) b.compile(CLI, out) if args.baseline: continue old_parts, old_nets = snapshot(OUT / 'before' / f'Board{number}.xml') new_parts, new_nets = snapshot(out / f'Board{number}.xml') assert old_parts == new_parts, 'Component metadata changed' approved = {(f'U4{ch}', '3') for ch in range(1, 6)} if number == 2 else set() changed = set() assert old_nets.keys() == new_nets.keys(), 'Net names changed' for name, endpoints in old_nets.items(): assert endpoints.keys() == new_nets[name].keys(), 'Connectivity changed' for endpoint, attrs in endpoints.items(): expected = dict(attrs) if endpoint in approved: assert len(endpoints) == 1 and name.startswith('unconnected-') assert attrs['pintype'] == 'passive' expected['pintype'] = 'passive+no_connect' actual = new_nets[name][endpoint] assert actual == expected, (endpoint, actual, expected) if actual != attrs: changed.add(endpoint) assert changed == approved if number == 2: for ch in range(1, 6): u, j, r = f'U4{ch}', f'J6{ch}', f'R74{ch}' assert b.net_members[b.net(u, 1)] == {(u, '1'), (j, '1')} assert b.net_members[b.net(u, 4)] == {(u, '4'), (j, '2')} assert b.net(u, 2) == 'GND' and b.net(u, 5) == '+3V3_HUB' assert b.net(u, 6) == f'EDL_EN{ch}' assert b.resistor(r) == 100000 assert {b.net(r, 1), b.net(r, 2)} == {'GND', b.net(u, 6)} old_erc = json.loads((OUT / 'before' / f'Board{number}-erc.json').read_text()) new_erc = json.loads((out / f'Board{number}-erc.json').read_text()) for key in ('ignored_checks', 'included_severities'): assert old_erc[key] == new_erc[key] def violations(report): # KiCad regenerates ERC pin UUIDs on each CLI load. return sorted(json.dumps([s['path'], v['type'], v['severity'], v['description'], [{k: value for k, value in item.items() if k != 'uuid'} for item in v['items']]], sort_keys=True) for s in report['sheets'] for v in s['violations']) expected_erc = json.loads(json.dumps(old_erc)) removed = 0 for sheet in expected_erc['sheets']: kept = [] for v in sheet['violations']: is_target = (number == 2 and v['type'] == 'pin_not_connected' and any(f'Symbol U4{ch} ' in v['items'][0]['description'] for ch in range(1, 6))) if is_target: removed += 1 else: kept.append(v) sheet['violations'] = kept assert removed == len(approved) assert violations(expected_erc) == violations(new_erc), 'Unexpected ERC change' rows.extend(inventory(b)) results[number] = {'components_unchanged': len(new_parts), 'nets_unchanged': len(new_nets), 'reviewed_nc': sorted(approved), 'erc': b.erc} if not args.baseline: result = {'status': 'PASS', 'boards': results, 'inventory': write_inventory(OUT, rows), 'evidence': 'datasheets/ic/TS5A3157.pdf pages 3 and 16', 'scope': 'Unused switch port and powered default selection only; not power-off isolation qualification'} (OUT / 'verification.json').write_text(json.dumps(result, indent=2) + '\n') print(json.dumps(result)) if __name__ == '__main__': main()