← Commit history

Preserve physical-pad current boundaries and repair component hero guidance (0.1.83)

John Lauer ·3c93dc160c · ·parent c21c717
10 files changed +62−20
Cargo.lock+10−10
@@ -4,7 +4,7 @@ version = 4  [[package]] name = "adom-aiflow"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-analyze",  "aiflow-board",@@ -24,7 +24,7 @@ dependencies = [  [[package]] name = "aiflow-analyze"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "serde",@@ -34,7 +34,7 @@ dependencies = [  [[package]] name = "aiflow-board"-version = "0.1.82"+version = "0.1.83" dependencies = [  "roxmltree",  "serde",@@ -43,7 +43,7 @@ dependencies = [  [[package]] name = "aiflow-bridge"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "serde",@@ -52,7 +52,7 @@ dependencies = [  [[package]] name = "aiflow-copper"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -62,7 +62,7 @@ dependencies = [  [[package]] name = "aiflow-grid"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "serde",@@ -71,7 +71,7 @@ dependencies = [  [[package]] name = "aiflow-place"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "serde",@@ -80,7 +80,7 @@ dependencies = [  [[package]] name = "aiflow-pours"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "aiflow-copper",@@ -90,7 +90,7 @@ dependencies = [  [[package]] name = "aiflow-router"-version = "0.1.82"+version = "0.1.83" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -100,7 +100,7 @@ dependencies = [  [[package]] name = "aiflow-run"-version = "0.1.82"+version = "0.1.83" dependencies = [  "serde",  "serde_json",
Cargo.toml+1−1
@@ -14,7 +14,7 @@ members = [ ]  [workspace.package]-version = "0.1.82"+version = "0.1.83" edition = "2021" license = "MIT" repository = "https://wiki.adom.inc/adom/adom-aiflow"
SKILL.md+5−1
@@ -293,7 +293,7 @@ Use supported native refresh/reload commands through the owning EDA bridge. If a  ## 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.+Before creating or revising component heroes, read the current `component-hero` skill from `adom/component-hero` and the `wiki-component` contract. Use its deterministic `scripts/hero_glb.py` generator with the clean board-use GLB, real footprint and component pin map; inspect its alignment report and overlay sidecar, then verify the published viewer. Older references to `eda-component-hero`, `eda-led-appearance` or an unverified `hero-check` executable may be stale: discover the current owning package rather than stopping or inventing a command. For LED variants, also follow the component state and appearance requirements in the current wiki-component guidance. 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. @@ -389,3 +389,7 @@ For native saved-board experiments, preserve a UUID-to-net map before and after AIFlow independently checks every declared hot part against its `maxRiseC` (or `hotMaxRiseC`) and any `maxThetaCPerW`, using matching watts and tab net. Both thermal solves must converge and report finite temperatures. A global Fields issue list cannot hide a tighter part limit. Existing chip summaries round to 0.1 C, so acceptance reserves 0.05 C for reporting precision; do not round a boundary value into a pass. Moving-air results do not waive the still-air check.  Derive continuous heat cases from the actual voltage/current/power envelope and keep overload/conductor screens separate. Do not lower a limit to advance the workflow. Package-to-heatsink transfer, sensor lag, airflow and physical qualification still require their own evidence.++### Repeated physical pads in explicit current boundaries++When multiple physical lands share one logical pin number, use the reviewed Fields physical-pad selector (`at: [x_mm, y_mm]`, adom/adom-fields PR10 and dependencies). Declare each branch current and its assumption; never silently divide the load to obtain a pass. AIFlow matches each reported physical boundary once, including its coordinates, and refuses missing/changed selectors. Recheck coordinates after moving a footprint. Preserve owner review and shared runtimes; source support is not a deployed release or package-resistance model.
bin/adom-aiflow
⋯ 1 unchanged line ⋯
crates/aiflow-analyze/src/lib.rs+31−2
@@ -320,8 +320,18 @@ pub fn field_screen(fields: &Value, spec: &Value, board_bytes: &[u8], spec_bytes                 if terminals["mode"] != "explicit" { return Err(format!("Fields {name} used heuristic terminals; solve the declared explicit pins")); }                 let wanted = value["terminals"].as_array().ok_or("branch model has no terminal array")?;                 let actual = terminals["pins"].as_array().ok_or("Fields has no explicit terminal pins")?;-                if wanted.len()!=actual.len() || !wanted.iter().all(|w| actual.iter().any(|a|a["reference"]==w["reference"] && a["pad"]==w["pad"] && a["amps"].as_f64()==w["amps"].as_f64())) {-                    return Err(format!("Fields {name} terminal assignments differ from the branch model"));+                let mut matched = vec![false; actual.len()];+                let same_boundary = wanted.len() == actual.len() && wanted.iter().all(|w| {+                    let found = actual.iter().enumerate().position(|(i, a)| !matched[i]+                        && a["reference"] == w["reference"] && a["pad"] == w["pad"]+                        && a["amps"].as_f64() == w["amps"].as_f64()+                        && a["at"] == w["at"]+                        && (w["at"].is_null() || w["at"].as_array().is_some_and(|xy|+                            xy.len() == 2 && xy.iter().all(|v| v.as_f64().is_some_and(f64::is_finite)))));+                    if let Some(i) = found { matched[i] = true; true } else { false }+                });+                if !same_boundary {+                    return Err(format!("Fields {name} terminal assignments differ from the branch model, including physical pad selectors"));                 }                 if fields["board"]["layers"] != json!(["F.Cu","B.Cu"]) { return Err("branch screening requires a physical two-layer Fields solve".into()); }                 for (report_key, expected) in [("thicknessMm",spec["branchCurrentModel"]["boardThicknessMm"].as_f64()),("copperUm",spec["copperUm"].as_f64())] {@@ -427,6 +437,25 @@ mod field_screen_tests {         assert!(field_screen(&f,&spec,b"board",b"spec","current").is_err());     }     #[test]+    fn repeated_pin_boundaries_require_each_physical_selector_exactly_once() {+        let pins=json!([{"reference":"J1","pad":"1","amps":2},+            {"reference":"D1","pad":"2","amps":-1,"at":[1.0,2.0]},+            {"reference":"D1","pad":"2","amps":-1,"at":[1.0,4.0]}]);+        let spec=json!({"copperUm":35,"branchCurrentModel":{"boardThicknessMm":1.6},"loads":{"VCC":{"amps":2,"currentModel":"resistive-branches","terminals":pins}}});+        let mut f=report();f["terminalAssignments"]=json!({"VCC":{"mode":"explicit","pins":pins}});+        f["board"]=json!({"layers":["F.Cu","B.Cu"],"copperUm":35,"thicknessMm":1.6});+        field_screen(&f,&spec,b"board",b"spec","current").unwrap();+        f["terminalAssignments"]["VCC"]["pins"].as_array_mut().unwrap().reverse();+        field_screen(&f,&spec,b"board",b"spec","current").unwrap();+        for at in [Value::Null,json!([1.0,4.0]),json!([1.0,2.1])] {+            let mut bad=f.clone();bad["terminalAssignments"]["VCC"]["pins"][1]["at"]=at;+            assert!(field_screen(&bad,&spec,b"board",b"spec","current").is_err());+        }+        let mut invalid=spec.clone();invalid["loads"]["VCC"]["terminals"][1]["at"]=json!(["x",2]);+        f["terminalAssignments"]["VCC"]["pins"]=invalid["loads"]["VCC"]["terminals"].clone();+        assert!(field_screen(&f,&invalid,b"board",b"spec","current").is_err());+    }+    #[test]     fn fresh_solve_requires_identity_coverage_and_no_relevant_findings() {         let spec=serde_json::json!({"loads":{"VCC":{"amps":2}},"hot":{"Q1":{"watts":1}}});         assert!(field_screen(&report(),&spec,b"board",b"spec","current").is_ok());
docs/release-0.1.83.mdadded+5
@@ -0,0 +1,5 @@+# 0.1.83: preserve physical pad boundaries++Current acceptance now matches explicit terminal rows one-to-one, including optional physical pad coordinates. A report cannot substitute the second anode for the first, omit the selector, or reuse a matching row. Existing unique-pin specifications remain compatible. The installed skill explains the Fields PR10 dependency, branch-current assumptions and coordinate updates after placement. No current or thermal threshold changes.++Component-stage hints now point to the available adom/component-hero generator and wiki-component contract, replacing stale EDA-skill and hero-check references while preserving artwork, provenance and visual-review requirements.
flows/board.json+3−3
@@ -64,7 +64,7 @@         "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."+        "Read component-hero from adom/component-hero and the current wiki-component guidance, including state/appearance rules for LEDs. 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 the component-hero package generator (skills/component-hero/scripts/hero_glb.py in its source repo), inspect its alignment result and overlay sidecar, then inspect published top/underside/pin1 and native LED surfaces. Rediscover stale tool references rather than inventing commands. 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."       ]     },     {@@ -90,7 +90,7 @@         "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.",         "`models` also checks every bound model is right way up (step2glb bbox after the footprint's rotate/offset): a flat SMD chip whose thinnest axis is not Z, or an SMD body whose bottom is off the board, is a warning to fix in the binding and verify in the native 3D viewer, or to acknowledge with `models --ack <refs> --why ...`; finish refuses open ones. Never adom-chipsmith.",         "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."+        "Read component-hero from adom/component-hero and the current wiki-component guidance, including state/appearance rules for LEDs. 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 the component-hero package generator (skills/component-hero/scripts/hero_glb.py in its source repo), inspect its alignment result and overlay sidecar, then inspect published top/underside/pin1 and native LED surfaces. Rediscover stale tool references rather than inventing commands. 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."       ]     },     {@@ -102,7 +102,7 @@         "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."+        "Read component-hero from adom/component-hero and the current wiki-component guidance, including state/appearance rules for LEDs. 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 the component-hero package generator (skills/component-hero/scripts/hero_glb.py in its source repo), inspect its alignment result and overlay sidecar, then inspect published top/underside/pin1 and native LED surfaces. Rediscover stale tool references rather than inventing commands. 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."     },
package.json+1−1
@@ -1,7 +1,7 @@ {   "slug": "adom-aiflow",   "type": "app",-  "version": "0.1.82",+  "version": "0.1.83",   "title": "AI Flow",   "description": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. One Rust binary with a crate per step (placement helpers, a grid router with Kelvin taps, pours with keepouts, KiCad's DRC gate, live landing through the KiCad Bridge, copper measurement, current and thermal analysis) and a finish line that refuses an unfinished board. Every command answers with hints for the AI; every turn, its thinking time and every rework loop go into run.jsonl, so Claude, Codex and any other engine are compared on the same flow. KiCad today; Altium, Fusion and Adom's own web apps next.",   "summary": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. The AI thinks its way from placement through routing, pours, current and thermal analysis to a delivered video; the binary does the fast, deterministic parts of every step, hands back hints, and keeps a ledger of every turn, every return to an earlier step, and the clock from the prompt to done.",
page.json+1−1
@@ -1,7 +1,7 @@ {   "slug": "adom-aiflow",   "type": "app",-  "version": "0.1.82",+  "version": "0.1.83",   "title": "AI Flow",   "description": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. One Rust binary with a crate per step (placement helpers, a grid router with Kelvin taps, pours with keepouts, KiCad's DRC gate, live landing through the KiCad Bridge, copper measurement, current and thermal analysis) and a finish line that refuses an unfinished board. Every command answers with hints for the AI; every turn, its thinking time and every rework loop go into run.jsonl, so Claude, Codex and any other engine are compared on the same flow. KiCad today; Altium, Fusion and Adom's own web apps next.",   "summary": "Adom's AI Flow: a tool to help the AI follow all of the steps it takes to build a board. The AI thinks its way from placement through routing, pours, current and thermal analysis to a delivered video; the binary does the fast, deterministic parts of every step, hands back hints, and keeps a ledger of every turn, every return to an earlier step, and the clock from the prompt to done.",
skills/adom-aiflow/SKILL.md+5−1
@@ -278,7 +278,7 @@ Use supported native refresh/reload commands through the owning EDA bridge. If a  ## 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.+Before creating or revising component heroes, read the current `component-hero` skill from `adom/component-hero` and the `wiki-component` contract. Use its deterministic `scripts/hero_glb.py` generator with the clean board-use GLB, real footprint and component pin map; inspect its alignment report and overlay sidecar, then verify the published viewer. Older references to `eda-component-hero`, `eda-led-appearance` or an unverified `hero-check` executable may be stale: discover the current owning package rather than stopping or inventing a command. For LED variants, also follow the component state and appearance requirements in the current wiki-component guidance. 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. @@ -355,3 +355,7 @@ For native saved-board experiments, preserve a UUID-to-net map before and after AIFlow independently checks every declared hot part against its `maxRiseC` (or `hotMaxRiseC`) and any `maxThetaCPerW`, using matching watts and tab net. Both thermal solves must converge and report finite temperatures. A global Fields issue list cannot hide a tighter part limit. Existing chip summaries round to 0.1 C, so acceptance reserves 0.05 C for reporting precision; do not round a boundary value into a pass. Moving-air results do not waive the still-air check.  Derive continuous heat cases from the actual voltage/current/power envelope and keep overload/conductor screens separate. Do not lower a limit to advance the workflow. Package-to-heatsink transfer, sensor lag, airflow and physical qualification still require their own evidence.++### Repeated physical pads in explicit current boundaries++When multiple physical lands share one logical pin number, use the reviewed Fields physical-pad selector (`at: [x_mm, y_mm]`, adom/adom-fields PR10 and dependencies). Declare each branch current and its assumption; never silently divide the load to obtain a pass. AIFlow matches each reported physical boundary once, including its coordinates, and refuses missing/changed selectors. Recheck coordinates after moving a footprint. Preserve owner review and shared runtimes; source support is not a deployed release or package-resistance model.