ShiboSoftwareDev/mspm0g3507-usb-c-dev-board

This circuit features a USB Type-C connector with integrated resistors and passives, a USB ESD protection device, a CH340 USB-to-serial interface chip, a 3.3V regulator (AP2112K), multiple decoupling and bulk capacitors, and a Microcontroller (MSPM0G3507) with associated I2C and SPI connections, providing USB communication, power regulation, and RGB LED control.

Version
1.4.1
License
unset
Stars
0

scripts/audit-fabrication.mjs

import { readFileSync } from "node:fs"
import {
  runAllNetlistChecks,
  runAllPinSpecificationChecks,
  runAllPlacementChecks,
  runAllRoutingChecks,
} from "@tscircuit/checks"

const circuitPath = process.argv[2] ?? "dist/index/circuit.json"
const circuit = JSON.parse(readFileSync(circuitPath, "utf8"))
const source = readFileSync("index.circuit.tsx", "utf8")
const failures = []

const elements = (type) => circuit.filter((element) => element.type === type)
const assert = (condition, message) => {
  if (!condition) failures.push(message)
}
const rounded = (value) => Number(value.toFixed(3))

const sourceComponents = elements("source_component")
const sourcePorts = elements("source_port")
const sourceNets = elements("source_net")
const sourceTraces = elements("source_trace")
const pcbComponents = elements("pcb_component")
const pcbBoards = elements("pcb_board")
const pcbPorts = elements("pcb_port")
const pcbTraces = elements("pcb_trace")
const vias = elements("pcb_via")
const schematicSheets = elements("schematic_sheet")
const schematicComponents = elements("schematic_component")
const schematicTraces = elements("schematic_trace")
const courtyards = [
  ...elements("pcb_courtyard_outline"),
  ...elements("pcb_courtyard_rect"),
]

const sourceComponentById = new Map(
  sourceComponents.map((component) => [component.source_component_id, component]),
)
const componentByName = new Map(
  sourceComponents.map((component) => [component.name, component]),
)
const sourceNetByName = new Map(sourceNets.map((net) => [net.name, net]))
const portsByComponentId = new Map()
for (const port of sourcePorts) {
  const ports = portsByComponentId.get(port.source_component_id) ?? []
  ports.push(port)
  portsByComponentId.set(port.source_component_id, ports)
}
const pcbComponentBySourceId = new Map(
  pcbComponents.map((component) => [component.source_component_id, component]),
)
const approximately = (actual, expected, tolerance = 0.001) =>
  Math.abs(actual - expected) <= tolerance
const pcbPortBySourceId = new Map(
  pcbPorts.map((port) => [port.source_port_id, port]),
)
const pcbPortById = new Map(pcbPorts.map((port) => [port.pcb_port_id, port]))
const pcbTracesBySourceId = new Map()
for (const trace of pcbTraces) {
  const traces = pcbTracesBySourceId.get(trace.source_trace_id) ?? []
  traces.push(trace)
  pcbTracesBySourceId.set(trace.source_trace_id, traces)
}
const viaCountByPcbTraceId = new Map()
for (const via of vias) {
  viaCountByPcbTraceId.set(
    via.pcb_trace_id,
    (viaCountByPcbTraceId.get(via.pcb_trace_id) ?? 0) + 1,
  )
}

const sourcePort = (componentName, portName) => {
  const component = componentByName.get(componentName)
  return (portsByComponentId.get(component?.source_component_id) ?? []).find(
    (port) => port.name === portName || port.port_hints?.includes(portName),
  )
}
const assertPortNet = (componentName, portName, netName) => {
  const port = sourcePort(componentName, portName)
  const net = sourceNetByName.get(netName)
  assert(Boolean(port), `${componentName}.${portName} is missing`)
  assert(Boolean(net), `net.${netName} is missing`)
  assert(
    port?.subcircuit_connectivity_map_key === net?.subcircuit_connectivity_map_key,
    `${componentName}.${portName} is not on net.${netName}`,
  )
}

const traceLength = (trace) => {
  let length = 0
  for (let index = 1; index < trace.route.length; index += 1) {
    const previous = trace.route[index - 1]
    const current = trace.route[index]
    length += Math.hypot(current.x - previous.x, current.y - previous.y)
  }
  return length
}
const traceStats = (name) => {
  const sourceTrace = sourceTraces.find((trace) => trace.name === name)
  assert(sourceTrace, `Missing named source trace ${name}`)
  if (!sourceTrace) return { length: Number.NaN, vias: Number.NaN, layers: [] }
  const traces = pcbTracesBySourceId.get(sourceTrace.source_trace_id) ?? []
  assert(traces.length > 0, `${name} has no routed PCB trace`)
  return {
    sourceTrace,
    traces,
    length: traces.reduce((sum, trace) => sum + traceLength(trace), 0),
    vias: traces.reduce(
      (sum, trace) => sum + (viaCountByPcbTraceId.get(trace.pcb_trace_id) ?? 0),
      0,
    ),
    layers: [
      ...new Set(
        traces.flatMap((trace) =>
          trace.route.map((point) => point.layer).filter(Boolean),
        ),
      ),
    ],
  }
}

// Three-terminal copper trees can be represented as autorouter MST segments.
// Prefer a routed endpoint-to-endpoint segment; otherwise use the same
// straight-line fallback as `tsci check trace-length`.
const endpointTraceLength = (name) => {
  const stats = traceStats(name)
  const sourceIds = new Set(stats.sourceTrace.connected_source_port_ids)
  const exact = stats.traces.find((trace) => {
    const pcbSourceIds = (trace.connectsTo ?? [])
      .map((pcbPortId) => pcbPortById.get(pcbPortId)?.source_port_id)
      .filter(Boolean)
    return pcbSourceIds.length === sourceIds.size && pcbSourceIds.every((id) => sourceIds.has(id))
  })
  if (exact) return traceLength(exact)
  const endpoints = stats.sourceTrace.connected_source_port_ids
    .map((id) => pcbPortBySourceId.get(id))
    .filter(Boolean)
  assert(endpoints.length === 2, `${name} does not have two positioned endpoints`)
  return Math.hypot(endpoints[1].x - endpoints[0].x, endpoints[1].y - endpoints[0].y)
}

const checkResults = {
  netlist: await runAllNetlistChecks(circuit),
  pinSpecification: await runAllPinSpecificationChecks(circuit),
  placement: await runAllPlacementChecks(circuit),
  routing: await runAllRoutingChecks(circuit),
}
for (const [name, results] of Object.entries(checkResults)) {
  assert(
    results.length === 0,
    `${name} checks returned ${results.length}: ${results.map((result) => result.message).join(" | ")}`,
  )
}

assert(sourceComponents.length === 38, `Expected 38 source components, found ${sourceComponents.length}`)
assert(pcbComponents.length === 38, `Expected 38 PCB components, found ${pcbComponents.length}`)

assert(pcbBoards.length === 1, `Expected one PCB outline, found ${pcbBoards.length}`)
const pcbBoard = pcbBoards[0]
assert(
  approximately(pcbBoard?.width, 90) && approximately(pcbBoard?.height, 21),
  `PCB bounds are ${pcbBoard?.width ?? "missing"} mm by ${pcbBoard?.height ?? "missing"} mm instead of 90 mm by 21 mm`,
)
const expectedBoardOutline = [
  [-45, 10.5], [45, 10.5], [45, -10.5], [-45, -10.5],
]
assert(
  pcbBoard?.outline?.length === expectedBoardOutline.length &&
    expectedBoardOutline.every(([x, y], index) =>
      approximately(pcbBoard.outline[index]?.x, x) &&
      approximately(pcbBoard.outline[index]?.y, y),
    ),
  "PCB outline is not the expected uniform 90 mm by 21 mm Pico-width rectangle",
)
const topHeader = pcbComponentBySourceId.get(componentByName.get("J_TOP")?.source_component_id)
const bottomHeader = pcbComponentBySourceId.get(componentByName.get("J_BOTTOM")?.source_component_id)
const headerRowSpacing = Math.abs(topHeader?.center.y - bottomHeader?.center.y)
const boardHalfHeight = 10.5
const boardMinX = -45
const boardMaxX = 45
const edgeOverhang = boardHalfHeight - Math.abs(topHeader?.center.y)
const breadboardPitch = 2.54
const nominalJumperHousingHalfWidth = breadboardPitch / 2
const adjacentHoleCenterClearance =
  Math.abs(topHeader?.center.y) + breadboardPitch - boardHalfHeight
const adjacentJumperBodyClearance =
  adjacentHoleCenterClearance - nominalJumperHousingHalfWidth
const headerPadEdgeClearance =
  boardHalfHeight - (Math.abs(topHeader?.center.y) + topHeader?.height / 2)
assert(
  approximately(topHeader?.center.x, 0) && approximately(topHeader?.center.y, 8.89),
  "J_TOP is not centered on the +8.89 mm breadboard row",
)
assert(
  approximately(bottomHeader?.center.x, 0) && approximately(bottomHeader?.center.y, -8.89),
  "J_BOTTOM is not centered on the -8.89 mm breadboard row",
)
assert(approximately(headerRowSpacing, 17.78), `Header row spacing is ${headerRowSpacing} mm instead of 17.78 mm`)
assert(approximately(edgeOverhang, 1.61), `Header-to-board-edge overhang is ${edgeOverhang} mm instead of 1.61 mm`)
assert(
  adjacentHoleCenterClearance >= 0.8,
  `Immediately adjacent breadboard holes are obstructed: only ${adjacentHoleCenterClearance.toFixed(3)} mm from center to PCB edge`,
)
assert(
  headerPadEdgeClearance >= 0.3,
  `Header copper-to-board-edge clearance is only ${headerPadEdgeClearance.toFixed(3)} mm`,
)
for (const header of [topHeader, bottomHeader]) {
  assert(
    approximately(header?.width, 49.86) && approximately(header?.height, 1.6),
    "Header copper footprint is not 49.86 mm by 1.6 mm",
  )
}
let lastHeaderHousingClearance = Number.POSITIVE_INFINITY
for (const headerName of ["J_TOP", "J_BOTTOM"]) {
  const header = componentByName.get(headerName)
  const headerPcbComponent = pcbComponentBySourceId.get(header?.source_component_id)
  const xs = pcbPorts
    .filter((port) => port.pcb_component_id === headerPcbComponent?.pcb_component_id)
    .map((port) => port.x)
    .sort((a, b) => a - b)
  assert(xs.length === 20, `${headerName} has ${xs.length} PCB pins instead of 20`)
  assert(
    xs.slice(1).every((x, index) => approximately(x - xs[index], 2.54)),
    `${headerName} is not on a 2.54 mm breadboard grid`,
  )
  const headerHoles = elements("pcb_plated_hole").filter(
    (hole) => hole.pcb_component_id === headerPcbComponent?.pcb_component_id,
  )
  assert(headerHoles.length === 20, `${headerName} has ${headerHoles.length} plated holes instead of 20`)
  assert(
    headerHoles.every((hole) =>
      hole.shape === "circular_hole_with_rect_pad" &&
      approximately(hole.hole_diameter, 1.05) &&
      approximately(hole.rect_pad_width, 1.6) &&
      approximately(hole.rect_pad_height, 1.6) &&
      approximately(hole.rect_border_radius, 0.8) &&
      (Math.min(hole.rect_pad_width, hole.rect_pad_height) - hole.hole_diameter) / 2 >= 0.275 - 0.001,
    ),
    `${headerName} does not retain the supplier's 1.05 mm drill and 0.275 mm annular ring`,
  )
  const housingEnvelope = Math.max(...xs.map(Math.abs)) + nominalJumperHousingHalfWidth
  lastHeaderHousingClearance = Math.min(
    lastHeaderHousingClearance,
    Math.min(boardMaxX - housingEnvelope, -boardMinX - housingEnvelope),
  )
}
assert(
  lastHeaderHousingClearance >= 0.5,
  `Board ends too early: only ${lastHeaderHousingClearance.toFixed(3)} mm beyond the end-pin jumper housing`,
)

assert(schematicSheets.length === 1, `Expected one schematic sheet, found ${schematicSheets.length}`)
const mainSchematicSheet = schematicSheets[0]
assert(mainSchematicSheet?.name === "MAIN", "The main schematic sheet is missing or misnamed")
assert(mainSchematicSheet?.sheet_size === "ansi_b", "The main schematic sheet is not ANSI B")
assert(
  mainSchematicSheet?.sheet_width === 431.8 && mainSchematicSheet?.sheet_height === 279.4,
  "The main schematic sheet dimensions are not 431.8 mm by 279.4 mm",
)
assert(
  schematicComponents.length === sourceComponents.length &&
    schematicComponents.every(
      (component) => component.schematic_sheet_id === mainSchematicSheet?.schematic_sheet_id,
    ),
  "Not every source component is represented on the main schematic sheet",
)
assert(
  schematicTraces.every(
    (trace) => trace.schematic_sheet_id === mainSchematicSheet?.schematic_sheet_id,
  ),
  "Not every schematic trace is assigned to the main schematic sheet",
)
const schematicText = new Set(elements("schematic_text").map((text) => text.text))
for (const sectionTitle of [
  "USB-C receptacle & CC",
  "USB protection & UART bridge",
  "5 V to 3.3 V power",
  "MCU, reset & boot",
  "RGB debug LED",
  "I2C connectors",
  "SPI display connector",
  "GPIO & debug headers",
]) {
  assert(schematicText.has(sectionTitle), `Schematic section title is missing: ${sectionTitle}`)
}
for (const component of sourceComponents) {
  assert(Boolean(component.manufacturer_part_number), `${component.name} has no manufacturer part number`)
  assert(
    Array.isArray(component.supplier_part_numbers?.jlcpcb) &&
      component.supplier_part_numbers.jlcpcb.length > 0,
    `${component.name} has no JLCPCB part number`,
  )
}

const courtyardComponentIds = new Set(courtyards.map((courtyard) => courtyard.pcb_component_id))
for (const component of pcbComponents) {
  const sourceComponent = sourceComponentById.get(component.source_component_id)
  assert(
    courtyardComponentIds.has(component.pcb_component_id),
    `${sourceComponent?.name ?? component.pcb_component_id} has no courtyard`,
  )
  assert(component.layer === "top", `${sourceComponent?.name ?? component.pcb_component_id} is not on the top layer`)
}

for (const via of vias) {
  assert(
    via.layers.length === 2 && via.layers.includes("top") && via.layers.includes("bottom"),
    `${via.pcb_via_id} is not a top-to-bottom through-via`,
  )
  assert(
    approximately(via.hole_diameter, 0.3),
    `${via.pcb_via_id} drill is ${via.hole_diameter} mm instead of 0.30 mm`,
  )
  assert(
    approximately(via.outer_diameter, 0.45),
    `${via.pcb_via_id} pad is ${via.outer_diameter} mm instead of 0.45 mm`,
  )
}

const usbTraceNames = [
  "USB_DP_FLIP_A",
  "USB_DP_FLIP_B",
  "USB_DM_FLIP_A",
  "USB_DM_FLIP_B",
  "USB_DM_TO_ESD",
  "USB_DP_PROTECTED",
  "USB_DM_PROTECTED",
]
const criticalStats = Object.fromEntries(
  usbTraceNames.map((name) => [name, traceStats(name)]),
)
for (const [name, stats] of Object.entries(criticalStats)) {
  assert(stats.vias === 0, `${name} contains ${stats.vias} via(s)`)
  assert(
    stats.layers.length === 1 && stats.layers[0] === "top",
    `${name} is not entirely top-layer`,
  )
}

const protectedLengths = {
  DP: endpointTraceLength("USB_DP_PROTECTED"),
  DM: endpointTraceLength("USB_DM_PROTECTED"),
}
const protectedSkew = Math.abs(protectedLengths.DP - protectedLengths.DM)
assert(protectedSkew <= 0.2, `Protected USB pair skew is ${protectedSkew.toFixed(3)} mm`)

const joinPin1 = pcbPortBySourceId.get(sourcePort("R_USB_DM_JOIN", "pin1")?.source_port_id)
const joinPin2 = pcbPortBySourceId.get(sourcePort("R_USB_DM_JOIN", "pin2")?.source_port_id)
const joinSpan = Math.hypot(joinPin2.x - joinPin1.x, joinPin2.y - joinPin1.y)
const usbPaths = {
  A_DP: endpointTraceLength("USB_DP_FLIP_A") + protectedLengths.DP,
  A_DM: endpointTraceLength("USB_DM_FLIP_A") + endpointTraceLength("USB_DM_TO_ESD") + protectedLengths.DM,
  B_DP: endpointTraceLength("USB_DP_FLIP_B") + protectedLengths.DP,
  B_DM: endpointTraceLength("USB_DM_FLIP_B") + joinSpan + endpointTraceLength("USB_DM_TO_ESD") + protectedLengths.DM,
}
const usbSkew = {
  A: Math.abs(usbPaths.A_DP - usbPaths.A_DM),
  B: Math.abs(usbPaths.B_DP - usbPaths.B_DM),
}
assert(
  Math.max(usbSkew.A, usbSkew.B) <= 1,
  `USB end-to-end skew exceeds 1 mm: ${JSON.stringify(usbSkew)}`,
)

const vcoreStats = traceStats("VCORE_DECOUPLE")
assert(vcoreStats.vias === 0, `VCORE_DECOUPLE contains ${vcoreStats.vias} via(s)`)
assert(
  vcoreStats.layers.length === 1 && vcoreStats.layers[0] === "top",
  "VCORE_DECOUPLE is not entirely top-layer",
)
assert(vcoreStats.length <= 4, `VCORE_DECOUPLE is ${vcoreStats.length.toFixed(3)} mm, over 4 mm`)

for (const switchName of ["SW_BOOT", "SW_RESET"]) {
  const component = componentByName.get(switchName)
  const ports = portsByComponentId.get(component?.source_component_id) ?? []
  const pcbComponent = pcbComponentBySourceId.get(component?.source_component_id)
  const physicalPorts = pcbPorts.filter((port) => port.pcb_component_id === pcbComponent?.pcb_component_id)
  assert(component?.ftype === "simple_push_button", `${switchName} is not a semantic pushbutton`)
  assert(ports.length === 2 && physicalPorts.length === 2, `${switchName} is not a true two-terminal switch`)
  assert(
    ports[0]?.subcircuit_connectivity_map_key !== ports[1]?.subcircuit_connectivity_map_key,
    `${switchName} terminals are shorted together`,
  )
}
assertPortNet("SW_BOOT", "pin1", "PA18_BSL_INVOKE")
assertPortNet("SW_BOOT", "pin2", "VDD_3V3")
assertPortNet("SW_RESET", "pin1", "MCU_RESET_N")
assertPortNet("SW_RESET", "pin2", "GND")

const rgbLed = componentByName.get("D_USER_RGB")
const rgbPorts = portsByComponentId.get(rgbLed?.source_component_id) ?? []
assert(rgbLed?.ftype === "simple_chip", "D_USER_RGB is not a four-channel semantic component")
assert(rgbLed?.manufacturer_part_number === "SZYY1615RGB-A 4pin", "D_USER_RGB has the wrong MPN")
assert(rgbLed?.supplier_part_numbers?.jlcpcb?.[0] === "C3029072", "D_USER_RGB has the wrong JLCPCB part number")
assert(rgbPorts.length === 4, `D_USER_RGB has ${rgbPorts.length} ports instead of four`)
assertPortNet("D_USER_RGB", "pin4", "GND")
assert(sourcePort("D_USER_RGB", "pin4")?.requires_ground === true, "D_USER_RGB common cathode is not marked requiresGround")
const rgbAnodeNetKeys = new Set()
for (const [color, resistor, gpioNet, ledPin] of [
  ["red", "R_RGB_RED", "PB2_RGB_RED", "pin1"],
  ["green", "R_RGB_GREEN", "PB3_RGB_GREEN", "pin2"],
  ["blue", "R_RGB_BLUE", "PB14_RGB_BLUE", "pin3"],
]) {
  const resistorComponent = componentByName.get(resistor)
  assert(resistorComponent?.resistance === 330, `${resistor} is not 330 ohms`)
  assert(resistorComponent?.manufacturer_part_number === "0402WGF3300TCE", `${resistor} has the wrong MPN`)
  assert(resistorComponent?.supplier_part_numbers?.jlcpcb?.[0] === "C25104", `${resistor} has the wrong JLCPCB part number`)
  assertPortNet(resistor, "pin1", gpioNet)
  const ledPort = sourcePort("D_USER_RGB", ledPin)
  assert(ledPort?.requires_power === true, `D_USER_RGB ${color} anode is not marked requiresPower`)
  rgbAnodeNetKeys.add(ledPort?.subcircuit_connectivity_map_key)
  assert(
    ledPort?.subcircuit_connectivity_map_key ===
      sourcePort(resistor, "pin2")?.subcircuit_connectivity_map_key,
    `D_USER_RGB ${color} anode is not connected through ${resistor}`,
  )
}
assert(rgbAnodeNetKeys.size === 3, "D_USER_RGB color channels are shorted together")
assertPortNet("U_MCU", "PA7", "PA7")
assertPortNet("J_BOTTOM", "PA7", "PA7")

const expectedConnectorNets = {
  J_I2C_JST_SH: { pin1: "GND", pin2: "VDD_3V3", pin3: "PA0_I2C_SDA", pin4: "PA1_I2C_SCL" },
  J_GROVE_I2C: { pin1: "PA1_I2C_SCL", pin2: "PA0_I2C_SDA", pin3: "VDD_3V3", pin4: "GND" },
  J_SPI_DISPLAY: {
    pin1: "GND", pin2: "VDD_3V3", pin3: "PB9_SPI_SCK", pin4: "PB8_SPI_MOSI",
    pin5: "PB7_SPI_MISO", pin6: "PB6_SPI_CS", pin7: "PA8_SPI_DC", pin8: "PA9_SPI_RST",
  },
}
for (const [componentName, pins] of Object.entries(expectedConnectorNets)) {
  assert(componentByName.get(componentName)?.ftype === "simple_connector", `${componentName} is not a connector`)
  for (const [pin, net] of Object.entries(pins)) assertPortNet(componentName, pin, net)
}

for (const contact of ["A6", "B6", "A7", "B7"]) {
  assert(Boolean(sourcePort("J_USB_C", contact)), `J_USB_C is missing ${contact}`)
}
assertPortNet("U_USB_UART", "VCC", "VDD_3V3")
assertPortNet("U_USB_UART", "V3", "VDD_3V3")
assertPortNet("R_UART_TX", "pin2", "PA11_UART_RX")
assertPortNet("R_UART_RX", "pin1", "PA10_UART_TX")

const mountingHoles = elements("pcb_hole").filter(
  (hole) => hole.pcb_component_id === null && Math.abs(hole.hole_diameter - 2.7) < 0.001,
)
const fiducials = elements("pcb_smtpad").filter(
  (pad) => pad.pcb_component_id === null && pad.shape === "circle" && pad.radius === 0.5,
)
assert(mountingHoles.length === 4, `Expected four M2.5 mounting holes, found ${mountingHoles.length}`)
assert(fiducials.length === 3, `Expected three SMT fiducials, found ${fiducials.length}`)
for (const [x, y] of [[-42, 8.3], [-42, -8.3], [35.5, 8.3], [26.75, -8.3]]) {
  assert(
    mountingHoles.some((hole) => approximately(hole.x, x) && approximately(hole.y, y)),
    `Missing M2.5 mounting hole at (${x}, ${y}) mm`,
  )
}
for (const hole of mountingHoles) {
  const edgeClearance = Math.min(
    pcbBoard.width / 2 - Math.abs(hole.x),
    pcbBoard.height / 2 - Math.abs(hole.y),
  ) - hole.hole_diameter / 2
  assert(edgeClearance >= 0.8, `${hole.pcb_hole_id} has only ${edgeClearance.toFixed(3)} mm edge clearance`)
}

const silk = elements("pcb_silkscreen_text").map((text) => text.text)
for (const requiredText of ["19 3V3", "3 3V3", "JST P1:G 2:3V3 3:SDA 4:SCL", "GROVE P1:SCL 2:SDA 3:3V3 4:G", "RGB R:PB2 G:PB3 B:PB14"]) {
  assert(silk.includes(requiredText), `Required silkscreen label is missing: ${requiredText}`)
}
assert(silk.some((text) => text.startsWith("SPI P1:G 2:3V3")), "SPI pinout silkscreen is missing")
assert(!source.includes("PA7_USER_LED"), "Stale PA7 white-LED net name remains")
assert(!source.includes("D_USER_WHITE"), "Stale white-LED component remains")

assert(!sourceComponents.some((component) => component.ftype === "simple_crystal"), "A crystal is present; CH340C should use its internal oscillator")
assert(!/<pcbtrace\b/i.test(source), "Manual <pcbtrace> routing is present")
assert(!/<via\b/i.test(source), "Manual <via> placement is present")
assert(!/<tracehint\b/i.test(source), "Manual <tracehint> routing is present")
assert(!/\bpcbPath\s*=/.test(source), "Manual pcbPath routing is present")
assert((source.match(/<differentialpair\b/g) ?? []).length === 1, "Expected one explicit protected USB differential pair")

const pasteLayers = [...new Set(elements("pcb_solder_paste").map((paste) => paste.layer))]
assert(pasteLayers.length === 1 && pasteLayers[0] === "top", `Unexpected solder-paste layers: ${pasteLayers.join(", ")}`)
assert(!circuit.some((element) => ["inner1", "inner2", "inner3", "inner4"].includes(element.layer)), "Inner-layer PCB elements are present")

const embeddedErrors = circuit.filter((element) => element.type.endsWith("_error"))
assert(embeddedErrors.length === 0, `Circuit JSON contains ${embeddedErrors.length} embedded errors`)
assert(
  elements("schematic_element_outside_sheet_warning").length === 0,
  "One or more schematic elements extend outside the sheet",
)
assert(
  !elements("schematic_component_styling_warning").some(
    (warning) => warning.styling_issue_type === "missing_schematic_sheet",
  ),
  "The circuit reports a missing schematic sheet",
)
const allowedWarnings = new Set([
  "schematic_component_styling_warning",
  "supplier_footprint_mismatch_warning",
  "source_part_not_found_warning",
])
const unexpectedWarnings = circuit.filter(
  (element) => element.type.endsWith("_warning") && !allowedWarnings.has(element.type),
)
assert(unexpectedWarnings.length === 0, `Circuit JSON contains unexpected warnings: ${unexpectedWarnings.map((warning) => warning.type).join(", ")}`)
const footprintWarnings = elements("supplier_footprint_mismatch_warning")
const ch340FootprintWarnings = footprintWarnings.filter((warning) => warning.message.includes("jlcpcb:C84681"))
assert(
  footprintWarnings.length === 1 && ch340FootprintWarnings.length === 1,
  "Unexpected supplier-footprint warning set",
)
const supplierFetchWarnings = elements("source_part_not_found_warning")

console.log(JSON.stringify({
  checks: Object.fromEntries(Object.entries(checkResults).map(([name, results]) => [name, results.length])),
  components: sourceComponents.length,
  courtyards: courtyardComponentIds.size,
  pcbTraces: pcbTraces.length,
  throughVias: vias.length,
  mountingHoles: mountingHoles.length,
  fiducials: fiducials.length,
  mechanical: {
    overallBoardBoundsMm: [pcbBoard?.width, pcbBoard?.height],
    uniformPicoWidthMm: boardHalfHeight * 2,
    headerRowSpacingMm: rounded(headerRowSpacing),
    headerPitchMm: 2.54,
    edgeOverhangMm: rounded(edgeOverhang),
    adjacentHoleCenterToBoardEdgeMm: rounded(adjacentHoleCenterClearance),
    nominalJumperBodyPlanOverlapMm: rounded(Math.max(0, -adjacentJumperBodyClearance)),
    boardBeyondEndPinJumperHousingMm: rounded(lastHeaderHousingClearance),
    headerPadToBoardEdgeMm: rounded(headerPadEdgeClearance),
    immediatelyAdjacentBreadboardHoleCentersOutsideBoard: true,
  },
  pasteLayers,
  schematic: {
    sheet: mainSchematicSheet?.display_name,
    size: mainSchematicSheet?.sheet_size,
    components: schematicComponents.length,
    traces: schematicTraces.length,
    sections: 8,
  },
  usb: {
    pathsMm: Object.fromEntries(Object.entries(usbPaths).map(([name, value]) => [name, rounded(value)])),
    skewMm: { A: rounded(usbSkew.A), B: rounded(usbSkew.B), protected: rounded(protectedSkew) },
    allTopLayerAndViaFree: usbTraceNames.every((name) => criticalStats[name].vias === 0),
  },
  vcore: { lengthMm: rounded(vcoreStats.length), vias: vcoreStats.vias },
  switches: "two terminal, distinct nets, active-high BOOT and active-low RESET",
  rgbDebugLed: "common cathode; PB2 red, PB3 green, PB14 blue; active-high through 330Ω",
  warningsReviewed: {
    exactFootprintComparison: ch340FootprintWarnings.map((warning) => warning.message),
    transientSupplierFetchWarnings: supplierFetchWarnings.length,
  },
  failures,
}, null, 2))

if (failures.length > 0) process.exitCode = 1