shibosoftwaredev/f1c100s-linux-nema17-stepper-controller
A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.
- Version
- 0.4.56
- License
- unset
- Stars
- 0
scripts/prepare-round3-publication.mjs
import fs from "node:fs"
import path from "node:path"
import crypto from "node:crypto"
import assert from "node:assert/strict"
const source=process.cwd(),read=p=>JSON.parse(fs.readFileSync(p,"utf8"))
const sha=b=>crypto.createHash("sha256").update(b).digest("hex")
const status=read("reports/round3-fix-status.json"),previous=read("reports/round3-prepush-remote.json")
const version="0.4.48-review-fixes-20261019"
assert.equal(read("package.json").version,"0.4.48")
assert.equal(previous.latestVersion,"0.4.47-review-fixes-20261019")
assert.equal(sha(fs.readFileSync("dist/index/circuit.json")),status.circuitSha256)
assert.equal(status.checks.nativeErrors,0);assert.equal(status.fixed.independentDrillViolations.after,0)
assert.equal(status.fabricationReady,false)
async function request(endpoint,body){
const r=await fetch("https://registry-api.tscircuit.com/"+endpoint,{method:body?"POST":"GET",
headers:body?{"content-type":"application/json"}:undefined,body:body?JSON.stringify(body):undefined,signal:AbortSignal.timeout(45000)})
assert.ok(r.ok,`${endpoint.split("?")[0]} HTTP ${r.status}`);return r.json()
}
const pkg=(await request("packages/get",{name:previous.name})).package
assert.equal(pkg.latest_package_release_id,previous.latestReleaseId,"stop for a concurrent unrelated update")
const listing=(await request("package_files/list?"+new URLSearchParams({package_release_id:previous.latestReleaseId}))).package_files
const entry=listing.find(f=>f.file_path==="dist/index/circuit.json");assert.ok(entry)
const remote=(await request("package_files/get?"+new URLSearchParams({package_file_id:entry.package_file_id}))).package_file
const bytes=remote.content_text!=null?Buffer.from(remote.content_text):Buffer.from(remote.content_base64,"base64")
const baseline=read("../../checkpoints/nema17-round3-20261019-Nfouf4/restore-verified/dist/index/circuit.json")
const types=new Set(["pcb_board","pcb_component","pcb_port","pcb_smtpad","pcb_plated_hole","pcb_hole","pcb_trace","pcb_via","pcb_copper_pour","pcb_keepout","source_component","source_port","source_trace","source_net","source_component_internal_connection"])
const normalize=v=>JSON.stringify(v,(_,x)=>typeof x==="number"?Math.round(x*1e8)/1e8:x&&typeof x==="object"&&!Array.isArray(x)?Object.fromEntries(Object.entries(x).sort(([a],[b])=>a.localeCompare(b))):x)
const critical=c=>c.filter(e=>types.has(e.type)).map(normalize).sort()
assert.deepEqual(critical(JSON.parse(bytes)),critical(baseline),"live previous release equals the actual pre-work baseline")
fs.writeFileSync("reports/round3-live-baseline-comparison.json",JSON.stringify({checkedAt:new Date().toISOString(),previous,
publishedCircuitSha256:sha(bytes),livePublishedCriticalRecordsMatchPreWorkBaseline:true,
auditedNewCircuitSha256:status.circuitSha256,improvement:status.fixed,regressionsAdded:0,fabricationReady:false},null,2)+"\n")
const root=path.resolve("../../publish-staging");fs.mkdirSync(root,{recursive:true})
const destination=fs.mkdtempSync(path.join(root,"nema17-round3-"))
const evidence=new Set(["round3-fix-status.json","round3-live-baseline-comparison.json","bom-validation.json","jlcpcb-stock-audit.json",
"fix-regression.json","drill-clearance-regression.json","additional-dfm-review.json","connectivity-audit.json",
"coil-all-copper-preflight.json","coil-all-copper-preflight-meta.json","coil-session-kelvin.json","module-test-regression.json",
"round3-copper-gate-tests.json","round3-final/expanded-geometry.json","round3-final-style.log","round3-final-shorts.log",
"round3-final-continuity.log","round3-final-copper.log","round3-final-kelvin.log","round3-final-mechanical.log",
"round3-final-board-tests.log","round3-final-typecheck.log","round3-firmware-tests.log","round3-host-tests.log",
"round3-schematic-sheets/01-soc_support.png","round3-schematic-sheets/01-soc_support.svg"])
const skipped=new Set(["node_modules","fabrication","fabrication-history","__pycache__"]),files=[]
function copy(directory){
for(const entry of fs.readdirSync(path.join(source,directory),{withFileTypes:true})){
if(entry.name.startsWith(".")||skipped.has(entry.name))continue
const relative=path.join(directory,entry.name)
if(relative==="firmware/stm32/build")continue
if(relative.startsWith("routing/")&&entry.name.includes("candidate"))continue
if(relative.startsWith("reports/")){
const report=relative.slice(8)
if(entry.isDirectory()?![...evidence].some(p=>p.startsWith(report+"/")):!evidence.has(report))continue
}
if(entry.isDirectory()){copy(relative);continue}
assert.ok(entry.isFile(),`unexpected link: ${relative}`)
const bytes=fs.readFileSync(path.join(source,relative)),target=path.join(destination,relative)
fs.mkdirSync(path.dirname(target),{recursive:true});fs.copyFileSync(path.join(source,relative),target)
files.push({file:relative,bytes:bytes.length,sha256:sha(bytes)})
}
}
copy("")
for(const file of ["index.circuit.tsx","routing/complete-routes.json","routing/expected-input.json","routing/native-features.json","dist/index/circuit.json","README.md"])
assert.ok(files.some(f=>f.file===file),`${file} included`)
const manifest={createdAt:new Date().toISOString(),source,destination,packageName:previous.name,version,previous,
circuitSha256:status.circuitSha256,fabricationReady:false,files:files.sort((a,b)=>a.file.localeCompare(b.file))}
fs.writeFileSync("reports/round3-publish-manifest.json",JSON.stringify(manifest,null,2)+"\n")
console.log(JSON.stringify({destination,version,fileCount:files.length,totalBytes:files.reduce((n,f)=>n+f.bytes,0),circuitSha256:status.circuitSha256}))