AI Flow
Public Made by Adomby adom
Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board.
Prefer interior documentation sections with a native Rust solve and ordered review priorities #22
Documentation sections now prefer the open board interior before trying edge fallbacks. The ESC candidate includes a fuller description sourced from its board wiki. Physical connector labels remain local to their contacts.
This adds a native Rust section solver with measured text bounds, polygon/hole obstacles, ordered left-aligned rows and explicit fallback reporting. The accompanying priority checklist and AI hints cover coverage, importance, locality, typography, section composition and final native verification.
Integration: run tools/integrate-rust-sections.py against the current crates/adom-aiflow/src/main.rs, then build and test. This guarded helper preserves existing commands; this PR deliberately does not replace main.rs with the older development snapshot. Other placement stages still use Python.
Validation: three Rust unit tests passed and release build succeeded. ESC v36 has 441 labels, zero independent collision errors; native KiCad reports the inherited 13 errors and 539 warnings. The new description is visibly present in the bottom 3D view. Four documentation edge fallbacks and five earlier association-quality reviews remain; this is a draft pending integration and broader validation.
Evidence: /home/adom/aiflow-esc-astra/silkscreen/fresh-grouped/ and esc-g431-astra-silkscreen-v36.kicad_pcb. Board description source: https://wiki.adom.inc/adom/esc-g431
Diff Skip to comments
@@ -0,0 +1,435 @@+//! Semantic documentation layout in native Rust. Measured glyph bounds come from+//! the EDA adapter; no font guesses and no Python execution in this solver.+use serde_json::{json, Value};+use std::collections::{HashMap, HashSet};+type Rect = [f64; 4];+type Pt = [f64; 2];+#[derive(Clone)]+struct Poly {+ rings: Vec<Vec<Pt>>,+ bounds: Rect,+}+fn overlaps(a: Rect, b: Rect) -> bool {+ a[0] <= b[2] && b[0] <= a[2] && a[1] <= b[3] && b[1] <= a[3]+}+fn expand(b: Rect, d: f64) -> Rect {+ [b[0] - d, b[1] - d, b[2] + d, b[3] + d]+}+fn union(a: Rect, b: Rect) -> Rect {+ [+ a[0].min(b[0]),+ a[1].min(b[1]),+ a[2].max(b[2]),+ a[3].max(b[3]),+ ]+}+fn rect(v: &Value) -> Result<Rect, String> {+ let a = v.as_array().ok_or("Missing rectangle")?;+ if a.len() != 4 {+ return Err("Rectangle needs four coordinates".into());+ }+ let mut b = [0.; 4];+ for i in 0..4 {+ b[i] = a[i]+ .as_f64()+ .filter(|x| x.is_finite())+ .ok_or("Invalid rectangle coordinate")?;+ }+ if b[0] > b[2] || b[1] > b[3] {+ return Err("Inverted rectangle".into());+ }+ Ok(b)+}+fn polys(v: &Value) -> Result<Vec<Poly>, String> {+ let kind = v["type"].as_str().ok_or("Missing geometry type")?;+ let groups: Vec<Value> = match kind {+ "Polygon" => vec![v["coordinates"].clone()],+ "MultiPolygon" => v["coordinates"]+ .as_array()+ .ok_or("Missing multipolygon")?+ .clone(),+ _ => return Err(format!("Unsupported geometry {kind}")),+ };+ groups+ .into_iter()+ .map(|g| {+ let mut rings = vec![];+ let mut b = [+ f64::INFINITY,+ f64::INFINITY,+ f64::NEG_INFINITY,+ f64::NEG_INFINITY,+ ];+ for r in g.as_array().ok_or("Invalid rings")? {+ let mut points = vec![];+ for p in r.as_array().ok_or("Invalid ring")? {+ let x = p[0].as_f64().filter(|x| x.is_finite()).ok_or("Invalid x")?;+ let y = p[1].as_f64().filter(|x| x.is_finite()).ok_or("Invalid y")?;+ points.push([x, y]);+ b = union(b, [x, y, x, y]);+ }+ if points.len() < 4 {+ return Err("Polygon ring too short".into());+ }+ rings.push(points)+ }+ if rings.is_empty() {+ return Err("Empty polygon".into());+ }+ Ok(Poly { rings, bounds: b })+ })+ .collect()+}+fn point_inside(p: Pt, poly: &Poly) -> bool {+ let mut inside = false;+ for ring in &poly.rings {+ for i in 0..ring.len() {+ let a = ring[i];+ let b = ring[(i + 1) % ring.len()];+ if (a[1] > p[1]) != (b[1] > p[1])+ && p[0] < (b[0] - a[0]) * (p[1] - a[1]) / (b[1] - a[1]) + a[0]+ {+ inside = !inside+ }+ }+ }+ inside+}+fn segment_rect(a: Pt, b: Pt, r: Rect) -> bool {+ let mut lo: f64 = 0.;+ let mut hi: f64 = 1.;+ for axis in 0..2 {+ let d = b[axis] - a[axis];+ if d.abs() < 1e-12 {+ if a[axis] < r[axis] || a[axis] > r[axis + 2] {+ return false;+ }+ } else {+ let t1 = (r[axis] - a[axis]) / d;+ let t2 = (r[axis + 2] - a[axis]) / d;+ lo = lo.max(t1.min(t2));+ hi = hi.min(t1.max(t2));+ if lo > hi {+ return false;+ }+ }+ }+ true+}+fn boundary_hits(p: &Poly, r: Rect) -> bool {+ p.rings+ .iter()+ .any(|ring| (0..ring.len()).any(|i| segment_rect(ring[i], ring[(i + 1) % ring.len()], r)))+}+fn intersects(p: &Poly, r: Rect) -> bool {+ overlaps(p.bounds, r) && (boundary_hits(p, r) || point_inside([r[0], r[1]], p))+}+fn contains(p: &Poly, r: Rect) -> bool {+ !boundary_hits(p, r)+ && [[r[0], r[1]], [r[0], r[3]], [r[2], r[1]], [r[2], r[3]]]+ .iter()+ .all(|x| point_inside(*x, p))+}+struct Index {+ items: Vec<Poly>,+ bins: HashMap<(i32, i32), Vec<usize>>,+}+impl Index {+ fn new(items: Vec<Poly>) -> Self {+ let mut bins: HashMap<(i32, i32), Vec<usize>> = HashMap::new();+ for (i, p) in items.iter().enumerate() {+ for x in (p.bounds[0] / 4.).floor() as i32..=(p.bounds[2] / 4.).floor() as i32 {+ for y in (p.bounds[1] / 4.).floor() as i32..=(p.bounds[3] / 4.).floor() as i32 {+ bins.entry((x, y)).or_default().push(i)+ }+ }+ }+ Self { items, bins }+ }+ fn hits(&self, r: Rect) -> bool {+ let mut seen = HashSet::new();+ for x in (r[0] / 4.).floor() as i32..=(r[2] / 4.).floor() as i32 {+ for y in (r[1] / 4.).floor() as i32..=(r[3] / 4.).floor() as i32 {+ if let Some(ids) = self.bins.get(&(x, y)) {+ for i in ids {+ if seen.insert(*i) && intersects(&self.items[*i], r) {+ return true;+ }+ }+ }+ }+ }+ false+ }+}+#[derive(Clone)]+struct Glyph {+ id: usize,+ size: f64,+ b: Rect,+ dx: f64,+ dy: f64,+}+fn rows(+ section: &Value,+ metrics: &Value,+ font: f64,+ bottom: bool,+) -> Result<Vec<Vec<Glyph>>, String> {+ let rr = section["rows"].as_array().ok_or("Section needs rows")?;+ if rr.is_empty() {+ return Err("Empty documentation section".into());+ }+ let mut out = vec![];+ let cols = rr+ .iter()+ .map(|r| r.as_array().map_or(0, |a| a.len()))+ .max()+ .unwrap_or(0);+ let mut widths = vec![0_f64; cols];+ for row in rr {+ for (col, id) in row.as_array().ok_or("Invalid row")?.iter().enumerate() {+ let id = id.as_u64().ok_or("Invalid label index")? as usize;+ let size = font+ * section["sizeFactors"][id.to_string()]+ .as_f64()+ .unwrap_or(1.);+ let b = rect(&metrics[id.to_string()])?;+ widths[col] = widths[col].max((b[2] - b[0]) * size + 0.8);+ }+ }+ for row in rr {+ let mut line = vec![];+ for (col, id) in row.as_array().unwrap().iter().enumerate() {+ let id = id.as_u64().unwrap() as usize;+ let size = font+ * section["sizeFactors"][id.to_string()]+ .as_f64()+ .unwrap_or(1.);+ let mut b = rect(&metrics[id.to_string()])?;+ for x in &mut b {+ *x *= size+ }+ let dx = widths[..col].iter().sum::<f64>() * if bottom { -1. } else { 1. }+ - if bottom { b[2] } else { b[0] };+ let dy = -b[1];+ line.push(Glyph {+ id,+ size,+ b: [b[0] + dx, 0., b[2] + dx, b[3] + dy],+ dx,+ dy,+ });+ }+ if line.is_empty() {+ return Err("Empty row".into());+ }+ out.push(line)+ }+ Ok(out)+}+/// Prefer interior placement above small font gains; record any edge fallback.+/// Rows keep alignment and order. Extra spacing occurs only in baseline quanta.+pub fn solve(d: &Value) -> Result<Value, String> {+ let outline = polys(&d["outline"])?;+ if outline.len() != 1 {+ return Err("One board outline required".into());+ }+ let outline = &outline[0];+ let bb = outline.bounds;+ let width = bb[2] - bb[0];+ let height = bb[3] - bb[1];+ let mut placements = vec![];+ let mut missing = vec![];+ let mut reports = vec![];+ for side in ["F.SilkS", "B.SilkS"] {+ let mut obstacles = vec![];+ for o in d["obstacles"].as_array().ok_or("Missing obstacles")? {+ if o["layer"] == side {+ obstacles.extend(polys(&o["polygon"])?);+ }+ }+ let index = Index::new(obstacles);+ let mut occupied: Vec<Rect> = vec![];+ for p in d["placements"].as_array().unwrap_or(&vec![]) {+ if p["layer"] == side {+ occupied.push(expand(rect(&p["box"])?, 0.06));+ }+ }+ for section in d["sections"]+ .as_array()+ .ok_or("Missing sections")?+ .iter()+ .filter(|s| s["layer"] == side)+ {+ let anchor = [+ section["anchor"][0]+ .as_f64()+ .unwrap_or((bb[0] + bb[2]) / 2.),+ section["anchor"][1]+ .as_f64()+ .unwrap_or((bb[1] + bb[3]) / 2.),+ ];+ let mut origins = vec![];+ let mut y = bb[1];+ while y < bb[3] {+ let mut x = bb[0];+ while x < bb[2] {+ origins.push([x, y]);+ x += 0.35;+ }+ y += 0.35;+ }+ // Position rank is evaluated from the actual block centre below; origins are+ // preordered around the requested semantic interior zone to bound work.+ origins.sort_by(|a, b| {+ ((a[0] - anchor[0]).powi(2) + (a[1] - anchor[1]).powi(2))+ .total_cmp(&((b[0] - anchor[0]).powi(2) + (b[1] - anchor[1]).powi(2)))+ });+ let fonts: Vec<f64> = section["fonts"]+ .as_array()+ .map(|a| a.iter().filter_map(Value::as_f64).collect())+ .unwrap_or(vec![0.6, 0.5, 0.4, 0.35, 0.3]);+ if fonts.is_empty() || fonts.iter().any(|f| !f.is_finite() || *f <= 0.) {+ return Err("Section font sizes must be positive and finite".into());+ }+ let prefer_interior = section["preferInterior"].as_bool().unwrap_or(true);+ let mut chosen: Option<(Vec<Glyph>, Rect, f64, usize, usize)> = None;+ 'passes: for pass in 0..if prefer_interior { 2 } else { 1 } {+ for font in &fonts {+ let raw = rows(section, &d["metrics"], *font, side == "B.SilkS")?;+ let minx = raw+ .iter()+ .flatten()+ .map(|g| g.b[0])+ .fold(f64::INFINITY, f64::min);+ let maxx = raw+ .iter()+ .flatten()+ .map(|g| g.b[2])+ .fold(f64::NEG_INFINITY, f64::max);+ for origin in &origins {+ let x = origin[0] - (minx + maxx) / 2.;+ let mut yy = origin[1];+ let mut packed = vec![];+ let mut envelope = [+ f64::INFINITY,+ f64::INFINITY,+ f64::NEG_INFINITY,+ f64::NEG_INFINITY,+ ];+ let mut skips = 0;+ let mut valid = true;+ for line in &raw {+ let mut accepted = None;+ for skip in 0..=section["maxRowGapQuanta"].as_u64().unwrap_or(6) {+ let rowy = yy + skip as f64 * 0.2;+ let shifted: Vec<Glyph> = line+ .iter()+ .map(|g| Glyph {+ id: g.id,+ size: g.size,+ dx: g.dx + x,+ dy: g.dy + rowy,+ b: [g.b[0] + x, g.b[1] + rowy, g.b[2] + x, g.b[3] + rowy],+ })+ .collect();+ if shifted.iter().all(|g| {+ contains(outline, expand(g.b, 0.045))+ && !index.hits(expand(g.b, 0.045))+ && !occupied.iter().any(|o| overlaps(*o, expand(g.b, 0.15)))+ }) {+ accepted = Some((shifted, skip as usize));+ break;+ }+ }+ if let Some((line, skip)) = accepted {+ for g in &line {+ envelope = union(envelope, g.b)+ }+ yy = line.iter().map(|g| g.b[3]).fold(0., f64::max)+ + (0.28_f64).max(*font * 0.65);+ packed.extend(line);+ skips += skip;+ } else {+ valid = false;+ break;+ }+ }+ if !valid+ || !contains(outline, expand(envelope, 0.02))+ || occupied+ .iter()+ .any(|o| overlaps(*o, expand(envelope, 0.15)))+ {+ continue;+ }+ let interior = envelope[0] > bb[0] + width * 0.20+ && envelope[2] < bb[2] - width * 0.20+ && envelope[1] > bb[1] + height * 0.20+ && envelope[3] < bb[3] - height * 0.20;+ if prefer_interior && pass == 0 && !interior {+ continue;+ }+ chosen = Some((packed, envelope, *font, pass, skips));+ break 'passes;+ }+ }+ }+ if let Some((packed, envelope, font, pass, skips)) = chosen {+ let ids: Vec<usize> = packed.iter().map(|g| g.id).collect();+ for g in packed {+ let l = &d["labels"][g.id];+ if l.is_null() {+ return Err("Missing label content".into());+ }+ placements.push(json!({"index":g.id,"text":l["text"],"reference":null,"layer":side,"role":l["role"],"section":section["id"],"textAlign":"left","x":g.dx,"y":g.dy,"size":g.size,"angle":0,"box":g.b}));+ }+ occupied.push(expand(envelope, 0.15));+ reports.push(json!({"id":section["id"],"status":"placed","font":font,"indices":ids,"box":envelope,"interiorPreferred":prefer_interior,"edgeFallback":prefer_interior&&pass==1,"extraRowGapQuanta":skips}));+ } else {+ let ids: Vec<Value> = section["rows"]+ .as_array()+ .unwrap()+ .iter()+ .flat_map(|r| r.as_array().unwrap().clone())+ .collect();+ missing.extend(ids.clone());+ reports.push(json!({"id":section["id"],"status":"unresolved","indices":ids}));+ }+ }+ }+ Ok(+ json!({"placements":placements,"unresolved":missing,"sections":reports,"engine":"native Rust section layout","nativeVerified":false}),+ )+}+#[cfg(test)]+mod tests {+ use super::*;+ fn poly() -> Poly {+ polys(&json!({"type":"Polygon","coordinates":[[[0,0],[20,0],[20,20],[0,20],[0,0]],[[8,8],[12,8],[12,12],[8,12],[8,8]]]})).unwrap().remove(0)+ }+ #[test]+ fn hole_and_boundary_conformance() {+ let p = poly();+ assert!(!intersects(&p, [9., 9., 10., 10.]));+ assert!(intersects(&p, [7., 9., 9., 10.]));+ assert!(contains(&p, [1., 1., 2., 2.]));+ assert!(!contains(&p, [7., 7., 13., 13.]));+ }+ #[test]+ fn invalid_geometry_refused() {+ assert!(polys(&json!({"type":"LineString","coordinates":[]})).is_err());+ }+ #[test]+ fn interior_and_order_are_preserved() {+ let d = json!({"outline":{"type":"Polygon","coordinates":[[[0,0],[30,0],[30,30],[0,30],[0,0]]]},"obstacles":[],"placements":[],"labels":[{"text":"Heading","role":"identity"},{"text":"Description","role":"note"}],"metrics":{"0":[-2,-0.5,2,0.5],"1":[-3,-0.5,3,0.5]},"sections":[{"id":"intro","layer":"B.SilkS","anchor":[1,1],"rows":[[0],[1]],"sizeFactors":{"0":1.5}}]});+ let r = solve(&d).unwrap();+ assert_eq!(r["unresolved"].as_array().unwrap().len(), 0);+ let ps = r["placements"].as_array().unwrap();+ assert_eq!(ps[0]["box"][2], ps[1]["box"][2]);+ assert!(ps[0]["y"].as_f64().unwrap() < ps[1]["y"].as_f64().unwrap());+ assert_eq!(r["sections"][0]["edgeFallback"], false);+ }+}+@@ -0,0 +1,27 @@+"""Integrate only the new section command into the chosen current AI Flow source.+Fail closed when the expected clap/match anchors have changed. Does not replace+main.rs with the development snapshot or remove any existing commands.+"""+import argparse+from pathlib import Path+p=argparse.ArgumentParser();p.add_argument('main',type=Path);a=p.parse_args();s=a.main.read_text()+if 'mod silkscreen_sections;' not in s:+ anchor='use std::collections::BTreeMap;'+ if s.count(anchor)!=1:raise SystemExit('Current import anchor changed; integrate the module explicitly')+ s=s.replace(anchor,'mod silkscreen_sections;\n'+anchor,1)+if 'SilkscreenSections {' in s:raise SystemExit('Section command already exists; review its implementation instead of duplicating it')+if s.count('enum Cmd {')!=1 or s.count('match &cli.cmd {')!=1:raise SystemExit('Current CLI anchors changed; integrate explicitly')+s=s.replace('enum Cmd {','enum Cmd {\n SilkscreenSections { #[arg(long)] input: PathBuf, #[arg(long)] out: PathBuf },',1)+arm='''+ Cmd::SilkscreenSections { input, out } => {+ thread(&cli); let _r=load_run(&cli);+ let data:serde_json::Value=serde_json::from_slice(&std::fs::read(input).unwrap_or_else(|e|err(&e.to_string(), &[]))).unwrap_or_else(|e|err(&e.to_string(), &[]));+ let result=silkscreen_sections::solve(&data).unwrap_or_else(|e|err(&e,&[]));+ std::fs::write(out,serde_json::to_vec_pretty(&result).unwrap()).unwrap_or_else(|e|err(&e.to_string(), &[]));+ if !result["unresolved"].as_array().unwrap().is_empty(){err("Documentation sections remain unresolved", &["Keep rows together; try shorter line layouts or other interior regions before edge fallback.".into()]);}+ let fallbacks=result["sections"].as_array().unwrap().iter().filter(|s|s["edgeFallback"]==true).count();+ ok(&format!("Native Rust placed {} documentation labels; {fallbacks} edge fallbacks",result["placements"].as_array().unwrap().len()), &["Prefer open board interior for a verified board description and left-aligned service blocks. Physical pin/contact labels stay local. Follow docs/silkscreen-priority-pass.md; inspect font sizes, edge fallbacks, native DRC and both EDA views.".into()]);+ }+'''+s=s.replace('match &cli.cmd {','match &cli.cmd {'+arm,1);a.main.write_text(s);print('Added native Rust section command without replacing existing commands')+@@ -0,0 +1,18 @@+# Silkscreen priorities and review passes++Treat silkscreen as a physical user interface for the EE assembling, wiring and debugging this specific board. The AI identifies intent and importance; deterministic geometry proves that the selected text and strokes fit. Explain decisions and exceptions with source data and short rationale, not private chain-of-thought.++The order below is explicit: a lower priority cannot buy a collision, incorrect label, hidden text or missing required value.++1. **Physical correctness.** Use actual numbered pad nets and verified component values. Include board edges, fitted component bodies, full custom-pad mask geometry, all holes/vias, native footprint artwork, other text and actual pointer/frame stroke widths as obstacles. Never infer voltage/current ratings from a part's absolute maximum or an unqualified solver estimate.+2. **Coverage and field use.** Label all required references, smaller values, test-point functions, polarity, connector pins and machine contacts/pins. Put contact/edge-connector identities and functions on BOTH faces near the actual feature; a remote table is supplementary.+3. **Board-purpose importance.** Before placement, classify the board and rank its human interfaces. On ESCs, prominently label PHASE A/B/C and battery polarity/ground. Other boards get their own appropriate prominent interfaces, supply limits and critical warnings. Functional terminal names may outrank MC/J references. Use only sourced descriptions/limits.+4. **Locality and association.** Keep each name/value pair atomic and close to its component. For edge contacts prefer the space between contact and board edge, consistently across a row; use inside placement only when needed. Pin labels face their target: right-aligned left of the pad, left-aligned right of it, reversed appropriately for a readable bottom-face view. Use curved pointers when association is unclear.+5. **Group design.** Repeated contact frames default on, with a user-off option. Solve common left/right rails, width/height, padding and rhythm for a row/column. Do not stretch a frame after checking collisions. Clearance gaps and exceptional font/inside placements are explicit. Calculation bounds are dashed and translucent; only actual manufacturing text/pointers/frames are opaque solid strokes.+6. **Readable typography.** Maximize font size within the above constraints. Start ordinary references around 0.8 mm and values around 0.4 mm, with values smaller than references. Important interfaces often justify 1.0–1.4 mm or more where space permits. The user-authorized InstaPCB 0.3/0.2 mm value text is a last resort, not a default or a general fabrication guarantee. Document the selected sizes and any tiny-text compromise.+7. **Interior documentation pass.** Reserve readable open INTERIOR regions for a source-backed board description, identity/revision, service instructions and reference tables. Prefer an interior layout at a readable font over a slightly larger edge layout. Keep physical terminal labels local. Preserve semantic blocks, left-aligned visible text, heading hierarchy and ordered rows. Reflow or split a large table into coherent columns before pushing it to the rim. Slight, quantized row-spacing increases may avoid vias; do not move lines independently or reorder them. If the middle cannot fit safely, report the blocking geometry, attempted sizes and explicit edge fallback. Include what the board does, not just a project code.+8. **Independent verification and final visual pass.** Check every text and stroke ahead of the EDA, then native DRC and native text/geometry read-back. Inspect top and bottom in both the editor and its refreshed 3D viewer. Review left alignment, common rails, name/value hierarchy, pin-1/polarity, no text hidden by bodies, no holes under text, and whether documentation uses interior space sensibly. Repair the general rule when a native check reveals a defect.+9. **Evidence.** Replay all required groups and real rework with active text sizes. Isolate faces and show the bottom from below (or explicitly mirrored from above). Record 1920×1080; frame the complete active group independently of manual inspection camera movement. Include final native EDA proof. Inspect contact sheets and actual webview playback. Never describe the replay as recorded internal AI reasoning or omit unresolved decisions from the report.++Report separately: coverage, geometric validity, native verification, visual association/readability, source handoff and actual shared-package release. Passing DRC alone is not production acceptance.+@@ -0,0 +1,154 @@+# Two-sided service silkscreen++The `silkscreen` AI-owned stage runs after analysis/net review and before the final native 3D tour. Plan label space at placement time. Read the reusable [InstaPCB silkscreen skill](https://wiki.adom.inc/adom/instapcb/files/skills/instapcb-silkscreen/SKILL.md).+++Treat silkscreen as the board's built-in service manual. Add useful information generously, with a visual hierarchy and space between labels. Do not fill space with ambiguous or unreadable text.++## Process profile and provenance++For the InstaPCB profile requested by Adam (Adom CEO, 2026-09-16), use approximately 0.8 mm reference designators and 0.5 mm secondary value text where space allows. He reports that InstaPCB's UV fiber laser process can render readable 0.5 mm text. This is a named process target, not a universal fab minimum or a measured acceptance result. Verify the current station profile for stroke width, contrast, mask registration and clearances; retain the profile/version and inspect a physical coupon when fabrication qualification is required. Do not infer minimum stroke from text height. Preserve other fabs' rules and never disable DRC globally to force microtext through. Treat two-sided marking cost as a property of the selected service, not a universal free option.++## Plan before placement; finish after copper stabilizes++1. Read the actual schematic, BOM, board and approved requirements. Build a label manifest with text, source, reference/net, face, size, orientation and purpose. Reserve service-label space during placement. Finalize after routing, pours and analysis, before final DRC and the 3D tour. Return here whenever a pinout, rating or placement changes.+2. Put board name, function, revision and an enduring project/documentation link on the board. Use an approved logo if available. Keep decoration subordinate to connection and safety information. Do not invent certifications, copyright ownership or electrical ratings.+3. Label power inputs and returns, polarity, connector pin 1 and every accessible signal, machine pin/contact functions, programming/debug pinout, switch actions, LED meanings, test points and mounting orientation. Verify pin labels against actual numbered pads and nets, not the connector's apparent geometry. A net name does not establish a safe voltage or current rating. Print voltage range, maximum current and other limits only with approved design evidence; distinguish input rating, rail nominal voltage and absolute maximum.+ Every test point MUST have visible silkscreen identifying both its reference and verified net/signal or measurement function. Prioritize these labels before ordinary component values. Keep them adjacent to the accessible probe pad, or use a short unambiguous leader/key on the same accessible face when crowded. Check complete test-point coverage against the actual board; missing or ambiguous labels are unresolved findings, never silently omitted. Repeat on the opposite face when useful for mounted-board debugging, without implying a probe pad exists there.++4. Use approximately 1.2–2.0 mm for board identity and critical connection labels, 0.8 mm for references and 0.5 mm for values/secondary notes under the named InstaPCB profile. These are starting sizes, not mandatory packing rules. Prefer horizontal text and consistent reading directions; rotate to follow a connector only when that aids use. Use familiar engineering notation (10k, 100nF, 4.7uF); distinguish value, tolerance and voltage rating. Give every resistor/capacitor its reference plus a nearby value; search microtext placements before declaring a space constraint. Long IC MPNs may belong in a back-side key rather than in congested assembly space.+Keep each reference unmistakably associated with its own component. Prefer reducing reference font size locally over moving a label farther away. Aim for complete reference coverage; use a short clear leader only when proximity alone is ambiguous. Treat approximately 0.8 mm as an initial reference size, not a minimum. For dense InstaPCB artwork Adam explicitly permits secondary values at 0.3 mm or even 0.2 mm (2026-09-16); try 0.5, 0.3 then 0.2 mm while preserving the ref/value pairing and required stroke/spacing. These tiny sizes are user-requested artwork options, not independently verified laser-process capability. Keep the actual sizes and any unresolved physical legibility/DFM limits in the review; do not silently omit labels or globally weaken fab rules. Inspect the result at actual size and close-up.++5. For every machine pin, machine contact and edge-pin connector, repeat its reference/pin number and verified signal or power function on BOTH faces. A mounted board may expose only one side during debugging. Put the repeated labels beside the same physical connection where possible; when crowded, use a short clear leader to the actual connection on that face; a remote keyed legend is supplementary only. A pinout table on the other face alone does not satisfy this check. Review both faces in the mounted-access context, with bottom text correctly mirrored and pin numbering preserved. Use both F.SilkS and B.SilkS (or the EDA's native equivalents). Bottom text must read correctly when viewed from underneath, with the EDA's proper mirror setting; do not reverse the string. Put a clear pinout/service key on the less crowded face, mapped to reference and pad number. Copper/pour labels identify a verified net; avoid implying that hidden traces are visible or electrically isolated.+6. Protect exposed pads, solder-mask openings, test contacts, holes, board edges, fiducials, optical windows, component courtyards and mechanical interfaces. Consider visible space with components fitted: body footprints may obscure text even when DRC passes. Retain assembly-only markings on fabrication layers if useful, but do not count them as visible silkscreen. Never move copper or parts merely to force extra text without a recorded design return.+7. Inspect both faces at realistic physical scale and enlarged, in native 2D, native assembled 3D and fabrication plots. Check overlaps, legibility, bottom mirroring, ref/value association, clip-to-mask losses and labels covered by components. Run native DRC with the selected fab profile; compare new violations to the baseline. Keep manufacturing uncertainties explicit.+8. Save the label manifest, before/after plots, native review images and DRC comparison. Prove connectivity, placement, zones, model transforms and board outline unchanged for a silk-only edit. Record unresolved labels rather than inventing them.++## Flow and bridge ownership++AI Flow orchestrates this as a `silkscreen` step and records review evidence. Native text insertion, layer/mirror settings, font metrics, visibility, plotting and DRC belong to the EDA bridge. Discover current verbs; request missing reusable operations from the owning bridge. An offline board-copy script is a transparent fallback, not a new competing bridge API. Do not use mouse clicks in KiCad workflows that prohibit them.++Film a slow top/bottom overview and a brief connector-label close-up in the native EDA. Keep raw recordings, then budget roughly 3–5 seconds in the final two-minute film; publish detailed readable plots separately. A render proves appearance, not laser-process qualification.++## Record the silkscreen being built++Start the native editor window recording BEFORE the first label mutation. Show references and their smaller value labels appearing one at a time, or in small meaningful groups chosen by the AI (a ref/value pair, a connector pinout, or a local circuit block). Keep enough dwell for the actual recorder to capture each change; inspect the contact sheet instead of assuming a fixed delay guarantees a frame. Frame the active region so text and its component remain visible, with occasional whole-board context and a face change for bottom markings.++Keep the recording running through actual revision: moves, rotations, font reductions, value pairing, overlap fixes and rejected placements should be visible in their real order. Preserve native undo and stable item identifiers where the bridge supports them. Save a sidecar event list with timestamps, affected references/IDs, operation, old/new text/position/size and a concise reason. Record explicit reasons and actions, not private chain-of-thought. Reusable add/update/delete text, refresh and undo operations belong in the EDA bridge; AI Flow chooses the sequence, records evidence and composes the result. Do not invent an unsupported bridge command or silently replace the entire board for each label.++If incremental native editing is unavailable, report that bridge gap and retain honest intermediate saved-board checkpoints and before/after evidence. A reconstruction from checkpoints or a reveal of finished labels MUST be identified as a replay; it is not footage of the original placement or reasoning. Do not manufacture rework to make the film interesting. The existing ESC v16 top/bottom review is final-state evidence, not a progressive-placement recording.++Retain the full raw, uncaptioned step clip and offer a separate detailed action cut that shows population and real rework. In the final two-minute video use roughly 3–5 seconds of accelerated population, including a representative correction when one occurred, ending on the final labelled board. Keep exact step/run clocks and chronological provenance. Put explanations in the composed narration/captions, never in the raw clip. Finish with native top/bottom inspection and DRC; a pleasing animation does not establish label coverage or fabrication legibility.++## Contact labels must preserve physical association on both faces++Place every machine-contact, machine-pin and edge-connector label beside its actual physical connection on BOTH faces, not merely in a remote pinout table. Treat a table as supplementary reference only; it never satisfies positional labelling. Verify each face against pad coordinates and numbering, including bottom mirroring. Record unresolved space constraints rather than claiming table coverage completes this requirement.++Separate the primary reference (for example MC10) from the secondary verified function (DSHOT). Use independently sized native text items: the function is smaller than the reference, allowing the pair to stay near the contact. Keep the pair visually grouped and readable in one direction; prefer consistent horizontal rows along a dense contact bank over alternating rotations that obscure association. Reduce size locally when necessary under the selected fabrication profile.++When proximity is still ambiguous, draw a short curved silkscreen leader from the label group toward its particular contact. Use a gentle arc or rounded path with an unmistakable endpoint outside exposed copper and solder-mask openings. Do not run a leader through another label, contact, part body, hole, board edge or another leader; keep clearance from unrelated silk. Avoid ornamental curves and crossings. Inspect both faces in native 2D and assembled 3D at contact-bank close-up scale, checking that each label and each leader points to exactly one intended connection. Native DRC remains required; a leader must not become clipped silk or resemble an electrical trace in the documentation.++Film real leader placement and ref/function resizing as part of progressive silkscreen capture. Native text, curves and undo operations belong in the EDA bridge; AI Flow owns the guidance, coverage checks, recording and composition. Retain source-to-pad mapping and unresolved physical font/stroke limits in the manifest.++## Complete local value coverage++For the requested InstaPCB profile, attempt a nearby value for EVERY resistor and capacitor, including rotated components and references. Search both orientations and adjacent sides at 0.5, 0.3 and 0.2 mm as needed, preserving an unmistakable reference/value association. Do not skip values merely because the reference is rotated, an initial placement fails, or a bottom table exists. Repack nearby silk or use a clear short leader when necessary. Audit actual-board value coverage and report each unresolved value explicitly; a back-side key is supplementary, not completion. Retain native mask/overlap checks and distinguish requested artwork sizes from measured physical legibility.++## Keep both native views current after every update++After EVERY board, footprint, silkscreen, library-binding or 3D-model update, update BOTH the native 2D board editor and its associated 3D viewer before reporting or showing the result. A file write, successful transfer, DRC result or web preview is not a refreshed native view. Verify the exact saved board path/revision in the editor, then regenerate/reload the 3D view and inspect the changed features after painting settles. Capture evidence from both exact windows; confirm models, markings and layer visibility, not only the window titles.++Use supported native refresh/reload commands through the owning EDA bridge. If an offline edit or model cache requires closing and reopening, inspect unsaved changes and dialogs first, preserve user work, close only task-owned stale windows, reopen the latest board, and open its linked 3D viewer. Never save stale editor contents over a newer disk revision. Keep one current editor/viewer pair rather than accumulating old windows. Re-discover HWNDs after reopening; preserve the user's foreground and view preferences unless showing a view was requested. Refresh a completed edit or coherent batch promptly; do not wait until the final video. If either view cannot be verified, state which one remains stale and resolve it before claiming the update is shown.++## Search space before shrinking text++Treat 0.2 mm as an exceptional fallback, not a successful default. Start with the largest sensible font for the information hierarchy and search nearby positions, rotations and both sides of the component. Use the native EDA's stroke-font bounds, stroke width, justification, rotation and mirrored bottom-face transform. If only estimated bounds are available, identify them as estimates and validate every accepted batch with native plots/DRC and assembled 3D visibility.++Build obstacles from fitted component bodies, individual pads and solder-mask openings, vias/holes, board edges, existing silk and text. Do not replace a collection of separated obstacles with one enormous bounding box that discards useful gaps. Keep reference/value pairs associated but retain separate text rectangles so empty space between them remains usable. Solve each face with its own obstacles; a copied top layout is not a validated bottom layout.++Search alternative positions at each useful font size, then jointly repack neighboring label groups. Use a bounded search with backtracking or beam alternatives so an early label does not permanently consume the best space. Favor complete coverage, readable font sizes and short unmistakable association; preserve connector pin-row order. Reserve and validate curved leader paths too. Report unresolved labels rather than hiding or silently omitting them. Never move copper or components merely to fit text without a design return.++Use `adom-aiflow silkscreen-layout --input candidates.json --out layout.json --ai-thread <thread> --run <run>` for the shared bounding-box candidate search. Input carries board bounds, fixed obstacle rectangles and label groups with alternative native-derived rectangles, font sizes, positions and anchors. A candidate may provide several `boxes` for an intact ref/value pair or leader segments. This is a bounded weighted search, not proof of a global optimum; it does not edit the board. Native text measurement/insertion/refresh remains the EDA bridge's job. Apply by stable item identity, never by text alone: duplicate values and repeated pinout tables are common.++Run native clearance/overlap checks, compare findings against the inherited baseline, then inspect actual-size legibility and close-up association on both faces. Revise the candidates when validation rejects them; do not just call the search successful. Refresh both the 2D editor and its linked 3D viewer after an accepted batch. Record genuine placement and rework in the silkscreen step clip.++### Candidate geometry evidence++`tools/native-text-bounds.py --svg front.svg --labels labels.json --layer F.SilkS --out bounds.json` measures native stroke paths from a single-face KiCad SVG export. Export each face separately through the bridge. The label manifest contains `labels` with `text`, `x`, `y`, `size`, `angle` and `layer`. The helper reports its nearest-text matching method and SVG hash; inspect ambiguous duplicate/multiline mappings. It is a fallback geometry reader, not a native live text-metrics API. Preserve stable item IDs for application.++A `silkscreen-layout` input has `bounds: [xmin,ymin,xmax,ymax]`, `obstacles: [{box: [...]}]`, and `labels: [{id,anchor:[x,y],candidates:[{font,position:[x,y],box:[...]}]}]`. Optional candidate `boxes` describes separate rectangles for grouped text/leader segments; every rectangle must be clear. Optional `orderGroup` and numeric `order` preserve increasing connector-row Y. `beamWidth` and `candidatesPerLabel` bound the search. The score weights font size, distance and movement; it cannot promise the global optimum. All outputs retain `nativeVerified: false` until separate native review evidence is recorded.++For tightly coupled regions, set `solver: "milp"` to use SciPy/HiGHS mixed-integer selection with `solverSeconds`, `milpPerFont`, `preferredMinimumFont`, and `smallFontPenalty`. This optional engine needs SciPy; the default beam engine uses Python's standard library. Candidate pruning must preserve alternatives at every font size. Solver optimality only concerns the finite supplied candidate set, never all possible board artwork.++`tools/silkscreen-leaders.py --input candidates.json --out routed-candidates.json` accepts per-label `leaderTargets` and `routeBounds`, uses a bounded grid search around fixed rectangles, and appends leader segment bounds to each candidate. The final selection prevents those reserved paths crossing other selected text/routes. It retains alternatives per font size. Native application may gently round corners inside the cleared envelope; validate the actual resulting curves. Failure to route a leader must trigger repacking or an explicit unresolved finding.++### Complete obstacle coverage is required++Before placing or accepting silkscreen, enumerate every fitted model, via and drilled hole across the entire board, on both faces. Record coverage counts and stable IDs. A local search region does not excuse leaving the rest of the board unchecked. Project the actual fitted 3D model into the board plane with its scale, offset, rotation and footprint transform; include overhangs. Conservative transformed model bounds are acceptable when a tighter silhouette is unavailable. F.Fab, courtyard or pad envelopes are fallbacks, not proof of fitted-body coverage: a footprint can have no Fab drawing, and the space between separated pads can still be occupied by the body. Missing model geometry must be reported and supplied a documented conservative envelope, never a tiny placeholder that silently allows text beneath the component.++Reserve every via hole on both faces, including tented vias when visible labeling is the requirement, and use the larger of the hole keepout and actual exposed mask opening. Also reserve through holes, slots, exposed pads and existing silk. Check actual stroked text extents, not just its anchor. After each re-layout, audit ALL existing labels and leaders against this complete obstacle set. A collision-free position is not enough: keep each reference/value next to its own component or add a clear, noncrossing leader. Do not move a label beside a different component merely to clear an obstacle. Native DRC and fitted 3D visibility are separate acceptance checks; a DRC baseline does not establish readable assembled silkscreen. Refresh and inspect both native 2D and 3D views before presenting the result.++## Optional live silkscreen dashboard++Offer `silkscreen-dashboard show` with the run and ai-thread flags. The shared observer renders real timestamped solver events, sampled candidate bounds and reasons, selected proposals and unresolved labels, in 2D and a fitted-model 3D preview. `silkscreen-layout --events <run>/silkscreen-dashboard/events.jsonl` emits these without AI/provider calls or deliberate solver pauses. Read `tools/silkscreen-dashboard/SKILL.md` for the manifest, transform limits, lifecycle and recording contract. Live and replay are visibly distinct; replay exports are not raw native CAD footage. Selected proposals remain unverified until native application, DRC and assembled visibility checks pass. Fusion/Altium adapters are not implemented merely because the manifest is tool-neutral.++### Release quality: references, values and visual association++Do not accept a fresh solve based on text-object coverage alone. Place each reference+and required value atomically; reference text is larger, value text is normally+60–80% of reference height. Reserve both before placing the next component. Keep+connector rows in physical pin order and preserve that constraint on both faces.+An old layout is a comparison baseline, never evidence that a new solver succeeded.++Where a nearby component could be mistaken for the label's owner, provide a short+curved pointer to the intended component's visible rim. Where space permits, a+shared outline may group the component and its reference/value. These graphics+must clear mask openings, drilled holes, other bodies and all text. Avoid extra+lines where proximity already makes ownership unambiguous. If no safe association+can be drawn, repack or flag it for review; do not silently mark it complete.++Release proof includes a solve from empty label occupancy without old positions as+candidates, name/value hierarchy and completeness checks, connector-order checks,+collision checks including fitted models and vias, native EDA readback and DRC,+and human-readable top/bottom review with the full event replay. Show bottom from+below with readable text, or explicitly mirror text in a top-view projection.++Machine contacts and machine pins use an outside-first policy: the label sits+between the contact and the nearest board edge whenever feasible. Preserve row+order and side consistency; report inside fallbacks. Printed contact/name/value+frames default on (`contactBorders: true`), with `--no-contact-borders` for a solve+without them. Reserve every frame stroke during placement, and report any small+clearance gaps required around holes. This preference applies to both board faces.++### Board-specific importance pass before layout+The AI first identifies how the real board will be connected, powered, serviced and+debugged. Rank interfaces by their importance to those tasks, using verified board,+schematic and spec data. Write that ranking into the solve input; do not give every+label equal weight. Reserve prominent connection labels first, then component+reference/value pairs and secondary service notes. Only print voltage/current+ratings supported by the design review, never guessed ratings.++ESC / BLDC controller rule: PHASE A, PHASE B and PHASE C are prominent motor-terminal+names, normally targeting 1.0–1.4 mm where geometry permits, on both service faces.+Battery input and polarity/ground also deserve prominent identification. Phase+names are primary interface labels, not small component values: their MC/connector+reference can be smaller. Preserve the mapping to the actual terminal nets; never+infer phase order from screen position. Programming/debug labels remain legible but+must not consume the space reserved for power and motor connections. Document any+geometry-driven reduction from the desired hierarchy.+++### Documentation sections are atomic+Board identity, instructions, warnings and service-reference tables must retain semantic sections. Preserve row order, a shared readable alignment, consistent line spacing and a larger heading. Place or resize the whole block; never sort individual lines by length or scatter them on generic center-column anchors. Bottom blocks align in the actual bottom-face reading orientation. Keep reference tables supplementary to labels beside physical connectors. Report an unresolved section rather than silently disassembling it. Replay one section at a time and expose its text heights.++Documentation blocks default to left-aligned visible glyphs, not merely aligned calculation boxes. Use the readable left edge on both faces, including bottom reflection. The dashboard must not recenter a shorter font rendering inside the EDA-measured box. Native exports may use equivalent centered anchors computed from measured glyph bounds, provided the actual ink shares the left edge.++### Visual consistency across connector groups+Treat repeated connector labels as a designed row or column. Prefer shared outer border rails, common widths/heights, padding, reference/value hierarchy and consistent spacing. Solve these at group level before independent placement. Reserve actual strokes against holes, masks and bodies. Never stretch borders after collision checks. Use consistent safe clearance gaps where needed; report any individual inside placement or sizing exception. Apply semantic importance first: ESC PHASE A/B/C are prominent functional labels. Documentation sections retain ordered, left-aligned text and headings rather than scattered rows.++Pin-label alignment is target-facing, not universally centered: right-align ink for labels left of their pad, left-align for labels right of their pad. Evaluate this in the visible face orientation, reversing it for the bottom view. Store the electrical target and alignment intent, keep measured native bounds, and avoid wasted visual gap between ink and the pad. Center only when it improves an intentionally symmetric group.+++## Final documentation and priority review+Prefer readable documentation blocks in open board interior, not crowded rim space. Include a verified description of what the board does, based on its project wiki/spec. Physical connector, test-point and contact labels remain local on both faces. Check interior alternatives across readable sizes before using an edge fallback; reflow coherent sections around holes, never scatter their sentences. Preserve left-aligned visible text, heading hierarchy and ordered rows. Record reasons and selected font heights. The complete priority/pass checklist is in AI Flow `docs/silkscreen-priority-pass.md`; its ordered requirements apply before native DRC and both-view visual acceptance.+@@ -1,83 +1,140 @@⋯ 80 unchanged lines ⋯ - `finish` is the only thing that ends a run. A run without `finish` is not a result, and its minutes are still counting. - KiCad drops pour islands that touch nothing: a heat spreader drawn across dense routing on the other layer fills as fragments and reads small in `measure`. Put the copper where the layer is actually free (the analysis numbers say when it is not). - 0.1's analyses are conservative heuristics (IPC-2221 for tracks, presence, connection style and vias for pours and tabs); they say so in their output. 0.2 computes cross-sections through the filled copper.++## Component coverage before placement++The early `components` step audits component identity, library coverage and model quality before `models` and placement. Run `plan` to read its ordered sourcing workflow. Inventory every reference on the actual board and schematic, and track exact manufacturer/MPN, supplier code, package and required ratings. Reuse exact wiki component pages first; check their assets rather than assuming a page contains a complete CAD bundle. Use `adom-parts-search` next and manufacturer/distributor sites for gaps. Pup is the browser fallback for JavaScript or blocked curl/fetch downloads; read its skill for current commands.++Publish missing identified component pages with verified symbol/footprint/model assets and provenance; improve existing pages instead of duplicating them. Do not invent identities for generic land patterns, DNP parts or bare copper test pads, or silently substitute a similar part. Record unresolved identities and missing assets separately. Generated/approximate bodies must be labelled. Keep model paths portable, preserve layout, rerun `kicad_model_check`, and visibly inspect native KiCad 3D before calling model coverage complete. The AI performs this sourcing audit; these instructions do not add an automatic sourcing or component-identity gate.++Global component pages serve ALL ADOM USERS. Publish only distinct reusable manufacturer parts or independently specified reusable custom components, after duplicate checking. Keep page titles and assets part-focused and portable. Board reference mappings, unresolved identities, one-off footprints, bare copper features and project-only assemblies belong in the board project wiki page, not new component catalog entries. Do not turn project-specific placeholders into generic-looking pages merely by renaming them.++## Early component quality and optional MPN marking++Before placement, declare `step components` and run `components` with your `--run` and `--ai-thread`. It writes `components.json`, inventories every board reference and preserves review notes on rerun. This is an AI review register, not an automated geometry or licensing certification. Record wiki links, classification, dimensions, terminals, pin-1/polarity, plain/marked variants, top/bottom/oblique visual evidence and redistribution evidence. Unknowns remain unknown.++Use manufacturer drawings and permitted CAD as reference checks. Third-party downloads may be private reference-only; never redistribute them without permission, or call extracted/recolored/etched geometry independently authored. Compare independently generated geometry with dimensional and visual evidence. Publish only reusable assets on global pages; board-only definitions stay in the project.++Offer `components --etch on` or `--etch off` (initial default `ask` is not consent). Discover adom/adom-chip-laser and the current STEP engine. Keep the plain model; cache a separate MPN-marked STEP, GLB and reviewed thumbnails when enabled, with input hash, generator version/parameters, text/mode and native-render evidence. Protect pin-1, polarity and functional features. Marking is an identification aid, not a claim of real factory markings. Do not regenerate a valid shared cache, and do not claim KiCad/Fusion/Altium parity until each named viewer was checked.++## Provenance is required for shared component assets++Creating a new global component page is optional; truthful per-file provenance is required when publishing or improving one. Reuse and improve existing pages first. Keep board-only definitions in the board project. Add a readable provenance section and machine-readable asset record, linked prominently from the component README (including HTML READMEs without removing their existing content).++For every symbol, footprint, STEP, GLB and optional marked variant, record the source URL/file/revision and retrieval time, source and output SHA-256, authoring classification (manufacturer-supplied, source-derived, AI-created, or unknown), generator and version, parameters, units, transforms, modifications, redistribution evidence, checks performed and unresolved limits. A hash proves file identity, not quality or permission. Existing wiki availability alone does not establish upstream authorship or rights.++For AI-created geometry, explicitly say it is AI-created and identify the datasheet page/figure/table, dimensional numbers and assumptions used by the generator. Publish the generator or reproducible parameters, disclose simplifications, and distinguish independent geometry from a converted/extracted reference. Keep restricted reference CAD private; document what the comparison tested and did not test. Preserve the lineage from plain input to marked STEP to GLB, including full marking text/mode.++Link to the component page's issue tracker and ask reviewers to include the filename/hash, disputed dimension or pin, source evidence, EDA/version and screenshot. Never fill provenance gaps with plausible guesses. Unknown origins and failed or missing validation remain visible until supported by evidence.++## Optional live progress++Offer the Hydrogen progress widget at intake; default off unless requested. Use `widget enable`, then open AI Flow progress in Hydrogen Widgets. Reuse saved milestone PNGs through `widget event --file <inside-run image> --label <milestone>`; the service also follows saved ledger artifacts and step changes. Use it for component models, longest-axis MPN variants, symbols, placement, pours and Fields. `widget disable` stops updates and thumbnail work. No AI calls or extra captures are required; the progress bar counts planned steps, not remaining time. See widgets/README.md.++## Keep both native views current after every update++After EVERY board, footprint, silkscreen, library-binding or 3D-model update, update BOTH the native 2D board editor and its associated 3D viewer before reporting or showing the result. A file write, successful transfer, DRC result or web preview is not a refreshed native view. Verify the exact saved board path/revision in the editor, then regenerate/reload the 3D view and inspect the changed features after painting settles. Capture evidence from both exact windows; confirm models, markings and layer visibility, not only the window titles.++Use supported native refresh/reload commands through the owning EDA bridge. If an offline edit or model cache requires closing and reopening, inspect unsaved changes and dialogs first, preserve user work, close only task-owned stale windows, reopen the latest board, and open its linked 3D viewer. Never save stale editor contents over a newer disk revision. Keep one current editor/viewer pair rather than accumulating old windows. Re-discover HWNDs after reopening; preserve the user's foreground and view preferences unless showing a view was requested. Refresh a completed edit or coherent batch promptly; do not wait until the final video. If either view cannot be verified, state which one remains stale and resolve it before claiming the update is shown.++## Shared component artwork and label placement++Read `eda-component-hero` and `eda-led-appearance` from `adom/eda-engineering` before creating or revising component heroes or LED variants. The existing wiki-component contract remains applicable. Use `hero-check --source <original.glb> --glb <hero.glb> --evidence <overlay.json> --out <check.json>` for source-preservation and structural checks, then perform the published visual review. Never put hero-only footprint helpers in board model files.++For silkscreen, read `docs/silkscreen.md`: measure native stroke bounds, search and repack before shrinking, preserve ref/value association and per-face pin positions, and treat 0.2 mm as exceptional. `silkscreen-layout` runs the shared candidate search; `tools/silkscreen-leaders.py` can reserve leader routes first. Native edits and verification belong to the bridge.++### Complete obstacle coverage is required++Before placing or accepting silkscreen, enumerate every fitted model, via and drilled hole across the entire board, on both faces. Record coverage counts and stable IDs. A local search region does not excuse leaving the rest of the board unchecked. Project the actual fitted 3D model into the board plane with its scale, offset, rotation and footprint transform; include overhangs. Conservative transformed model bounds are acceptable when a tighter silhouette is unavailable. F.Fab, courtyard or pad envelopes are fallbacks, not proof of fitted-body coverage: a footprint can have no Fab drawing, and the space between separated pads can still be occupied by the body. Missing model geometry must be reported and supplied a documented conservative envelope, never a tiny placeholder that silently allows text beneath the component.++Reserve every via hole on both faces, including tented vias when visible labeling is the requirement, and use the larger of the hole keepout and actual exposed mask opening. Also reserve through holes, slots, exposed pads and existing silk. Check actual stroked text extents, not just its anchor. After each re-layout, audit ALL existing labels and leaders against this complete obstacle set. A collision-free position is not enough: keep each reference/value next to its own component or add a clear, noncrossing leader. Do not move a label beside a different component merely to clear an obstacle. Native DRC and fitted 3D visibility are separate acceptance checks; a DRC baseline does not establish readable assembled silkscreen. Refresh and inspect both native 2D and 3D views before presenting the result.++## Optional live silkscreen dashboard++Offer `silkscreen-dashboard show` with the run and ai-thread flags. The shared observer renders real timestamped solver events, sampled candidate bounds and reasons, selected proposals and unresolved labels, in 2D and a fitted-model 3D preview. `silkscreen-layout --events <run>/silkscreen-dashboard/events.jsonl` emits these without AI/provider calls or deliberate solver pauses. Read `tools/silkscreen-dashboard/SKILL.md` for the manifest, transform limits, lifecycle and recording contract. Live and replay are visibly distinct; replay exports are not raw native CAD footage. Selected proposals remain unverified until native application, DRC and assembled visibility checks pass. Fusion/Altium adapters are not implemented merely because the manifest is tool-neutral.+++## Final documentation and priority review+Prefer readable documentation blocks in open board interior, not crowded rim space. Include a verified description of what the board does, based on its project wiki/spec. Physical connector, test-point and contact labels remain local on both faces. Check interior alternatives across readable sizes before using an edge fallback; reflow coherent sections around holes, never scatter their sentences. Preserve left-aligned visible text, heading hierarchy and ordered rows. Record reasons and selected font heights. The complete priority/pass checklist is in AI Flow `docs/silkscreen-priority-pass.md`; its ordered requirements apply before native DRC and both-view visual acceptance.+@@ -0,0 +1,83 @@+# Silkscreen dashboard++An optional, EDA-neutral observer of placement candidates and recorded solver decisions. It makes no AI/provider calls and never edits a native board. Native geometry, text metrics, undoable edits and 2D/3D refresh belong to each EDA bridge. The ESC integration currently exports KiCad geometry; Fusion and Altium adapters still need implementation and native tests. Do not claim those integrations work from schema compatibility alone.++## Displaying this app (REQUIRED — read before showing anything)++Use `adom-aiflow silkscreen-dashboard show --ai-thread "<name>" --run <run>` to open the named Hydrogen webview. Never use VS Code Simple Browser. `--surface pup` requires an explicit desktop `--target` and desktop-reachable `--url`. Keep standard workspace navigation. Reuse the same run/thread instance; `ls` shows instances and version drift.++## Inputs and live observation++Place `board.json` and an append-only `events.jsonl` in `<run>/silkscreen-dashboard/`. These are separate artifacts; never edit the measurement ledger `run.jsonl`. The board manifest has `bounds` in mm, `labels`, `obstacles`, `viaCount`, source-board identity and validation state. Each label carries text, x/y, size, angle, face and an optional existing-collision flag. Each obstacle carries a stable reference, kind, layer and conservative world-space box. Model obstacles may additionally supply a relative GLB URL, footprint `at` in KiCad XY/degrees, model offset and height. This initial 3D adapter supports top-mounted, unit-scale models without separate model rotations; bake other transforms into the supplied GLB or refuse the preview. The viewport's board slab is an envelope, not a manufactured-board export; pads, routed copper and drilled geometry are not yet native-equivalent. Keep that distinction visible.++`adom-aiflow silkscreen-layout --input candidates.json --out layout.json --events <run>/silkscreen-dashboard/events.jsonl --run <run> --ai-thread "<name>"` emits timestamped start, sampled candidate, selected proposal, unresolved and completion events with a solve ID. Events are generated by real computation, not invented for a film. Candidate samples are bounded: this is not every internal solver iteration. Pre-filtered inputs cannot reconstruct prior rejected candidates. The event reason describes the observable constraint/result, not private internal reasoning.++SSE updates do not reload the DOM. Live follows new events; replay has shared play/pause, scrub and speed controls. Playback is independent of solver speed. A selected proposal is not a native edit. Native application/DRC/assembled-visibility evidence must be recorded separately; the dashboard never promotes proposal success into native acceptance.++## Recording++Record replay exports a WebM of the 2D canvas with a persistent REPLAY label and the current recorded decision. Detailed review and a short final-video segment are separate artifacts. Preserve original event timestamps and raw native per-step clips. Do not call replay footage a live native edit or a KiCad recording. Verify the exported video actually plays. The browser-font preview does not replace KiCad's measured stroke-font geometry. Final-video pacing should not force the solver to sleep or trigger extra AI calls for every label.++## Acceptance++Audit the whole board on both faces: fitted body projections including the area between pads, every via/hole, actual mask openings, labels and leader paths. Missing Fab geometry is not empty space. Keep each label associated with its own component. Unresolved labels remain visible and block acceptance. The independent inventory in `silkscreen-audit` must be derived from the whole board, not from the same potentially incomplete obstacle list.++## Automated recording++Use `adom-aiflow silkscreen-dashboard control --json '{"record":"overview"}' --run <run> --ai-thread "<name>"` (or `walkthrough`). An open dashboard records through the same UI path and uploads the completed WebM into `<run>/silkscreen-dashboard/recordings/`; read `state.lastRecording` for the path. A queued request is not a completed clip. Verify nonempty decoded frames and visible replay/native-review status. Normalize WebM with ffmpeg `fps=30` before H.264 composition; MediaRecorder can report a 1000 Hz nominal rate. Keep each wiki asset below its cap.++## Full-board silkscreen review++A full placement demonstration starts with no authored labels in the candidate occupancy, then attempts every required label. Reuse text content, native glyph metrics and electrical anchors, not earlier accepted positions. Preserve unresolved attempts and subsequent rework in the event history. Front and back are separate collision/placement passes in one run. Filter candidates, selected labels, leaders and playback events by the active face; never overlay the opposite face during a recording.++Show the active label's native text height in millimetres, including distinct reference/value sizes. Maximize readable size near its physical feature; 0.20 mm is a last-resort InstaPCB value, not a default. Prefer short curved leader lines whenever contact/pin association is unclear. Route leaders to the feature's visible rim, keep them off holes, pads, bodies and other text, and verify both faces in the native EDA. Include leaders as actual placement/rework events.++Record each face as a 1920x1080 detailed replay with an explicit replay label. End the review video with the same revision in the user's native EDA, including top and bottom inspection. A dashboard preview or API success is not proof of a faithful native transfer. Keep native raw clips separate from captioned/replayed dashboard clips.++### Face orientation and label hierarchy+- Show bottom placement from below: reflect board geometry, pad positions, obstacles, leaders and label anchors together; keep lettering readable. Do not display unmirrored bottom text on unchanged top-view geometry. State the viewing direction alongside the face name in the dashboard and video.+- Use distinct face colors plus explicit F.SilkS/B.SilkS text; color alone is insufficient.+- Place each component reference and value as a group: the reference has priority and is larger; the value is mandatory and visibly smaller. A count of placed text objects does not prove this hierarchy or readability.+- Treat machine contacts, machine pins and connector pin labels as structured groups. Preserve ordered pin mapping, nearby placement and clear curved leaders when needed; compare against the previous native layout before accepting a fresh solve.++- 2D wheel/trackpad zoom must preserve the board point beneath the pointer, including aspect-fit margins and bottom-face reflection. Manual zoom or pan cancels camera animation and disables automatic follow until the user enables it again.++- Rendering contract: only manufacturing silkscreen is solid and fully opaque. Calculation-only text bounds, keepouts and obstacle outlines use dashed strokes at approximately 50% opacity, with an explicit legend. Never make a debug bounding box look like a printed enclosure. Captured footage must preserve the distinction.++### Machine-contact grouping (default on)+Prefer the label on the board-edge side of each machine contact, machine pin or edge+connector. Determine that direction in physical board coordinates from the nearest+outline edge, independent of whether the viewer is showing top or bottom. Keep a+column on the same side where feasible, preserve physical pin order, and use an+inside fallback only when the outside cannot fit collision-free. Explain fallbacks.++By default reserve a printed frame around each contact plus its larger reference and+smaller function/value. `contactBorders: false` / `--no-contact-borders` disables+these frames without disabling the outside-first policy. Borders are placement+geometry, not decoration added after the solve. Check their full stroke against+holes, mask openings, existing artwork, text and the board edge. A frame may have+small, explicitly reported clearance gaps; never draw across a hole to close it.+Display printed frames as solid; calculation bounding boxes remain dashed at 50%.++Before solving, perform a board-specific interface importance pass. For ESCs, give+verified PHASE A/B/C motor terminals conspicuously larger connection labels (target+1.0–1.4 mm when space allows) and prioritize battery input, polarity and ground.+A functional terminal name can outrank its MC reference; component values remain+smaller than their component references. Record the chosen semantic priorities in+the input and event explanation, then reserve those groups before secondary notes.+++### Documentation sections are atomic+Board identity, instructions, warnings and service-reference tables must retain semantic sections. Preserve row order, a shared readable alignment, consistent line spacing and a larger heading. Place or resize the whole block; never sort individual lines by length or scatter them on generic center-column anchors. Bottom blocks align in the actual bottom-face reading orientation. Keep reference tables supplementary to labels beside physical connectors. Report an unresolved section rather than silently disassembling it. Replay one section at a time and expose its text heights.++Documentation blocks default to left-aligned visible glyphs, not merely aligned calculation boxes. Use the readable left edge on both faces, including bottom reflection. The dashboard must not recenter a shorter font rendering inside the EDA-measured box. Native exports may use equivalent centered anchors computed from measured glyph bounds, provided the actual ink shares the left edge.++### Visual consistency across connector groups+Treat repeated connector labels as a designed row or column. Prefer shared outer border rails, common widths/heights, padding, reference/value hierarchy and consistent spacing. Solve these at group level before independent placement. Reserve actual strokes against holes, masks and bodies. Never stretch borders after collision checks. Use consistent safe clearance gaps where needed; report any individual inside placement or sizing exception. Apply semantic importance first: ESC PHASE A/B/C are prominent functional labels. Documentation sections retain ordered, left-aligned text and headings rather than scattered rows.++Pin-label alignment is target-facing, not universally centered: right-align ink for labels left of their pad, left-align for labels right of their pad. Evaluate this in the visible face orientation, reversing it for the bottom view. Store the electrical target and alignment intent, keep measured native bounds, and avoid wasted visual gap between ink and the pad. Center only when it improves an intentionally symmetric group.+++## Final documentation and priority review+Prefer readable documentation blocks in open board interior, not crowded rim space. Include a verified description of what the board does, based on its project wiki/spec. Physical connector, test-point and contact labels remain local on both faces. Check interior alternatives across readable sizes before using an edge fallback; reflow coherent sections around holes, never scatter their sentences. Preserve left-aligned visible text, heading hierarchy and ordered rows. Record reasons and selected font heights. The complete priority/pass checklist is in AI Flow `docs/silkscreen-priority-pass.md`; its ordered requirements apply before native DRC and both-view visual acceptance.+@@ -1,162 +1,243 @@ { "name": "board", "title": "The board flow: parts placement to a qualified board",- "scope": "Starts at the 3D models and parts placement on a board whose schematic, libraries and part choices already exist. Ends when the board is 100 percent routed, DRC-clean, poured, its copper measured, its current and thermal analyses passed, its nets and its 3D view walked through on camera, and the AI has delivered the video.",+ "scope": "Starts with component identity, reusable CAD review and native library assembly for an existing schematic/board. Reviews the selected model variants on camera before placement, then routes, pours, analyzes and delivers a bounded final video.", "steps": [ { "name": "intake", "who": "ai",- "does": "read the board and the spec, write the spec from the schematic if it is missing, plan",- "record": "nothing on screen yet: the clip is the board opening on the test box (capture open) and the spec being read"+ "does": "read the board and the spec, write the spec from the schematic if it is missing, plan; offer the optional Hydrogen progress widget (default off; enable when requested), reusing saved milestone images without extra AI calls",+ "record": "nothing on screen yet: the clip is the board opening on the test box (capture open) and the spec being read",+ "workflow": [+ "After EVERY board or model update, refresh and verify BOTH the native 2D editor and its linked 3D viewer before showing/reporting completion. Check exact saved board revision and actual rendered changes in both windows. Reload cached models; if reopening is required preserve unsaved user work, close only task-owned stale windows and retain one current editor/viewer pair. Never overwrite a newer disk edit from a stale editor. Use native bridge controls and keep foreground preferences."+ ] }, {+ "name": "components",+ "who": "ai",+ "does": "Audit wiki component identity, reusable CAD quality and redistribution evidence before placement; offer cached optional MPN-marked variants.",+ "binary": [+ "components"+ ],+ "workflow": [+ "Inventory every reference from the actual board and schematic: manufacturer, MPN, supplier code, package, value and ratings; group repeated exact parts and record their references. Do not invent an MPN or silently substitute a similar value/package. Distinguish populated parts, DNP parts and bare copper/mechanical features; a bare test pad needs no purchased component or fictitious 3D body.",+ "Search the wiki FIRST for each exact manufacturer/MPN and supplier code; reuse the matching component page and inspect its symbol, footprint and STEP/WRL assets. A page existing is not proof its CAD bundle is complete. Record the page URL and missing assets per reference.",+ "For missing identities or assets, use adom-parts-search next, then original manufacturer and distributor websites. Use Pup to navigate and download through the automated browser when curl/fetch is blocked or the site requires JavaScript; do not treat a blocked fetch as proof the part is unavailable. Read the relevant parts-search and Pup skills for current commands.",+ "Verify manufacturer, exact ordering code, package dimensions, pin numbering and required electrical ratings against source evidence before accepting CAD or a candidate part. Preserve source URLs and provenance. Label generated or approximate models as such; never present an approximate body as a verified vendor model.",+ "Global component pages are shared resources for ALL ADOM USERS, never a board-specific BOM dump. Create one only for a distinct reusable manufacturer part or independently specified reusable custom component, after searching for duplicates. Write a part-focused page with portable verified assets and provenance, and improve existing pages. Keep board references, unresolved identities, one-off land patterns, bare copper test pads and project-only assemblies inside the board project wiki page; do not create catalog placeholders or rename a one-off feature to make it appear global.",+ "Use portable project/library model paths, preserve placement and routing, rerun kicad_model_check and inspect the saved board in native KiCad 3D. Report reference coverage, reused/created page URLs, unresolved identities and missing CAD separately. A successful download or wiki publication alone does not close a missing-model finding.",+ "Judge quality per component, not per board screenshot: publish a linked visual register with top, bottom and oblique views. Check dimensions, units, terminal count and pitch, pin-1/polarity, body/pad alignment, standoff, materials and visible details. File resolution alone is not quality. Record pass, needs-work, reference-only or unknown with evidence and limits.",+ "Prefer manufacturer CAD when the source permits the intended redistribution. Keep third-party/Ultra Librarian downloads as private reference-only inputs unless redistribution is explicitly permitted. Compare independently generated models against manufacturer drawings and permitted reference views; retain dimensional deviations and source hashes. Converting, extracting, recoloring, or etching a restricted model does not make it independently authored or license-cleared.",+ "Offer optional MPN marking using adom/adom-chip-laser or the current adom-step2glb laser-etch service. Ask whether to enable it; default to unmarked models until the user chooses. Check the shared page cache first. Preserve the plain STEP and publish an additional marked STEP, derived GLB and reviewed thumbnails only for assets eligible for redistribution. Keep the mark clear of pin-1, polarity, terminals and optical/mechanical features. Marking is an identification aid, not evidence of actual factory top-marking, especially on tiny passives.",+ "Cache reviewed artifacts on the existing global component page: source/plain STEP, optional MPN STEP, GLB, thumbnails and machine-readable provenance. Record input hash, generator/tool version, parameters, units, transforms, marking text/mode, reference evidence and review results. Cache keys must change when geometry, text or generator parameters change. Keep board-only transforms and mappings in the board project. Never claim cross-EDA parity without rendering the variant in the named native viewers.",+ "When publishing or improving a component page, make per-file provenance mandatory even though creating a new page is optional. Record original source URL/file and revision, retrieval date, source and output SHA-256, authoring classification (manufacturer-supplied, source-derived, AI-created, or unknown), generator/version and parameters, units/transforms, redistribution evidence and limitations. For AI-created geometry cite the actual datasheet page/figure/table and dimensions used, list simplifications and reference comparisons, and never present copied/extracted CAD as independent work. State which checks ran and which remain unverified; retain plain and marked variant lineage. Put a readable provenance section on the page plus a machine-readable asset record and a link to that component's issue tracker. Unknown provenance stays unknown, not a fabricated source. Reuse/improve existing pages first; offer new global-page publication only for reusable components, keeping board-specific records in the project.",+ "For optional MPN marking, fit the text along the longest usable top-face direction with the largest legible size, respecting pin-1 and mechanical features. Compare both orientations and retain the package coordinate frame. Cache and identify the marked variant explicitly.",+ "Offer the optional Hydrogen progress widget. If enabled, reuse saved component, marked-model, symbol and later board/analysis thumbnails via widget event; do not generate extra screenshots or call a model solely for the widget. Respect widget disable immediately.",+ "Before accepting a wiki component, read its actual native model_3d and STEP bindings and hash the referenced downloads against the reviewed variants. Wait for the native viewer to finish painting, then inspect the visible body and readable mark; nonzero meshes or a successful HTTP request do not prove a painted model. Check the static hero too. Use a descriptive manufacturer/MPN/function title in both page.json and package.json; follow wiki-component and preserve other contributors and original files.",+ "A resolved 3D file may still be hidden by native EDA appearance filters (for example KiCad excludes models not in position files). Check those filters before inventing replacement parts or changing BOM/placement flags. Keep bridge-specific visibility, binding and native audit operations in the owning bridge; report missing capabilities there. Explicit rights-holder permission may authorize a derivative despite a restrictive package default; record who authorized what and its scope, without extending it to third-party assets.",+ "Read eda-component-hero and eda-led-appearance from the shared EDA skillpack. Component wiki heroes need separate nonphysical teal dashed COPPER boundaries (alpha 0.50), actual silk (0.30), and mapped signal labels (0.50); preserve physical pin1, MPN, animations and lights. Keep board-use models clean. Run hero-check --source <original.glb> --glb <hero.glb> --evidence <overlay.json> --out <check.json>, then inspect published top/underside/pin1 and native LED surfaces. Raised LED skins must have verified non-coplanar clearance, including the MPN; STEP color is not a light. Record source, footprint, pin map, font and generator hashes. Never claim structural checks establish visual or electrical qualification."+ ]+ },+ {+ "name": "libraries",+ "who": "ai",+ "does": "Assemble and validate the reviewed symbols, footprints and selected model variants in the chosen EDA before placement.",+ "workflow": [+ "Use the components register to build a portable project library for the actual EDA (KiCad, Altium or Fusion). Verify symbol pin numbers against footprint pads, package dimensions and pin-1/polarity; resolve model transforms and selected plain or marked STEP paths. Record native tool/version and evidence per part.",+ "Keep board reference mappings and native project transforms in the board project, while reusable source CAD and provenance remain on their existing global component pages. Do not claim native EDA support from a GLB gallery or a file extension alone.",+ "Return to components with --back --why when identity, rights or geometry cannot be resolved; preserve honest unknowns and report the affected references."+ ],+ "record": "Native library review with the selected symbol, footprint and model; saved verification evidence belongs with the library register."+ },+ { "name": "models", "who": "ai",- "does": "every footprint on the board has its 3D model resolved (kicad_model_check): fetch the vendor STEP, build one, or fix the path, so the board renders as it will be built; a bare footprint in the 3D view is a missing model",+ "does": "Check native board model resolution and inspect the selected library variants in the chosen EDA; use the component register for unresolved assets.", "binary": [ "models" ],- "record": "nothing to film: the model check's list and the fixes; the 3D walkthrough later is the proof"+ "record": "Native board 3D inspection and model-check evidence; the separate library-tour step reviews each selected component.",+ "workflow": [+ "Use the components register and its reviewed plain or explicitly selected marked variants; fix portable model paths, run kicad_model_check, then inspect the native board render. Do not substitute a model merely to make the missing-file gate pass.",+ "After EVERY board or model update, refresh and verify BOTH the native 2D editor and its linked 3D viewer before showing/reporting completion. Check exact saved board revision and actual rendered changes in both windows. Reload cached models; if reopening is required preserve unsaved user work, close only task-owned stale windows and retain one current editor/viewer pair. Never overwrite a newer disk edit from a stale editor. Use native bridge controls and keep foreground preferences.",+ "Read eda-component-hero and eda-led-appearance from the shared EDA skillpack. Component wiki heroes need separate nonphysical teal dashed COPPER boundaries (alpha 0.50), actual silk (0.30), and mapped signal labels (0.50); preserve physical pin1, MPN, animations and lights. Keep board-use models clean. Run hero-check --source <original.glb> --glb <hero.glb> --evidence <overlay.json> --out <check.json>, then inspect published top/underside/pin1 and native LED surfaces. Raised LED skins must have verified non-coplanar clearance, including the MPN; STEP color is not a light. Record source, footprint, pin map, font and generator hashes. Never claim structural checks establish visual or electrical qualification."+ ] }, {+ "name": "library-tour",+ "who": "ai",+ "does": "Review each selected component model in motion and produce a separate short library overview for the final video.",+ "workflow": [+ "Use tools/library-tour.py with the reviewed library.json, --run and --ai-thread. The manifest must identify the same plain or explicitly chosen marked variants and hashes that the native board uses. A marking choice does not authorize silent plain-model fallback.",+ "Inspect the detailed orbit tour and the moving overview in a rendered browser. Reject blank, clipped, wrong-variant or static clips; retain raw recordings and contact sheets. The detailed tour stays separately linked for component review.",+ "Budget approximately five seconds for the moving overview within the entire final video limit of 120 seconds. Do not insert the whole BOM walkthrough or one wiki-page shot per part into the final video. Optional scrolling wiki-page clips belong in the separate detailed review.",+ "Automatic overview selection in released compose requires the complete maintained release source (issue #16); until integrated, report that limitation explicitly and keep the reviewed clips and selection manifest available for integration.",+ "Read eda-component-hero and eda-led-appearance from the shared EDA skillpack. Component wiki heroes need separate nonphysical teal dashed COPPER boundaries (alpha 0.50), actual silk (0.30), and mapped signal labels (0.50); preserve physical pin1, MPN, animations and lights. Keep board-use models clean. Run hero-check --source <original.glb> --glb <hero.glb> --evidence <overlay.json> --out <check.json>, then inspect published top/underside/pin1 and native LED surfaces. Raised LED skins must have verified non-coplanar clearance, including the MPN; STEP color is not a light. Record source, footprint, pin map, font and generator hashes. Never claim structural checks establish visual or electrical qualification."+ ],+ "record": "Two separate raw clips: a detailed component orbit tour and a roughly five-second moving overview. No title pages or baked captions; the final composer supplies its own overlays."+ },+ { "name": "placement", "who": "ai",- "does": "place the parts for routability, current and heat; the binary packs, checks courtyards and lands moves",+ "does": "place the parts for routability, current and heat; the binary packs, checks courtyards and lands moves; reserve visible space for connector labels and the two-sided service silkscreen", "binary": [ "place pack", "place check",⋯ 67 unchanged lines ⋯ "record": "the editor with one net lit at a time, framed; the markers say which net" }, {+ "name": "silkscreen",+ "who": "ai",+ "does": "Make both faces useful in real service: references and values, verified connector and machine-contact pinouts, polarity, board identity and bring-up labels; review native plots and assembled visibility. Offer the optional shared silkscreen dashboard: real solver events, candidate reasons, live/replay separation, fitted-model inspection and separately recorded detailed/5s replays. Audit every fitted body and every via/hole across the whole board, both faces, with coverage counts. Missing Fab geometry is not free space; native DRC does not establish fitted visibility. Keep unresolved labels explicit and do not apply an incomplete layout. Native geometry/edit/undo/refresh belongs to the EDA bridge.",+ "workflow": [+ "Read the InstaPCB silkscreen skill for the selected process; reserve label space during placement and finalize after copper and analysis stabilize. Use both faces, a clear font-size hierarchy, and the approved process profile for small secondary text.",+ "Build a source-backed label manifest from actual schematic, pad numbers, nets and approved requirements. Include reference/value pairs, connector pinouts, power polarity, test points, switch/LED functions, revision and documentation link. Never infer voltage/current ratings from net names or component absolute maxima.",+ "For every machine pin, machine contact and edge-pin connector, repeat its reference/pin number and verified signal or power function on BOTH faces. A mounted board may expose only one side during debugging. Put the repeated labels beside the same physical connection where possible; when crowded, use a short clear leader to the actual connection on that face; a remote keyed legend is supplementary only. A pinout table on the other face alone does not satisfy this check. Review both faces in the mounted-access context, with bottom text correctly mirrored and pin numbering preserved.",+ "Every test point MUST have visible silkscreen identifying both its reference and verified net/signal or measurement function. Prioritize these labels before ordinary component values. Keep them adjacent to the accessible probe pad, or use a short unambiguous leader/key on the same accessible face when crowded. Check complete test-point coverage against the actual board; missing or ambiguous labels are unresolved findings, never silently omitted. Repeat on the opposite face when useful for mounted-board debugging, without implying a probe pad exists there.",+ "Keep each reference unmistakably associated with its own component. Prefer reducing reference font size locally over moving a label farther away. Aim for complete reference coverage; use a short clear leader only when proximity alone is ambiguous. Treat approximately 0.8 mm as an initial reference size, not a minimum. For dense InstaPCB artwork Adam explicitly permits secondary values at 0.3 mm or even 0.2 mm (2026-09-16); try 0.5, 0.3 then 0.2 mm while preserving the ref/value pairing and required stroke/spacing. These tiny sizes are user-requested artwork options, not independently verified laser-process capability. Keep the actual sizes and any unresolved physical legibility/DFM limits in the review; do not silently omit labels or globally weaken fab rules. Inspect the result at actual size and close-up.",+ "Avoid mask openings, contact surfaces, holes, fiducials and bodies that hide labels. Inspect bottom mirroring, actual-size legibility and both native 2D/3D faces. Use EDA bridge text/plot/DRC operations; give missing primitives back to the bridge.",+ "Run native DRC against the chosen fab profile and compare with the baseline. Preserve connectivity, placement, copper, outline and model transforms for silk-only edits. Register the label manifest and top/bottom evidence; return here when placements or pinouts change.",+ "Record BEFORE the first silkscreen mutation: show labels appearing individually or in small meaningful groups, pairing references with smaller values. Film actual moves, resizing, rotations and overlap corrections in order; preserve a timestamped operation/reason sidecar and raw uncaptioned footage. Use native bridge edits and refresh, never invented verbs. If native incremental editing is missing, file the bridge gap; identify any checkpoint reconstruction as a replay, never as original live placement. Keep a detailed action cut and use 3\u20135 seconds of accelerated population/rework in the final 120-second film. Read docs/silkscreen.md for recording and evidence rules.",+ "Require positional contact labels on BOTH faces: a pinout table is supplementary, never a substitute for text beside each actual machine contact, machine pin or edge connection. Separate primary reference (MC10) and smaller secondary function (DSHOT) as independently sized paired text. Prefer consistent reading directions. Where association remains ambiguous, add a short gentle curved silkscreen leader ending outside the intended pad mask opening; avoid crossings and obstacles. Verify one-to-one pad association, bottom mirroring, label/leader clearance and legibility in close-up native views and DRC. Film real additions and rework; retain mapping and unresolved constraints. See docs/silkscreen.md.",+ "For the requested InstaPCB profile, attempt a nearby value for EVERY resistor and capacitor, including rotated components and references. Search both orientations and adjacent sides at 0.5, 0.3 and 0.2 mm as needed, preserving an unmistakable reference/value association. Do not skip values merely because the reference is rotated, an initial placement fails, or a bottom table exists. Repack nearby silk or use a clear short leader when necessary. Audit actual-board value coverage and report each unresolved value explicitly; a back-side key is supplementary, not completion. Retain native mask/overlap checks and distinguish requested artwork sizes from measured physical legibility.",+ "After EVERY board or model update, refresh and verify BOTH the native 2D editor and its linked 3D viewer before showing/reporting completion. Check exact saved board revision and actual rendered changes in both windows. Reload cached models; if reopening is required preserve unsaved user work, close only task-owned stale windows and retain one current editor/viewer pair. Never overwrite a newer disk edit from a stale editor. Use native bridge controls and keep foreground preferences.",+ "Search space before shrinking text: 0.2 mm is a last resort. Use native text bounds and per-face body/pad/mask/via/silk obstacles, keep separate boxes for ref/value pairs, repack neighboring labels, preserve pin-row order and validate leader paths. Run silkscreen-layout on candidates; bounded search is not native verification. Apply by stable item ID, compare native DRC with baseline, inspect fitted visibility, and refresh BOTH native views. See docs/silkscreen.md."+ ],+ "record": "Native incremental label population on both faces, individual ref/value pairs or meaningful groups, plus real rework. Raw uncaptioned clip and timestamped edit sidecar; detailed action cut separate from the 3\u20135 second final-video excerpt. Clearly label reconstructed replay.",+ "hints": [+ "Final documentation pass: prefer open interior regions for a verified board description and ordered left-aligned service blocks. Physical pin/contact labels remain local. Apply docs/silkscreen-priority-pass.md; inspect interior alternatives at readable fonts and report explicit edge fallbacks. Native Rust silkscreen-sections performs the documentation solve; preflight, native DRC and both EDA views still gate acceptance."+ ]+ },+ { "name": "3d", "who": "binary", "does": "the 3D walkthrough: the viewer opened from the editor, then fit, top, tilt, orbit, zoom in, swing, front, bottom, flip, top, fit, all by menu command, no mouse", "binary": [ "tour 3d" ],- "record": "the 3D Viewer window itself: the board turning, the components up close; full of motion, so the action cut keeps most of it"+ "record": "the 3D Viewer window itself: the board turning, the components up close; full of motion, so the action cut keeps most of it",+ "workflow": [+ "After EVERY board or model update, refresh and verify BOTH the native 2D editor and its linked 3D viewer before showing/reporting completion. Check exact saved board revision and actual rendered changes in both windows. Reload cached models; if reopening is required preserve unsaved user work, close only task-owned stale windows and retain one current editor/viewer pair. Never overwrite a newer disk edit from a stale editor. Use native bridge controls and keep foreground preferences."+ ] }, { "name": "capture",⋯ 21 unchanged lines ⋯ "returns": "any step may send the AI back to any earlier step: step <name> --back --why \"...\"", "later": [ {- "name": "components",+ "name": "part-selection", "does": "choose the parts from the requirements; SPICE may send the AI back here" }, {- "name": "libraries",- "does": "symbols, footprints, 3D chips for every part"- },- { "name": "schematic", "does": "the schematic, and the spec that falls out of it" },⋯ 17 unchanged lines ⋯ "clips": "every `step <name>` stops the previous step's clip and starts a new window recording tagged with the step, when the board is open on a test box; run.json captures[] carries one entry per clip with its step, start, stop and file, and deliver lists them; the final video is cut from these clips, one segment per step, so two engines' videos line up step for step; a return (step <name> --back --why) is a new visit and gets its own clip, tagged <step>-<visit> with the reason, so the rework is on camera and the final cut can show the loop", "screenshots": "every step visit gets two background screenshots of the editor window, at its start and at its end (shot-<step>-<visit>-start.png, shot-<step>-<visit>-end.png), logged as artifacts, so a run's own README has a picture for every step without anyone taking one" }+
Comments
Log in to comment.
No comments yet.