app
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.
← All Pull Requests
AI Flow 0.2.74: parts finds a packaging variant on its base number's page #93
Merges
aiflow-0.2.74 → mainAI Flow 0.2.74: parts finds a packaging variant on its base page (Ray, #193).
mpn_basealso strips a Nexperia-style,nnnsuffix and a reel suffix (-TR, -TR13, -REEL, -REEL7, -RL);partssays which suffix it dropped. Checked live: 74HCT244PW-Q100,11 and TSM-110-01-L-DV-P-TR now find adom/74hct244pw-q100 and adom/tsm-110-01-l-dv-p.- aiflow-sourcing retry list: separate land drawings (Samtec), no pin numbers, a blocked maker site.
Tests: 716 workspace tests (1 new), parts workflow suites pass; preflight clean (page.json checked by hand: only the version differs; the wiki read of it fails with TRANSPORT_ALTERED).
🤖 Generated with Claude Code
Diff Skip to comments
Cargo.lock+10−10@@ -4,7 +4,7 @@ version = 4 [[package]] name = "adom-aiflow"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-analyze", "aiflow-board",@@ -25,7 +25,7 @@ dependencies = [ [[package]] name = "aiflow-analyze"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "serde",@@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "aiflow-board"-version = "0.2.73"+version = "0.2.74" dependencies = [ "roxmltree", "serde",@@ -44,7 +44,7 @@ dependencies = [ [[package]] name = "aiflow-bridge"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "serde",@@ -53,7 +53,7 @@ dependencies = [ [[package]] name = "aiflow-copper"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "aiflow-grid",@@ -63,7 +63,7 @@ dependencies = [ [[package]] name = "aiflow-grid"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "serde",@@ -72,7 +72,7 @@ dependencies = [ [[package]] name = "aiflow-place"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "serde",@@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "aiflow-pours"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "aiflow-copper",@@ -91,7 +91,7 @@ dependencies = [ [[package]] name = "aiflow-router"-version = "0.2.73"+version = "0.2.74" dependencies = [ "aiflow-board", "aiflow-grid",@@ -101,7 +101,7 @@ dependencies = [ [[package]] name = "aiflow-run"-version = "0.2.73"+version = "0.2.74" dependencies = [ "serde", "serde_json",
Cargo.toml+1−1@@ -14,7 +14,7 @@ members = [ ] [workspace.package]-version = "0.2.73"+version = "0.2.74" edition = "2021" license = "MIT" repository = "https://wiki.adom.inc/adom/adom-aiflow"
bin/adom-aiflow⋯ 1 unchanged line ⋯
crates/adom-aiflow/src/preboard.rs+37−4@@ -926,9 +926,25 @@ pub fn wiki_slug(s: &str) -> String { /// adom/mcp73831t-2aci for MCP73831T-2ACI/OT); other pages keep the suffix in their slug (adom/sp485een-l-tr /// for SP485EEN-L/TR), so the full forms are always tried first. pub fn mpn_base(mpn: &str) -> Option<String> {- let (b, rest) = mpn.trim().split_once('/')?;- let b = b.trim();- (!b.is_empty() && !rest.trim().is_empty()).then(|| b.to_string())+ let m = mpn.trim();+ // "/OT" (issue #161)+ if let Some((b, rest)) = m.split_once('/') {+ let b = b.trim();+ if !b.is_empty() && !rest.trim().is_empty() { return Some(b.to_string()); }+ }+ // Ray, #193: the part factory files a packaging variant on its base number's page: Nexperia's ",115" style+ // orderable suffix, and a tape-and-reel suffix ("-TR", "-TR13", "-REEL", "-REEL7", "-RL")+ if let Some((b, digits)) = m.rsplit_once(',') {+ if !b.trim().is_empty() && !digits.is_empty() && digits.chars().all(|c| c.is_ascii_digit()) { return Some(b.trim().to_string()); }+ }+ let up = m.to_ascii_uppercase();+ for suf in ["-TR", "-REEL", "-RL"] {+ if let Some(i) = up.rfind(suf) {+ let tail = &up[i + suf.len()..];+ if i > 0 && tail.chars().all(|c| c.is_ascii_digit()) { return Some(m[..i].to_string()); }+ }+ }+ None } /// The slugs a part's component page may have: the lowercase MPN, then the wiki's slug form (issue #76),@@ -954,7 +970,8 @@ pub fn matched_by_base(page: &str, mpn: &str) -> Option<String> { let slug = page.rsplit('/').next().unwrap_or(page).to_lowercase(); let full = [mpn.trim().to_lowercase(), wiki_slug(mpn)]; let b = mpn_base(mpn)?;- (!full.contains(&slug) && (slug == b.to_lowercase() || slug == wiki_slug(&b))).then(|| format!("{page} is the page for {b}, the MPN without its /{} packaging suffix", mpn.trim().split_once('/').map(|x| x.1.trim()).unwrap_or("")))+ let suffix = mpn.trim()[b.len()..].trim().to_string();+ (!full.contains(&slug) && (slug == b.to_lowercase() || slug == wiki_slug(&b))).then(|| format!("{page} is the page for {b}, the MPN without its {suffix} packaging suffix")) } /// The component page for an MPN among `adom-wiki search` hits: a hardware page the search matched by@@ -975,6 +992,22 @@ pub fn part_page(hits: &[Value], mpn: &str) -> Option<String> { mod bom_parts_tests { use super::*; + /// Ray (#193): a packaging variant is filed on its base number's page.+ #[test]+ fn packaging_suffixes_find_the_base_page() {+ assert_eq!(mpn_base("74HCT244PW-Q100,11").as_deref(), Some("74HCT244PW-Q100"));+ assert_eq!(mpn_base("TSM-110-01-L-DV-P-TR").as_deref(), Some("TSM-110-01-L-DV-P"));+ assert_eq!(mpn_base("LM358DR-REEL7").as_deref(), Some("LM358DR"));+ assert_eq!(mpn_base("MCP73831T-2ACI/OT").as_deref(), Some("MCP73831T-2ACI"));+ assert_eq!(mpn_base("CMT-8530S-SMT-TR").as_deref(), Some("CMT-8530S-SMT"));+ assert_eq!(mpn_base("TPS259474LRPWR"), None, "a reel letter fused into the number is left alone");+ assert_eq!(mpn_base("SN74LVC1G14-TRUE"), None, "-TR only as the whole last part");+ assert!(part_slug_candidates("74HCT244PW-Q100,11").contains(&"74hct244pw-q100".to_string()));+ let hits = vec![serde_json::json!({"type": "hardware", "owner": "adom", "slug": "tsm-110-01-l-dv-p"})];+ assert_eq!(part_page(&hits, "TSM-110-01-L-DV-P-TR").as_deref(), Some("adom/tsm-110-01-l-dv-p"));+ assert!(matched_by_base("adom/74hct244pw-q100", "74HCT244PW-Q100,11").unwrap().contains("without its ,11 packaging suffix"));+ }+ #[test] fn a_dot_in_the_mpn_becomes_a_dash_in_the_slug() { assert_eq!(wiki_slug("AP2112K-3.3TRG1"), "ap2112k-3-3trg1");
docs/release-0.2.74.mdadded+9@@ -0,0 +1,9 @@+# AI Flow 0.2.74++- **`parts` finds a packaging variant on its base number's page** (Ray, #193). The part factory files+ `74HCT244PW-Q100,11` on `adom/74hct244pw-q100` and `TSM-110-01-L-DV-P-TR` on `adom/tsm-110-01-l-dv-p`;+ `parts` reported both as having no page. It now also tries the number without a Nexperia-style `,nnn` suffix+ or a reel suffix (`-TR`, `-TR13`, `-REEL`, `-REEL7`, `-RL`), as it already did for `/OT` (#161), and says which+ suffix it dropped. A reel letter fused into the number (`...DR`, `...PWR`) is left alone.+- aiflow-sourcing's retry list names Ray's cases: a land in a separate drawing (Samtec), a datasheet with no pin+ numbers (the maker's footprint or 3D download), a maker site that turns the fetcher away (another copy).
package.json+1−1@@ -1,7 +1,7 @@ { "slug": "adom-aiflow", "type": "app",- "version": "0.2.73",+ "version": "0.2.74", "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, Fusion 360 and Altium Designer today (the same steps and gates through each tool's bridge); 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+2−3@@ -1,7 +1,7 @@ { "slug": "adom-aiflow", "type": "app",- "version": "0.2.73",+ "version": "0.2.74", "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, Fusion 360 and Altium Designer today (the same steps and gates through each tool's bridge); 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.",@@ -101,8 +101,7 @@ "org": "adom", "tag": "latest", "author": {- "name": "John Lauer",- "email": "[email protected]"+ "name": "John Lauer" }, "confirmed_user_skills": [ "aiflow-simulate",
skills/aiflow-sourcing/SKILL.md+5−1@@ -169,7 +169,11 @@ Verified example, 2026-10-08: Pup showed Mouser Access Denied for MF40200V1-1000 - no distributor sells the number, or a packaging/reel suffix: `--as <orderable MPN>` (from `adom-wiki part candidates <MPN>`); the BOM line keeps its MPN, and the page built under the other number is used for it; - no datasheet, or no land-pattern drawing: `--datasheet` with the maker's product page, its separate package drawing or its CAD download (section 5's order), or the distributor PDF when the maker's page failed; - land-pattern readings disagreed: `--datasheet` with the maker's own footprint or package drawing, which settles it;- - a factory-internal stop (3D model step, publishing): the same part with another datasheet link, or `--manufacturer`.+ - a factory-internal stop (3D model step, publishing): the same part with another datasheet link, or `--manufacturer`;+ - the land is in a separate drawing, not the datasheet (Samtec connectors print it in their footprint drawing): `--datasheet` with that drawing's link;+ - the datasheet prints no pin numbers: `--datasheet` with the maker's footprint or 3D download;+ - the maker's site turns the factory's fetcher away: `--datasheet` with another copy (a distributor's PDF).+ A packaging or reel variant (`,11`, `-TR`, `/OT`) is filed on its base number's page, and `parts` finds it there by itself. This is one bounded retry, not a loop; the "one search per question, never retry" rule for vendor searches stays as it is. 2. **Still no page: assess its supply.** Write `design/supply-risk.json` and run `adom-aiflow supply-risk`. Every figure carries its source (URL, or the tool that gave it) and the date it was read; `supply-risk` lists what is left out. Read the figures from Parts Search (`adom-parts-search`), the distributors and the maker's site:
Comments
Log in to comment.
No comments yet.