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
simulation/cli.ts
import { readFile, readdir } from "node:fs/promises"
import { resolve, dirname, join } from "node:path"
import { buildCoverage, exportContext, requireQualifiedCoverage } from "./context-coverage"
import { planCoupled } from "./plan"
import { sha256, writeJson } from "./shared"
import { createSolver } from "./solver-cache"
import { runSmoke } from "./smoke"
const [mode, input, outputArgument, ...args] = process.argv.slice(2), output = resolve(outputArgument ?? ".simulation/results")
try {
if (["inventory","plan","board"].includes(mode)) {
if (!input) throw Error("Supply an independently rendered physical Circuit JSON file")
const records = JSON.parse(await readFile(input, "utf8")), platingMm = Number(process.env.SIM_PLATING_MM)
if (!(platingMm>0)) throw Error("Declare the plating scenario explicitly, e.g. SIM_PLATING_MM=0.025; this is not fabrication confirmation")
const coverage = buildCoverage(records, platingMm), intermediate = exportContext(records, coverage)
await writeJson(`${output}/coverage.json`, coverage); await writeJson(`${output}/native-context.json`, intermediate)
if (mode === "board") requireQualifiedCoverage(coverage) // Runs before binary/resource setup; cannot be promoted by edited metadata.
if (mode === "plan") {
const [radius, ...seeds] = args
if (!seeds.length) throw Error("plan requires radius-mm and one or more native pcb_trace IDs")
await writeJson(`${output}/plan.json`, planCoupled(records, seeds, Number(radius)))
}
console.log(JSON.stringify({ objects: intermediate.objects.length, sourceHash: coverage.physicalRecordsSha256, solverReady: false }))
} else if (mode === "smoke") {
const binary = process.env.FASTER_CAP_BIN
if (!binary) throw Error("Set FASTER_CAP_BIN to an existing FasterCap executable")
const directory = dirname(new URL(import.meta.url).pathname), sources: Record<string,string> = {}
for (const name of (await readdir(directory)).filter(n => n.endsWith(".ts")).sort()) sources[name] = sha256(await readFile(join(directory,name)))
const fingerprint = sha256(JSON.stringify({ sources, runtime: process.versions, platform: process.platform, architecture: process.arch }))
const solver = createSolver({ root: output, binaries: { fastercap: resolve(binary), fasthenry: "unused", ngspice: "unused" }, fingerprint, timeoutSeconds: 120 })
console.log(JSON.stringify(await runSmoke(solver, output)))
} else throw Error("Commands: inventory INPUT OUTPUT | plan INPUT OUTPUT RADIUS TRACE_ID... | board INPUT OUTPUT | smoke - OUTPUT")
} catch (error) {
await writeJson(`${output}/terminal.json`, { status: "blocked", command: mode, diagnostic: String(error), acceptedBoardRlc: false, acceptedEye: false })
console.error(String(error)); process.exitCode = 1
}