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
scripts/verify-native-layout.tsx
import { Circuit } from "@tscircuit/core"
import { createHash } from "node:crypto"
import { readFileSync } from "node:fs"
import Board from "../index"
// Independently captured from the checked routed reference before its removal.
const expected: Record<string, { count: number; sha256: string }> = {
"segments": {
"count": 18672,
"sha256": "0e5974b6ee4a6a89edc105c4e486594fe270a3af9ef25b3c1bcc8166e3e5fda8"
},
"vias": {
"count": 1143,
"sha256": "090b556763a7a0ae5d20f6d792788428feae569ea25ff6c2a39d38e23eaec74d"
},
"pours": {
"count": 76,
"sha256": "7a7c3f0fe9ca2eb048bb7de47f7a2982ec6318966fd54aca4723a61fbbb772d5"
}
}
function stable(value: any): any {
if (typeof value === "number") return Math.round(value * 1e8)
if (Array.isArray(value)) return value.map(stable)
if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map(k => [k, stable(value[k])]))
return value ?? null
}
function fingerprints(records: any[]) {
const nets = new Map(records.filter(r => r.type === "source_net").map(r => [r.source_net_id, r.name]))
const traces = new Map(records.filter(r => r.type === "source_trace").map(r => [r.source_trace_id, r]))
const rows: Record<string, string[]> = { segments: [], vias: [], pours: [] }
for (const r of records) {
if (r.type === "pcb_trace") {
const trace = traces.get(r.source_trace_id)
if (!trace || trace.connected_source_net_ids.length !== 1) throw Error(`Ambiguous route net: ${r.pcb_trace_id}`)
const net = nets.get(trace.connected_source_net_ids[0])
for (let i = 1; i < r.route.length; i++) {
const a = r.route[i - 1], b = r.route[i]
if (a.route_type !== "wire" || b.route_type !== "wire") continue
if (a.layer !== b.layer) throw Error("Wire changes layer without a via")
const points = [[a.x, a.y], [b.x, b.y]].map(p => JSON.stringify(stable(p))).sort()
if (points[0] !== points[1]) rows.segments.push(JSON.stringify([net, a.layer, stable(a.width), ...points]))
}
} else if (r.type === "pcb_via" || r.type === "pcb_copper_pour") {
const keys = r.type === "pcb_via"
? ["x", "y", "hole_diameter", "outer_diameter", "layers", "tented_on_top", "tented_on_bottom"]
: ["layer", "shape", "brep_shape", "points", "covered_with_solder_mask"]
rows[r.type === "pcb_via" ? "vias" : "pours"].push(JSON.stringify(stable([nets.get(r.source_net_id), ...keys.map(k => r[k])])) )
}
}
return Object.fromEntries(Object.entries(rows).map(([kind, values]) => [kind, { count: values.length, sha256: createHash("sha256").update(values.sort().join("\n")).digest("hex") }]))
}
if (process.argv[2] === "--capture") {
console.log(JSON.stringify(fingerprints(JSON.parse(readFileSync(process.argv[3], "utf8"))), null, 2))
} else {
const circuit = new Circuit()
circuit.add(<Board />)
await circuit.renderUntilSettled()
const records = circuit.getCircuitJson()
const errors = records.filter(r => r.type.endsWith("_error"))
if (errors.length) throw Error(`Native render errors: ${errors.map(r => r.type).join(", ")}`)
const actual = fingerprints(records)
console.log(JSON.stringify(actual, null, 2))
if (JSON.stringify(actual) !== JSON.stringify(expected)) throw Error("Native copper differs from the checked routed reference")
console.log("PASS: native segments, widths, layers, net bindings, vias, tenting and pours preserved")
}