← Commit history

AI Flow 0.1.62: on top of 0.1.61 (restores its main.rs, Cargo and package files that the previous push overwrote): silkscreen the fab would clip blocks gate and finish; board-glb clips silk at mask openings and its check refuses an unclipped render

John Lauer ·07003c9bdb · ·parent b3629de
5 files changed +23−16
Cargo.lock+10−10
@@ -4,7 +4,7 @@ version = 4  [[package]] name = "adom-aiflow"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-analyze",  "aiflow-board",@@ -24,7 +24,7 @@ dependencies = [  [[package]] name = "aiflow-analyze"-version = "0.1.61"+version = "0.1.62" dependencies = [  "serde",  "serde_json",@@ -33,7 +33,7 @@ dependencies = [  [[package]] name = "aiflow-board"-version = "0.1.61"+version = "0.1.62" dependencies = [  "roxmltree",  "serde",@@ -42,7 +42,7 @@ dependencies = [  [[package]] name = "aiflow-bridge"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "serde",@@ -51,7 +51,7 @@ dependencies = [  [[package]] name = "aiflow-copper"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -61,7 +61,7 @@ dependencies = [  [[package]] name = "aiflow-grid"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "serde",@@ -70,7 +70,7 @@ dependencies = [  [[package]] name = "aiflow-place"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "serde",@@ -79,7 +79,7 @@ dependencies = [  [[package]] name = "aiflow-pours"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "aiflow-copper",@@ -89,7 +89,7 @@ dependencies = [  [[package]] name = "aiflow-router"-version = "0.1.61"+version = "0.1.62" dependencies = [  "aiflow-board",  "aiflow-grid",@@ -99,7 +99,7 @@ dependencies = [  [[package]] name = "aiflow-run"-version = "0.1.61"+version = "0.1.62" dependencies = [  "serde",  "serde_json",
Cargo.toml+1−1
@@ -14,7 +14,7 @@ members = [ ]  [workspace.package]-version = "0.1.61"+version = "0.1.62" edition = "2021" license = "MIT" repository = "https://wiki.adom.inc/adom/adom-aiflow"
SKILL.md+1−1
@@ -123,7 +123,7 @@ The clock starts at the prompt even when there is no board yet. - **`evidence add --kind calcs|simulation|vendor-model --file <json|md> [--note ...]`** records the design record in the run and the ledger with its sha256 (a copy lands in `<run>/evidence/`). A simulation result that says it fails (a top-level `"pass": false`, or a `"checks"` row `{"name","value","limit","pass"}` that fails) is refused. Vendor PSpice/LTspice runs belong to the separately published adom/adom-spice-skillpack; `--kind vendor-model` records their result. - **`finish`** also refuses without a passed sourcing check against the board when the spec or the requirements name a sourcing profile, and without the evidence kinds the spec lists in `"requireEvidence": ["calcs", "simulation"]`. -**Silkscreen the fab would clip blocks the board (0.1.61).** KiCad grades `silk_over_copper`, `silk_overlap`, `silk_edge_clearance`, `text_height` and `text_thickness` as warnings by default.+**Silkscreen the fab would clip blocks the board (0.1.62).** KiCad grades `silk_over_copper`, `silk_overlap`, `silk_edge_clearance`, `text_height` and `text_thickness` as warnings by default. - `gate` and `finish` treat them as blocking, like the other manufacturing warnings. `finish` runs KiCad's full DRC on the live board for this. - Ink over a mask opening is clipped off by the fab: the text prints broken and the pad carries ink at its edge. The fix is to move the text, or the pad, never to downgrade the rule. - KiCad's STEP export keeps the whole ink. So `board-glb copper` lays the exposed copper over the ink inside every mask opening, the way the fab prints it, and `board-glb check` fails a GLB whose silkscreen is not clipped.
crates/adom-aiflow/src/main.rs+10−3
@@ -3456,8 +3456,12 @@ fn main() {             ok(&format!("{done} board corner(s) rounded to {rad} mm; the outline has no sharp corner"), &["Copper keeps its edge clearance from the new arcs: refill the pours (`land pours` again) if a pour followed the old corner.".into()]);         }         Cmd::Timeline { action, port } => {-            let r = load_run(&cli);+            let mut r = load_run(&cli);             let flow_full: Value = serde_json::from_str(include_str!("../../../flows/board.json")).unwrap();+            if r.data["steps"].as_object().map(|o| o.keys().all(|k| k == "intake")).unwrap_or(true) {+                let want = json!(sequence::sequence_of(&flow_full, sequence::lane(&dir, &r.data)));+                if r.data["sequence"] != want { r.data["sequence"] = want; r.save().unwrap(); }+            }             let seq: Vec<String> = r.data["sequence"].as_array().map(|a| a.iter().filter_map(|x| x.as_str().map(str::to_string)).collect()).unwrap_or_else(|| sequence::sequence_of(&flow_full, sequence::lane(&dir, &r.data)));             let tl = sequence::timeline(&dir, &r.data, &flow_full, &seq, &r.step_report());             sequence::write_timeline(&dir, &tl, TIMELINE_PAGE);@@ -3947,8 +3951,11 @@ fn main() {             // the required steps, in order: a run that starts now carries its lane's sequence, and no step             // in it can be skipped (sequence.rs)             let flow_full: Value = serde_json::from_str(include_str!("../../../flows/board.json")).unwrap();-            if r.data["sequence"].is_null() && r.data["steps"].as_object().map(|o| o.keys().all(|k| k == "intake")).unwrap_or(true) {-                r.data["sequence"] = json!(sequence::sequence_of(&flow_full, sequence::lane(&dir, &r.data)));+            // the lane can still change while only intake is done (the run learns it is a Fusion board from the+            // brief or the requirements written during intake)+            if r.data["steps"].as_object().map(|o| o.keys().all(|k| k == "intake")).unwrap_or(true) {+                let want = json!(sequence::sequence_of(&flow_full, sequence::lane(&dir, &r.data)));+                if r.data["sequence"] != want { r.data["sequence"] = want; }             }             let seq: Vec<String> = r.data["sequence"].as_array().map(|a| a.iter().filter_map(|x| x.as_str().map(str::to_string)).collect()).unwrap_or_default();             if !seq.is_empty() && !*back {
package.json+1−1
@@ -1,7 +1,7 @@ {   "slug": "adom-aiflow",   "type": "app",-  "version": "0.1.61",+  "version": "0.1.62",   "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.",