AnasSarkiz/usb-c-pd-brushed-motor
USB-C PD-powered motor controller with protected input, selectable 5/9/12 V buck supply, MCU qualification, PWM H-bridge drive, overvoltage sensing, regenerative energy-dump resistors, and safety interlocks.
- Version
- 0.0.1-a48-cloud-pipeline9-unrouted-c41d79a-305b1e7a
- License
- unset
- Stars
- 0
scripts/audit-dailywell-import.ts
import { readFile, writeFile } from "node:fs/promises"
import { createHash } from "node:crypto"
import {
any_circuit_element,
pcb_solder_paste,
type AnyCircuitElement,
} from "circuit-json"
import { z } from "zod"
const supplierCode = z.enum(["C908270", "C908281"]).parse(process.argv[2])
const revision = z.enum(["A4", "A5", "A6"]).parse(process.argv[3] ?? "A4")
const probeSlug =
supplierCode === "C908270"
? "dailywell-1m-import-probe"
: "dailywell-2m-import-probe"
const failures: string[] = []
const expectedManufacturerPartNumber =
supplierCode === "C908270" ? "1MS3T1B1M2QES-5" : "2MS3T1B1M1QES-5"
const importedSourceSha256 = createHash("sha256")
.update(
await readFile(
`imports/A_${expectedManufacturerPartNumber.replace(/-/g, "_")}.tsx`,
),
)
.digest("hex")
const circuitJson: AnyCircuitElement[] = []
const invalidElements = []
const rawElements = z
.array(z.unknown())
.parse(
JSON.parse(await readFile(`dist/tests/${probeSlug}/circuit.json`, "utf8")),
)
for (const [elementIndex, rawElement] of rawElements.entries()) {
const result = any_circuit_element.safeParse(rawElement)
if (result.success) {
circuitJson.push(result.data)
continue
}
const header = z.object({ type: z.string() }).parse(rawElement)
const specific =
header.type === "pcb_solder_paste"
? pcb_solder_paste.safeParse(rawElement)
: result
failures.push(
`Element ${elementIndex} ${header.type}: circuit schema rejects generated element`,
)
invalidElements.push({
elementIndex,
rawElement,
issues: specific.success ? [] : specific.error.issues,
})
}
const sourceComponent = circuitJson.find(
(element) => element.type === "source_component" && element.name === "SW1",
)
const pinReports = []
const probeSheet = circuitJson.find(
(element) => element.type === "schematic_sheet" && element.name === "probe",
)
if (probeSheet?.type !== "schematic_sheet" || probeSheet.sheet_size !== "a4")
failures.push("Import probe lacks its required native A4 sheet")
if (!sourceComponent || sourceComponent.type !== "source_component") {
failures.push("Supplier switch source component missing")
} else {
const sourcePorts = circuitJson.filter(
(element) =>
element.type === "source_port" &&
element.source_component_id === sourceComponent.source_component_id,
)
if (sourcePorts.length !== 3)
failures.push("Expected exactly three electrical source ports")
const schematicComponent = circuitJson.find(
(element) =>
element.type === "schematic_component" &&
element.source_component_id === sourceComponent.source_component_id,
)
const supplierBox =
sourceComponent.ftype === "simple_chip" &&
sourceComponent.manufacturer_part_number ===
expectedManufacturerPartNumber &&
sourceComponent.supplier_part_numbers?.jlcpcb?.includes(supplierCode) &&
schematicComponent?.type === "schematic_component" &&
!schematicComponent.symbol_name
if (
schematicComponent?.type !== "schematic_component" ||
probeSheet?.type !== "schematic_sheet" ||
schematicComponent.schematic_sheet_id !== probeSheet.schematic_sheet_id
)
failures.push("Supplier component is not rendered on the reviewed A4 sheet")
if (
!supplierBox &&
(schematicComponent?.type !== "schematic_component" ||
schematicComponent.symbol_name !== "spdt_switch_right")
) {
failures.push(
"Generated symbol does not represent SPDT center-off or its common pin 2",
)
}
for (const pinNumber of [1, 2, 3]) {
const sourcePort = sourcePorts.find(
(element) =>
element.type === "source_port" && element.pin_number === pinNumber,
)
if (!sourcePort || sourcePort.type !== "source_port") {
failures.push(`Electrical pin ${pinNumber}: source port missing`)
continue
}
const schematicPort = circuitJson.find(
(element) =>
element.type === "schematic_port" &&
element.source_port_id === sourcePort.source_port_id,
)
if (!schematicPort)
failures.push(`Electrical pin ${pinNumber}: schematic port missing`)
if (
schematicPort?.type === "schematic_port" &&
schematicPort.pin_number !== undefined &&
schematicPort.pin_number !== pinNumber
)
failures.push(
`Electrical pin ${pinNumber}: schematic numbering disagrees with supplier source pin`,
)
const expectedNetName =
pinNumber === 1 ? "IN1" : pinNumber === 2 ? "PWM" : "IN2"
const expectedNet = circuitJson.find(
(element) =>
element.type === "source_net" && element.name === expectedNetName,
)
const sourceTrace = circuitJson.find(
(element) =>
element.type === "source_trace" &&
element.connected_source_port_ids.includes(sourcePort.source_port_id),
)
if (
expectedNet?.type !== "source_net" ||
sourceTrace?.type !== "source_trace" ||
!sourceTrace.connected_source_net_ids.includes(
expectedNet.source_net_id,
) ||
sourceTrace.connected_source_port_ids.length !== 1 ||
sourceTrace.connected_source_net_ids.length !== 1
)
failures.push(
`Electrical pin ${pinNumber}: expected isolated ${expectedNetName} association missing or shorted`,
)
if (
schematicComponent?.type === "schematic_component" &&
schematicComponent.symbol_name === "spdt_switch_right" &&
pinNumber === 2 &&
schematicPort?.type === "schematic_port" &&
schematicPort.facing_direction !== "left"
)
failures.push(
"Physical common pin 2 is drawn as a throw instead of the moving common contact",
)
const pcbPort = circuitJson.find(
(element) =>
element.type === "pcb_port" &&
element.source_port_id === sourcePort.source_port_id,
)
const platedHole =
pcbPort?.type === "pcb_port"
? circuitJson.find(
(element) =>
element.type === "pcb_plated_hole" &&
element.pcb_port_id === pcbPort.pcb_port_id,
)
: undefined
if (!platedHole)
failures.push(`Electrical pin ${pinNumber}: physical pad missing`)
pinReports.push({
pinNumber,
sourcePort,
schematicPort,
pcbPort,
platedHole,
})
}
}
const warnings = circuitJson.filter((element) =>
/warning|error/.test(element.type),
)
const reviewedWarnings =
revision === "A6"
? z
.array(
z.object({
supplierCode: z.string(),
importedSourceSha256: z.string(),
type: z.string(),
message: z.string(),
source_component_id: z.string(),
reason: z.string(),
evidence: z.array(z.string()),
}),
)
.parse(
JSON.parse(
await readFile("evidence/dailywell-warning-review-A6.json", "utf8"),
),
)
: []
const acceptedWarnings = []
const unresolvedWarnings = []
for (const warning of warnings) {
const reviewed = reviewedWarnings.find(
(entry) =>
entry.supplierCode === supplierCode &&
entry.importedSourceSha256 === importedSourceSha256 &&
entry.type === warning.type &&
"message" in warning &&
entry.message === warning.message &&
"source_component_id" in warning &&
entry.source_component_id === warning.source_component_id,
)
if (reviewed) acceptedWarnings.push({ warning, review: reviewed })
else unresolvedWarnings.push(warning)
}
if (unresolvedWarnings.length !== 0)
failures.push(
`${unresolvedWarnings.length} unsuppressed generated diagnostic entries require resolution`,
)
const pcbTraceCount = circuitJson.filter(
(element) => element.type === "pcb_trace",
).length
if (pcbTraceCount !== 0)
failures.push("Routing unexpectedly present in import probe")
const report = {
revision,
supplierCode,
approved: failures.length === 0,
auditScope:
"Supplier identity, electrical pin coverage/numbering, common-2 PWM net association, generated schema and reviewed diagnostics. Mechanical assembly/stencil qualification is separate.",
failures,
invalidElements,
pinReports,
warnings,
acceptedWarnings,
unresolvedWarnings,
importedSourceSha256,
manufacturerContacts: {
commonPin: 2,
endPositions: [
[2, 3],
[2, 1],
],
center: "open",
},
pcbTraceCount,
physicalFitApproval:
"Separate manufacturer mechanical review is mandatory; not inferred from this electrical/schema audit",
}
await writeFile(
`evidence/${supplierCode}-strict-audit-${revision}.json`,
`${JSON.stringify(report, null, 2)}\n`,
)
console.log(JSON.stringify({ supplierCode, failures, pcbTraceCount }, null, 2))
if (failures.length !== 0) process.exitCode = 1