AnasSarkiz/muse-voice-remote

Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.

Version
1.3.2
License
unset
Stars
0

tests/design.test.ts

import { test } from "node:test"
import assert from "node:assert/strict"
import { readFileSync } from "node:fs"
import type { AnyCircuitElement } from "circuit-json"
import { createHash } from "node:crypto"
import { parts } from "../design/parts"
import { catalogFor } from "../design/catalog"
import copper from "../design/routed-copper.json"
import selection from "../docs/jlcpcb-import-selection.json"
import { validateCatalog } from "../design/validate-catalog"

// Validate the actual tscircuit output, not just input data or a passing fixture.
const json: AnyCircuitElement[] = JSON.parse(readFileSync("dist/circuit.json", "utf8"))
const components = json.filter(e => e.type === "source_component")
const ports = json.filter(e => e.type === "source_port")
const traces = json.filter(e => e.type === "source_trace")
const nets = json.filter(e => e.type === "source_net")
const pcb = json.filter(e => e.type === "pcb_component")
function component(name: string) {
  const found = components.find(c => c.name === name)
  assert.ok(found, `Missing component ${name}`)
  return found
}
function port(ref: string, alias: string) {
  const c = component(ref)
  const found = ports.find(p => p.source_component_id === c.source_component_id &&
    (p.name === alias || p.port_hints?.includes(alias)))
  assert.ok(found, `Missing rendered port ${ref}.${alias}`)
  return found
}
function netAt(ref: string, alias: string) {
  const p = port(ref, alias)
  const c = component(ref)
  const ids = new Set([p.source_port_id])
  // Repeated physical ground/supply pads are internally joined by tscircuit.
  for (const group of c.internally_connected_source_port_ids ?? [])
    if (group.includes(p.source_port_id)) group.forEach(id => ids.add(id))
  const names = traces.filter(t => t.connected_source_port_ids.some(id => ids.has(id)))
    .flatMap(t => t.connected_source_net_ids ?? [])
    .map(id => nets.find(n => n.source_net_id === id)?.name)
  return [...new Set(names)].sort()
}
function expectNet(ref: string, alias: string, name: string) { assert.deepEqual(netAt(ref,alias),[name],`${ref}.${alias}`) }

test("rendered board has exact PCB dimensions, thickness and top-only component assembly", () => {
  const b = json.find(e => e.type === "pcb_board")
  assert.ok(b); assert.equal(b.width,66); assert.equal(b.height,48); assert.equal(b.thickness,1)
  assert.equal(pcb.length,155)
  assert.ok(pcb.every(p => p.layer === "top"))
  for (const [ref, x, y] of [["MIC1",-28,21.5],["MIC2",28,21.5],["SW_TALK",0,20.5],
    ["SW_PRIVACY",-29.5,3],["SW_POWER",29.5,-6],["J_USB",0,-19.75]] as const) {
    const c=component(ref);const placed=pcb.find(p=>p.source_component_id===c.source_component_id)
    assert.ok(placed);assert.equal(placed.display_offset_x,x);assert.equal(placed.display_offset_y,y)
  }
})

test("microphones use opposite I2S time slots and exclusively switched power", () => {
  for(const ref of ["MIC1","MIC2"]) {
    expectNet(ref,"VDD","MIC_VDD");expectNet(ref,"BCLK","MIC_BCLK")
    expectNet(ref,"WS","MIC_WS");expectNet(ref,"DATA","MIC_SD");expectNet(ref,"GND","GND")
  }
  expectNet("MIC1","SELECT","GND");expectNet("MIC2","SELECT","MIC_VDD")
})

test("physical privacy switch grounds microphone power and disables every digital path", () => {
  expectNet("SW_PRIVACY","PWR_COM","MIC_VDD");expectNet("SW_PRIVACY","PWR_ON","V3_3")
  expectNet("SW_PRIVACY","PWR_OFF","GND");expectNet("SW_PRIVACY","OE_COM","PRIVACY_N_OE")
  expectNet("SW_PRIVACY","OE_ON","GND");assert.deepEqual(netAt("SW_PRIVACY","OE_OFF"),[])
  for(const ref of ["U_ISO1","U_ISO2","U_ISO3"])expectNet(ref,"N_OE","PRIVACY_N_OE")
  expectNet("U_ISO1","A","MIC_BCLK_HOST");expectNet("U_ISO1","Y","MIC_BCLK")
  expectNet("U_ISO2","A","MIC_WS_HOST");expectNet("U_ISO2","Y","MIC_WS")
  expectNet("U_ISO3","A","MIC_SD");expectNet("U_ISO3","Y","MIC_DATA_HOST")
  expectNet("U1","GPIO15","PRIVACY_SENSE")
  expectNet("R_PRIVACY_SENSE","pin1","PRIVACY_N_OE");expectNet("R_PRIVACY_SENSE","pin2","PRIVACY_SENSE")
  // Static hardware isolation analysis, not a physical timing/leakage test.
  const worstOeIfSenseGpioDrivesLow=3.3*100_000/(100_000+10_000)
  assert.ok(worstOeIfSenseGpioDrivesLow > 0.7*3.3)
})

test("native USB uses correct ESP32-S3 pins and independent CC pull-downs", () => {
  expectNet("U1","GPIO19","USB_DM_MCU");expectNet("U1","GPIO20","USB_DP_MCU")
  expectNet("J_USB","CC1","USB_CC1");expectNet("J_USB","CC2","USB_CC2")
  expectNet("R_CC1","pin1","USB_CC1");expectNet("R_CC1","pin2","GND")
  expectNet("R_CC2","pin1","USB_CC2");expectNet("R_CC2","pin2","GND")
  expectNet("J_USB","DP_A6","USB_DP");expectNet("J_USB","DP_B6","USB_DP")
  expectNet("J_USB","DM_A7","USB_DM");expectNet("J_USB","DM_B7","USB_DM")
  for(const pin of [1,2,3,4,13,14])expectNet("J_USB",`pin${pin}`,"GND")
  for(const pin of [15,16])expectNet("J_USB",`pin${pin}`,"USB_VBUS")
})

test("power-path charging and hardware enable do not place the charger behind the off switch", () => {
  expectNet("U_CHARGE","IN","VBUS_FUSED");expectNet("U_CHARGE","BAT","BAT")
  expectNet("U_CHARGE","OUT","SYS");expectNet("U_CHARGE","TS","BAT_NTC")
  expectNet("J_BAT","NTC","BAT_NTC");expectNet("U_CHARGE","N_CE","GND")
  expectNet("U_REG","VIN","SYS");expectNet("U_REG","VOUT","V3_3")
  expectNet("SW_POWER","COM","REG_ENABLE");expectNet("U_REG","EN","REG_ENABLE")
  expectNet("SW_POWER","OFF","GND")
})

test("speaker bridge, haptic flyback and switched battery measurement are wired correctly", () => {
  expectNet("U_AMP","OUTP","SPK_P");expectNet("U_AMP","OUTN","SPK_N")
  expectNet("J_SPK","P","SPK_P");expectNet("J_SPK","N","SPK_N")
  expectNet("U_AMP","VDD","SYS");expectNet("U_AMP","N_SD_MODE","AMP_ENABLE")
  expectNet("Q_MOTOR","S","GND");expectNet("Q_MOTOR","D","MOTOR_LOW")
  expectNet("D_FLYBACK","anode","MOTOR_LOW");expectNet("D_FLYBACK","cathode","MOTOR_3V0")
  expectNet("Q_BAT_SENSE","S","BAT");expectNet("Q_BAT_SENSE","D","BAT_DIV_SUPPLY")
  expectNet("R_BAT_TOP","pin1","BAT_DIV_SUPPLY");expectNet("U1","GPIO38","BAT_SENSE_EN")
  expectNet("U1","GPIO1","BAT_ADC")
})

test("user controls omit approve/reject and the exact panel uses a real stocked connector", () => {
  expectNet("SW_TALK","A","TALK");expectNet("SW_TALK","B","GND")
  assert.ok(!components.some(c=>/approve|reject|encoder/i.test(c.name)))
  assert.equal(component("J_LCD").manufacturer_part_number,"FH12A-50S-0.5SH(55)")
  assert.equal(catalogFor(parts.find(p=>p.name==="J_LCD")!).lcsc,"C202120")
  expectNet("U1","GPIO0","BOOT")
})

test("no source connectivity or current placement rule errors are hidden", () => {
  const errors=json.filter(e=>e.type.endsWith("_error"))
  assert.deepEqual(errors,[],JSON.stringify(errors,null,2))
  assert.ok(traces.length>250)
  assert.equal(json.filter(e=>e.type==="pcb_trace").length,copper.tracks.length)
  assert.ok(copper.tracks.length>500,"The verified native copper must be present in the review")
  assert.ok(json.some(e=>e.type.endsWith("_warning")),"Qualification warnings must be retained")
})

test("published copper planes preserve native clearance holes and the complete ground reference", () => {
  const retained = (copper as typeof copper & {pours?: {
    net:string; layer:string; brep_shape:{outer_ring:{vertices:{x:number;y:number}[]};inner_rings:{vertices:{x:number;y:number}[]}[]}
  }[]}).pours
  assert.ok(retained && retained.length >= 3, "Checked ground and power planes are required")
  const published = json.filter(e => e.type === "pcb_copper_pour")
  assert.equal(published.length,retained.length)
  for (const [i,p] of retained.entries()) {
    assert.equal(published[i].shape,"brep")
    if (published[i].shape !== "brep") throw new Error("Native polygon geometry was replaced")
    assert.deepEqual(published[i].brep_shape,p.brep_shape)
    assert.equal(published[i].layer,p.layer)
    assert.equal(nets.find(n=>n.source_net_id===published[i].source_net_id)?.name,p.net)
    assert.ok(p.brep_shape.outer_ring.vertices.length >= 3)
  }
  const ground=retained.filter(p=>p.net==="GND" && p.layer==="inner1")
  assert.ok(ground.length > 0)
  assert.ok(ground.some(p=>p.brep_shape.inner_rings.length > 0),"Foreign via clearances must remain in the ground geometry")
  assert.ok(copper.tracks.every(t=>t.layer!=="inner1" || t.net==="GND"))
})

test("every populated component imports JLCPCB geometry and has exact live supplier stock",()=>{
  const evidence=JSON.parse(readFileSync("docs/stock-evidence.json","utf8"))
  assert.equal(evidence.all_populated_pcb_parts_have_positive_snapshot,true)
  assert.equal(evidence.unique_pcb_mpns,56)
  const manifest=JSON.parse(readFileSync("vendor/jlcpcb/native-library-manifest.json","utf8"))
  const imports=JSON.parse(readFileSync("vendor/jlcpcb/import-manifest.json","utf8"))
  assert.equal(imports.errors.length,0);assert.equal(imports.imports.length,56)
  for (const part of parts.filter(p=>catalogFor(p))) {
    const selected=catalogFor(part)!
    assert.equal(component(part.name).manufacturer_part_number,selected.mpn)
    assert.deepEqual(component(part.name).supplier_part_numbers?.jlcpcb,[selected.lcsc])
    const entry=manifest.find((e:{library:string})=>e.library===selected.library)
    assert.ok(entry,`${part.name} must import a real footprint`)
    assert.equal(createHash("sha256").update(readFileSync(entry.file)).digest("hex"),entry.sha256)
    const imported=imports.imports.find((e:{lcsc:string})=>e.lcsc===selected.lcsc)
    assert.ok(imported,`${part.name} must use a generated JLCPCB component import`)
    assert.equal(createHash("sha256").update(readFileSync(imported.file)).digest("hex"),imported.sha256)
    assert.equal(createHash("sha256").update(readFileSync(imported.rawFile)).digest("hex"),imported.rawSha256)
    assert.ok(evidence.parts.some((e:{mpn:string;stock:number|null;meta?:{stale?:boolean}})=>e.mpn===selected.mpn &&
      e.stock!==null && e.stock>=evidence.required_quantities[selected.mpn] && !e.meta?.stale),`${selected.mpn} stock evidence`)
  }
})

test("every placed JLCPCB component retains its supplier OBJ and STEP CAD models",()=>{
  const seen = new Set<string>()
  for (const part of parts.filter(p=>catalogFor(p))) {
    const selected = catalogFor(part)!
    const imported = JSON.parse(readFileSync(`vendor/jlcpcb/${selected.lcsc}.circuit.json`,"utf8"))
    const supplied = imported.find((e:{type:string})=>e.type==="cad_component")
    const rendered = json.find(e=>e.type==="cad_component" &&
      e.source_component_id===component(part.name).source_component_id)
    assert.ok(rendered && rendered.type==="cad_component",`${part.name} missing CAD`)
    assert.notEqual(rendered.show_as_bounding_box,true,`${part.name} must use supplier CAD, not a box`)
    for (const key of ["model_obj_url","model_step_url"] as const) {
      assert.ok(rendered[key],`${part.name} missing ${key}`)
      const actual: URL = new URL(rendered[key]!)
      const expected: URL = new URL(supplied[key])
      assert.equal(actual.origin+actual.pathname,expected.origin+expected.pathname)
      assert.equal(actual.searchParams.get("uuid"),expected.searchParams.get("uuid"))
      assert.ok(actual.searchParams.get("uuid"),`${part.name} must retain the supplier model UUID`)
    }
    seen.add(selected.lcsc)
  }
  assert.equal(seen.size,56)
  assert.equal(json.filter(e=>e.type==="cad_component").length,155)
})

test("every passive supplier assignment matches its electrical family and value", () => {
  const audit = validateCatalog(parts, selection)
  assert.equal(audit.checkedComponents, 155)
  assert.deepEqual(audit.failures, [])
  for (const ref of ["C_ANA1", "C_ANA2", "C_ANA3", "C_VDDA1", "C_CPU", "C_SPI1", "C_SPI2", "C_FLASH"]) {
    assert.equal(audit.rows.find(row => row.reference === ref)?.kind, "capacitor")
  }
})

test("supplier audit rejects same-pin-count substitutions, value errors and duplicate assignments", () => {
  const wrongFamily = structuredClone(selection)
  const original = wrongFamily.parts.find(entry => entry.references.includes("C_CPU"))!
  original.references = original.references.filter(ref => ref !== "C_CPU"); original.quantity--
  const resistor = wrongFamily.parts.find(entry => entry.lcsc === "C14675")!
  resistor.references.push("C_CPU"); resistor.quantity++
  assert.ok(validateCatalog(parts, wrongFamily).failures.some(error => /C_CPU: expected capacitor/.test(error)))
  const wrongValue = parts.map(part => part.name === "C_XTAL_P" ? { ...part, value: "220pF" } : part)
  assert.ok(validateCatalog(wrongValue, selection).failures.some(error => /C_XTAL_P: expected 220pF/.test(error)))
  const duplicate = structuredClone(selection)
  duplicate.parts.find(entry => entry.lcsc === "C14675")!.references.push("C_CPU")
  assert.ok(validateCatalog(parts, duplicate).failures.some(error => /C_CPU: expected exactly one/.test(error)))
  const underrated = structuredClone(selection)
  const highVoltage = underrated.parts.find(entry => entry.references.includes("C_BL_OUT"))!
  highVoltage.references = highVoltage.references.filter(ref => ref !== "C_BL_OUT"); highVoltage.quantity--
  const lowVoltage = underrated.parts.find(entry => entry.lcsc === "C6475754")!
  lowVoltage.references.push("C_BL_OUT"); lowVoltage.quantity++
  assert.ok(validateCatalog(parts, underrated).failures.some(error => /C_BL_OUT: capacitor rating 10V is below 50 V/.test(error)))
})

test("imported TALK button terminal pairs and physical ESP32 pins match their datasheets",()=>{
  for(const [ref,net] of [["SW_TALK","TALK"],["SW_BOOT","BOOT"],["SW_RESET","RESET"]]) {
    for(const pin of [1,4])expectNet(ref,`pin${pin}`,net)
    for(const pin of [2,3])expectNet(ref,`pin${pin}`,"GND")
  }
  expectNet("U1","pin25","USB_DM_MCU");expectNet("U1","pin26","USB_DP_MCU")
  expectNet("U1","pin5","BOOT");expectNet("U1","pin57","GND")
})

test("manufacturer LCD pinout uses serial-II straps and isolated 2.8 V power/signals",()=>{
  expectNet("J_LCD","pin6","GND")
  for(const pin of [7,8,9,40,41,42])expectNet("J_LCD",`pin${pin}`,"LCD_2V8")
  for(const [pin,signal] of [[10,"RESET"],[34,"MOSI"],[36,"DC"],[37,"SCK"],[38,"CS"]] as const)
    expectNet("J_LCD",`pin${pin}`,`LCD_${signal}_2V8`)
  for(const pin of [43,48,49,50])expectNet("J_LCD",`pin${pin}`,"GND")
  for(const pin of [33,39,44,45,46,47])assert.deepEqual(netAt("J_LCD",`pin${pin}`),[])
  expectNet("U_LCD_POWER","pin1","V3_3");expectNet("U_LCD_POWER","pin5","LCD_2V8")
  for(const [i,signal] of ["MOSI","SCK","CS","DC","RESET"].entries()){
    expectNet(`U_LCD_BUF${i+1}`,"VCC","LCD_2V8")
    expectNet(`U_LCD_BUF${i+1}`,"N_OE","GND")
    expectNet(`U_LCD_BUF${i+1}`,"A",`LCD_${signal}`)
    expectNet(`U_LCD_BUF${i+1}`,"Y",`LCD_${signal}_2V8`)
  }
})

test("four backlight anodes have ballast and a current driver separate from hard-off",()=>{
  for(let i=1;i<=4;i++){
    expectNet("J_LCD",`pin${i+1}`,`LCD_LEDA${i}`)
    expectNet(`R_BL_BALANCE${i}`,"pin1","BL_ANODE_SUPPLY")
    expectNet(`R_BL_BALANCE${i}`,"pin2",`LCD_LEDA${i}`)
  }
  expectNet("J_LCD","pin1","BL_SENSE")
  expectNet("Q_BL_OFF","pin3","BL_INPUT");expectNet("Q_BL_OFF","pin2","V3_3")
  expectNet("Q_BL_DRIVE","C","BL_ENABLE_GATE");expectNet("Q_BL_DRIVE","E","GND")
  // Physical TPS61169 pin 3 is FB and pin 4 is CTRL, per TI p.3.
  expectNet("U_BACKLIGHT","pin3","BL_SENSE");expectNet("U_BACKLIGHT","pin4","LCD_BL_PWM")
  expectNet("U_BACKLIGHT","pin5","BL_INPUT")
  expectNet("R_BL_FB","pin1","BL_SENSE");expectNet("R_BL_FB","pin2","GND")
  expectNet("D_BL","anode","BL_SW");expectNet("D_BL","cathode","BL_ANODE_SUPPLY")
  expectNet("U1","GPIO48","LCD_BL_PWM");expectNet("U1","MTMS","LCD_BL_ENABLE")
  assert.ok(0.220/(5.1*0.99)<0.080,"Worst static feedback tolerance stays below the panel's 80 mA array maximum")
})

test("native copper is bound to the current placement/wiring and a clean independent DRC",()=>{
  assert.equal(createHash("sha256").update(readFileSync("docs/routing-input.json")).digest("hex"),copper.input_sha256)
  assert.equal(createHash("sha256").update(readFileSync("hardware/MuseVoiceRemote.kicad_pcb")).digest("hex"),copper.cad_sha256)
  assert.ok(copper.ground_planes.some(z=>z.net==="GND" && z.layer==="inner1" && z.filled))
  assert.ok(copper.tracks.every(t=>t.layer!=="inner1" || t.net==="GND"),"All of Layer 2 is reserved for ground")
  assert.ok(copper.tracks.filter(t=>["RF_LNA","RF_ANT"].includes(t.net)).every(t=>t.layer==="top"))
  assert.ok(!copper.vias.some(v=>["RF_LNA","RF_ANT"].includes(v.net)))
  const report=readFileSync("hardware/drc-report.txt","utf8")
  assert.match(report,/Found 0 DRC violations/);assert.match(report,/Found 0 unconnected pads/)
  assert.match(report,/Found 0 Footprint errors/)
})


test("bare ESP32-S3R8 has compatible flash, clock, RF and power connections",()=>{
  assert.equal(component("U1").manufacturer_part_number,"ESP32-S3R8")
  assert.ok(components.every(c=>!String(c.manufacturer_part_number).includes("WROOM")))
  expectNet("U1","pin47","MIC_WS_HOST");expectNet("U1","MTDI","MIC_WS_HOST")
  expectNet("U1","pin14","STATUS_B");expectNet("U1","GPIO9","STATUS_B")
  expectNet("U1","pin11","TALK");expectNet("U1","GPIO6","TALK")
  expectNet("U1","pin12","USB_EN1");expectNet("U1","pin50","USB_EN2")
  assert.deepEqual(netAt("U1","pin49"),[])
  assert.equal(component("U_FLASH").manufacturer_part_number,"W25Q64JVSSIQ")
  for(const pin of [2,3])expectNet("U1",`pin${pin}`,"RF_3V3")
  for(const pin of [20,46,55,56])expectNet("U1",`pin${pin}`,"V3_3")
  expectNet("U1","pin29","VDD_SPI_3V3");expectNet("U_FLASH","pin8","VDD_SPI_3V3")
  expectNet("U_FLASH","pin4","GND");expectNet("U1","pin4","RESET")
  for(const [signal,mcu,flash] of [["HD",30,7],["WP",31,3],["CS",32,1],["CLK",33,6],["Q",34,2],["D",35,5]] as const){
    expectNet("U1",`pin${mcu}`,`FLASH_${signal}_HOST`)
    expectNet(`R_FLASH_${signal}`,"pin1",`FLASH_${signal}_HOST`)
    expectNet(`R_FLASH_${signal}`,"pin2",`FLASH_${signal}`)
    expectNet("U_FLASH",`pin${flash}`,`FLASH_${signal}`)
  }
  for(const pin of [28,38,39,40,41,42])assert.deepEqual(netAt("U1",`pin${pin}`),[])
  expectNet("U1","pin51","STRAP_VDD_SPI");expectNet("R_STRAP45","pin2","GND")
  expectNet("U1","pin52","BOOT_IO46");expectNet("R_STRAP46","pin2","GND")
  expectNet("U1","pin54","XTAL_P_CHIP");expectNet("L_XTAL","pin1","XTAL_P_CHIP")
  expectNet("L_XTAL","pin2","XTAL_P");expectNet("Y1","pin1","XTAL_P")
  expectNet("U1","pin53","XTAL_N");expectNet("Y1","pin3","XTAL_N")
  for(const pin of [2,4])expectNet("Y1",`pin${pin}`,"GND")
  expectNet("U1","pin1","RF_LNA");expectNet("L_RF_MATCH","pin2","RF_LNA")
  expectNet("L_RF_MATCH","pin1","RF_ANT");expectNet("J_RF","pin2","RF_ANT")
  for(const pin of [1,3])expectNet("J_RF",`pin${pin}`,"GND")
  expectNet("D_RF_ESD","pin1","RF_ANT");expectNet("D_RF_ESD","pin2","GND")
  const u1=pcb.find(p=>p.source_component_id===component("U1").source_component_id)!
  const thermal=json.filter(e=>e.type==="pcb_plated_hole" && e.pcb_component_id===u1.pcb_component_id)
  assert.equal(thermal.length,9,"Supplier's nine exposed-pad thermal holes must be retained")
  for(const hole of thermal){
    assert.ok(hole.type==="pcb_plated_hole" && hole.shape==="circle")
    assert.ok(Math.abs(hole.hole_diameter-0.3048)<0.000001)
    assert.ok(Math.abs(hole.outer_diameter-0.6096)<0.000001)
  }
})


test("reset bias prevents USB overdraw, backlight enabling and haptic motion from weak pin pulls",()=>{
  const value=(ref:string)=>{
    const raw=parts.find(p=>p.name===ref)!.value
    return Number.parseFloat(raw)*(raw.endsWith("k")?1000:1)
  }
  for(const [ref,net] of [["R_USB_EN1_PD","USB_EN1"],["R_USB_EN2_PD","USB_EN2"],["R_BL_PWM_PD","LCD_BL_PWM"]]){
    expectNet(ref,"pin1",net);expectNet(ref,"pin2","GND")
    const maximumResetLevel=3.4*value(ref)/(30_000+value(ref))
    assert.ok(maximumResetLevel<.3,`${ref} must override a 30 kohm boot pull-up`)
  }
  expectNet("U_CHARGE","EN1","USB_EN1");expectNet("U_CHARGE","EN2","USB_EN2")
  expectNet("U1","GPIO14","AMP_ENABLE_HOST")
  expectNet("R_AMP_PD","pin1","AMP_ENABLE_HOST")
  expectNet("R_AMP_CONTROL","pin1","AMP_ENABLE_HOST");expectNet("R_AMP_CONTROL","pin2","AMP_ENABLE")
  const seriesMin=value("R_AMP_CONTROL")*.99,seriesMax=value("R_AMP_CONTROL")*1.01
  const ampLowLeakage=1e-6*((seriesMax+value("R_AMP_PD")*1.01)*108_000/(seriesMax+value("R_AMP_PD")*1.01+108_000))+1e-6*value("R_AMP_PD")*1.01
  assert.ok(ampLowLeakage<.08,"GPIO14 input leakage and conservative SD_MODE leakage must remain below minimum shutdown threshold")
  const ampMinimumHigh=.8*(3.3*(1-.015))*92_000/(seriesMax+92_000)
  const ampMaximumHigh=(3.3*(1+.015))*108_000/(seriesMin+108_000)
  assert.ok(ampMinimumHigh>1.5,"Enabled SD_MODE must select left channel above maximum B2 threshold")
  assert.ok(ampMaximumHigh<2.5+.3,"SD_MODE must remain within its supply-referenced absolute maximum at minimum amplifier supply")
  const motorResetLevel=3.4*value("R_MOTOR_PD")/(30_000+value("R_MOTOR_GATE")+value("R_MOTOR_PD"))
  assert.ok(motorResetLevel<.3)
  const minimumGateHigh=0.8*(3.3*(1-.015))*value("R_MOTOR_PD")/(value("R_MOTOR_GATE")+value("R_MOTOR_PD"))
  assert.ok(minimumGateHigh>2.5,"Minimum specified GPIO high voltage must retain the MOSFET's 2.5 V conduction guarantee")
  const baseResetLevel=3.4*value("R_BL_BASE_PD")/(30_000+value("R_BL_GATE")+value("R_BL_BASE_PD"))
  assert.ok(baseResetLevel<.3)
})

test("memory uses the externally driven 3.3 V option and motor has its own regulated rail",()=>{
  expectNet("R_VDD_SPI_EXT","pin1","V3_3");expectNet("R_VDD_SPI_EXT","pin2","VDD_SPI_3V3")
  assert.equal(parts.find(p=>p.name==="R_VDD_SPI_EXT")!.value,"0")
  expectNet("C_RF_BULK","pin1","RF_3V3")
  expectNet("U_MOTOR_POWER","IN","V3_3");expectNet("U_MOTOR_POWER","OUT","MOTOR_3V0")
  expectNet("J_MOTOR","P","MOTOR_3V0");expectNet("D_FLYBACK","cathode","MOTOR_3V0")
})


test("published vias and checked native rules enforce 0.30 mm holes and 0.45 mm pads",()=>{
  const vias=json.filter(e=>e.type==="pcb_via")
  const profile=JSON.parse(readFileSync("design/fabrication-profile.json","utf8"))
  const project=JSON.parse(readFileSync("hardware/MuseVoiceRemote.kicad_pro","utf8"))
  const proof=JSON.parse(readFileSync("docs/final-via-size-audit.json","utf8"))
  assert.equal(profile.minimumViaHoleDiameter,0.3)
  assert.equal(profile.minimumViaPadDiameter,0.45)
  assert.equal(proof.board_sha256,createHash("sha256").update(readFileSync("hardware/MuseVoiceRemote.kicad_pcb")).digest("hex"))
  assert.equal(proof.passed,true)
  assert.equal(vias.length,proof.routing_via_count)
  assert.ok(vias.every(v=>v.hole_diameter>=0.3 && v.outer_diameter>=0.45 && (v.outer_diameter-v.hole_diameter)/2>=0.075-1e-7))
  assert.equal(project.board.design_settings.rules.min_through_hole_diameter,0.3)
  assert.equal(project.board.design_settings.rules.min_via_diameter,0.45)
  assert.equal(project.board.design_settings.rules.min_via_annular_width,0.075)
  assert.equal(project.board.design_settings.drc_exclusions.length,0)
  assert.ok(proof.imported_mcu_thermal_holes.every((v:{drill_mm:number;pad_diameter_mm:number})=>v.drill_mm>=0.3 && v.pad_diameter_mm>=0.45))
})