Record Accepted PCB Placement And Fit

Align component groups, repair affected routing, and add preservation
audits.
Assign the confirmed U2 footprint and update pull-ups to 2 kΩ across
design files.
Document user acceptance, switch to an A3 worksheet, and refresh PCB
exports.
This commit is contained in:
2026-09-22 10:28:08 +02:00
parent 901afbe754
commit c257158ada
42 changed files with 29500 additions and 17205 deletions
+19 -11
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
"""Read-only PCB checks and fresh KiCad reports; does not regenerate or save PCB.
Requires KiCad's pcbnew binding in system Python. The known U2 footprint parity
warning is reported explicitly, not hidden or added to KiCad's exclusions.
Requires KiCad's pcbnew binding in system Python. Schematic footprint parity
must be clean, including the user-confirmed U2 reference footprint assignment.
"""
import hashlib
import json
@@ -23,6 +23,13 @@ run("kicad-cli","sch","export","netlist","--format","kicadxml","-o",str(OUT/"pcb
run("kicad-cli","pcb","drc","--format","json","--all-track-errors","--severity-all","--schematic-parity","-o",str(OUT/"pcb-parity-drc.json"),str(PCB))
board=p.LoadBoard(str(PCB))
verify(board)
from update_presentation import expected_tree, CAPTION
from validate_u1_update import parse, canonical
tree=parse(PCB)
assert ['paper', '"A3"'] in tree, "A3 worksheet required to clear the title block"
assert canonical(expected_tree(tree)) == canonical(tree), "Stale presentation labels"
assert board.GetTitleBlock().GetComment(0) == ""
assert any(isinstance(g,p.PCB_TEXT) and g.GetText()==CAPTION for g in board.GetDrawings())
source=ET.parse(OUT/"pcb-source-netlist.xml").getroot()
comps={c.get("ref"):c for c in source.findall("components/comp")}
footprints={f.GetReference():f for f in board.GetFootprints()}
@@ -38,9 +45,9 @@ expected_edges={frozenset((a,b)) for a,b in zip(expected_outline,expected_outlin
actual_edges={frozenset((round(p.ToMM(v.x)-100,5),round(p.ToMM(v.y)-100,5))
for v in (d.GetStart(),d.GetEnd())) for d in outline}
assert actual_edges==expected_edges
placements={"U1":(8,23),"U2":(43,26.670),"DS1":(43,36),
"R1":(43,34),"R2":(54,34),"R3":(65,34),
"SW1":(43,68),"SW2":(55,68),"SW3":(67,68),
placements={"U1":(8,23),"U2":(43,26.670),"DS1":(43.97,36),
"R1":(42.16,32.6685),"R2":(53.16,32.6685),"R3":(64.16,32.6685),
"SW1":(41.72,68),"SW2":(53.72,68),"SW3":(65.72,68),
"H1":(3.5,22.5),"H2":(3.5,75),"H3":(78,4),"H4":(78,76)}
for ref,(x,y) in placements.items():
position=footprints[ref].GetPosition()
@@ -72,7 +79,7 @@ for ref,comp in comps.items():
assert fp.GetPath().AsString().endswith("/"+comp.findtext("tstamps")),ref
wanted=comp.findtext("footprint")
if ref=="U2":
assert not wanted
assert wanted=="Carrier:MAX3243_Reference_Provisional"
assert fp.GetFPIDAsString()=="Carrier:MAX3243_Reference_Provisional"
else:
assert fp.GetFPIDAsString()==wanted,ref
@@ -102,8 +109,7 @@ report=json.loads((OUT/"pcb-parity-drc.json").read_text())
assert not report["violations"],report["violations"]
assert not report["unconnected_items"],report["unconnected_items"]
parity=report["schematic_parity"]
assert len(parity)==1 and parity[0]["type"]=="footprint_symbol_mismatch",parity
assert len(parity[0]["items"])==1 and parity[0]["items"][0]["uuid"]==footprints["U2"].m_Uuid.AsString()
assert not parity,parity
summary={
"carrier_bounds_mm":[82,80],
"outline_local_mm":expected_outline,
@@ -120,12 +126,14 @@ summary={
"physical_DRC_violations":0,
"unconnected_items":0,
"schematic_pad_nets_match":True,
"known_parity_warning":"U2 reference footprint assigned on PCB only; schematic footprint intentionally blank; nominal male external metal dimensions user-confirmed",
"schematic_parity_violations":0,
"project_settings_sha256":hashlib.sha256((ROOT/'serial-carrier.kicad_pro').read_bytes()).hexdigest(),
"ignored_DRC_checks":report["ignored_checks"],
"not_validated":["male module pin map/header fit", "ESP32 measured-planar 1:1 fit and complete assembly envelope/heights", "header/socket fit", "RF performance and antenna clearance", "power/return-path integrity", "USB power path", "OLED pull-ups", "fabrication process", "hardware operation"],
"user_accepted":["module dimensions/visual fit and USB clearance", "male pinout/header/footprint and pin-by-pin review", "M3 carrier/module and M2 display hardware", "RF keepout and power/ground routing"],
"not_independently_verified":["reported 10 mm assembled module elevation", "regulator margin", "USB backfeed safety", "OLED onboard pull-up resistance/rail", "manufacturer RF qualification", "fabrication process/certification"],
"new_hardware_tests":False,
}
(OUT/"pcb-validation-summary.json").write_text(json.dumps(summary,indent=2)+"\n")
print("PCB draft verified: 82 x 80 mm; 2 copper layers; 0 physical DRC violations; 0 unrouted.")
print("All schematic pad nets match. One expected U2 footprint parity warning remains visible.")
print("All schematic pad nets and footprint assignments match. Zero schematic parity violations.")
print("Not fabrication-ready; see ../../docs/devel/hardware/PCB/pcb-draft-notes.md and ignored checks in the DRC report.")