0hmX/am3352-ddr-track-a-local-dfm-wip-20261007
Experimental RJ45-corrected board with isolated PG indication. 1005/1005 source joins pass; 15 expanded-guard physical errors, sourcing and qualification gates remain. Not fabrication-ready.
- Version
- 0.0.14
- License
- unset
- Stars
- 0
layout/saved-geometry-guard.tsx
// Browser-safe geometry guard; generated baseline from the checked native board.
// Numeric IDs and record ordering are excluded; physical dimensions use 0.1 nm precision.
const expectedGeometryFingerprint = "5c7ef8856a7c24cb"
export function pcbGeometryFingerprint(db: any): string {
const components = new Map(db.source_component.list().map((r: any) => [r.source_component_id, r.name]))
const pcbComponents = new Map(db.pcb_component.list().map((r: any) => [r.pcb_component_id, components.get(r.source_component_id)]))
const ports = new Map(db.source_port.list().filter((r: any) => components.has(r.source_component_id)).map((r: any) => [r.source_port_id, `${components.get(r.source_component_id)}.${r.pin_number || r.name}`]))
const netNames = new Map(db.source_net.list().map((r: any) => [r.source_net_id, r.name]))
const netBindings = new Map<string, Set<string>>()
for (const trace of db.source_trace.list()) {
for (const id of trace.connected_source_port_ids ?? []) {
const names = netBindings.get(id) ?? new Set<string>()
for (const net of trace.connected_source_net_ids ?? []) names.add(String(netNames.get(net)))
netBindings.set(id, names)
}
}
let expanded = true
while (expanded) {
expanded = false
for (const group of db.source_component_internal_connection.list()) {
const names = new Set<string>(group.source_port_ids.flatMap((id: string) => [...(netBindings.get(id) ?? [])]))
for (const id of group.source_port_ids) {
if ([...(netBindings.get(id) ?? [])].length !== names.size) expanded = true
netBindings.set(id, new Set(names))
}
}
}
const pcbPorts = new Map(db.pcb_port.list().map((r: any) => [r.pcb_port_id, ports.get(r.source_port_id)]))
const fields: Record<string, string[]> = {
pcb_board: ["center", "width", "height", "thickness", "num_layers", "outline"],
pcb_component: ["center", "rotation", "layer"],
pcb_port: ["x", "y", "layers"],
pcb_smtpad: ["x", "y", "layer", "shape", "radius", "width", "height", "ccw_rotation", "corner_radius", "points", "solder_mask_margin", "is_covered_with_solder_mask"],
pcb_plated_hole: ["x", "y", "layers", "shape", "hole_diameter", "outer_diameter", "hole_height", "hole_width", "outer_height", "outer_width", "ccw_rotation", "is_covered_with_solder_mask"],
pcb_via: ["x", "y", "layers", "from_layer", "to_layer", "hole_diameter", "outer_diameter", "tented_on_top", "tented_on_bottom"],
pcb_hole: ["x", "y", "hole_diameter", "hole_shape", "hole_width", "hole_height"],
}
const normalize = (v: any): any => typeof v === "number" ? Math.round(v * 1e7) / 1e7 : Array.isArray(v) ? v.map(normalize) : v && typeof v === "object" ? Object.fromEntries(Object.keys(v).sort().map(k => [k, normalize(v[k])])) : v ?? null
const rows: string[] = []
for (const [type, keys] of Object.entries(fields)) {
for (const r of db[type].list()) {
const identity = type === "pcb_component" ? components.get(r.source_component_id) : type === "pcb_port" ? ports.get(r.source_port_id) : pcbPorts.get(r.pcb_port_id) ?? pcbComponents.get(r.pcb_component_id) ?? null
// Manually placed vias create synthetic ports/components; their actual copper is checked below.
if ((type === "pcb_component" || type === "pcb_port") && !identity) continue
const namedNets = type === "pcb_via" ? [netNames.get(r.source_net_id)] : type === "pcb_port" ? [...(netBindings.get(r.source_port_id) ?? [])].sort() : null
rows.push(JSON.stringify([type, identity, namedNets, ...keys.map(k => normalize(r[k]))]))
}
}
const text = rows.sort().join("\n")
let a = 2166136261, b = 3339675911
for (let i = 0; i < text.length; i++) {
a = Math.imul(a ^ text.charCodeAt(i), 16777619)
b = Math.imul(b ^ text.charCodeAt(i), 2246822519)
}
return `${(a >>> 0).toString(16).padStart(8, "0")}${(b >>> 0).toString(16).padStart(8, "0")}`
}
export function assertSavedGeometry(db: any): void {
const board = db.pcb_board.list()[0]
const rules: Record<string, number> = {
min_board_edge_clearance: 0.2, min_pad_edge_to_pad_edge_clearance: 0.1,
min_plated_hole_drill_edge_to_drill_edge_clearance: 0.15,
min_trace_to_hole_edge_clearance: 0.2, min_trace_to_pad_edge_clearance: 0.1,
min_trace_width: 0.1, min_via_hole_diameter: 0.15,
min_via_hole_edge_to_via_hole_edge_clearance: 0.1, min_via_pad_diameter: 0.3,
}
for (const [name, value] of Object.entries(rules)) {
if (board[name] !== value) throw new Error(`Saved routing requires ${name}=${value}; found ${board[name]}`)
}
const actual = pcbGeometryFingerprint(db)
if (actual !== expectedGeometryFingerprint) throw new Error(`Saved routing requires unchanged PCB placement and footprints (${actual} != ${expectedGeometryFingerprint}). Restore the checked geometry or deliberately reroute and validate the changed board.`)
}