← Commit history

v0.1.29: import_part surfaces model counts and fails on a zero-model attach

John Lauer ·64adefc631 ·1mo ago ·parent 1b587b8
7 files changed +28−10
CHANGELOG.md+6
@@ -1,5 +1,11 @@ # Changelog +## 0.1.29 — 2026-09-01+- **`import_part` no longer reports a silent half-import.** The `add_models` step recorded a bare boolean, so attaching ZERO footprint models looked identical to attaching one — and a symbol with no model places on a schematic with no footprint. It now surfaces the agent's own counts and FAILS with `failedAt: "add_models"` when the count is zero.+- **It also sanitises the model spec the way `add_models` always did**: the agent splits models on `;` and fields on `|`, so an unescaped separator inside a DESCRIPTION silently truncated the spec. `import_part` passed the description raw.+- Known defect, recorded not fixed: **`add_models` is not idempotent** — each call appends another implementation, so calling it twice leaves a symbol with duplicate footprint models. Removing a model needs an implementation-read API this agent has not proven yet, so the safe repair today is `remove_symbol` + re-import.+- Verified end to end against a real wiki component (`adom/stm32f303cbt6`, published by ray): kicad_sym → 48-pin symbol with 10 display modes, kicad_mod → LQFP-48 land pattern with courtyard/fab/pin-1 marker, STEP → 3D body, all three vendor part numbers attached, **zero dialogs, 7.75 s, and the user's foreground window never changed**.+ ## 0.1.28 — 2026-09-01 - **Four design-rule hygiene checks**, all from the rules the board read already carries:   - `disabled_design_rules` — a rule that exists but is switched OFF. Worse than a missing rule: the board LOOKS ruled, DRC passes, and the constraint was never applied. Raised to error for Clearance / Width / HoleSize / ShortCircuit.
adom-bridge-altium-manifest.json+4−4
@@ -1,9 +1,9 @@ {   "name": "altium",-  "version": "0.1.28",-  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.28/adom-bridge-altium-v0.1.28.zip",-  "sha256": "8cf6cda116e08da60816540c274409aeb752f5125b9135d7ff4bbfb21db09051",-  "size": 127694,+  "version": "0.1.29",+  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.29/adom-bridge-altium-v0.1.29.zip",+  "sha256": "03d78b08a236eaf10333233f9fa58b5b8e52942b9c77c5895401fc119413133d",+  "size": 128004,   "verbPrefixes": [     "altium_"   ],
adom-bridge-altium-v0.1.29.zipadded
⋯ 1 unchanged line ⋯
bridge.json+1−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "altium",   "displayName": "Altium Designer",-  "version": "0.1.28",+  "version": "0.1.29",   "description": "Drive Altium Designer from Adom: a resident DelphiScript agent (eval + the 1,100-command process launcher), the X2 -R command line, UIA over the VCL shell, dialogs by PID, screenshots of every Altium window, and Altium 365.",   "homepage": "https://wiki.adom.inc/adom/altium-bridge",   "docs": "https://wiki.adom.inc/adom/altium-bridge",
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "altium-bridge",-  "version": "0.1.28",+  "version": "0.1.29",   "type": "app",   "description": "Skills for your container so your AI knows how to drive the Altium Designer bridge (altium_* verbs). The bridge runtime itself is the release zip; Adom Bridge loads that.",   "tags": [
src/BRIDGE_VERSION+1−1
@@ -1 +1 @@-0.1.28+0.1.29
src/server.py+15−3
@@ -2296,11 +2296,23 @@ def h_import_part(args):         sym_name = (r.get("data") or {}).get("libref")         steps.append({"build_symbol_modes": sym_name})     if sym_name and fp_name:+        # Sanitise exactly like h_add_models does: the agent splits models on ';' and fields on '|',+        # so an unescaped separator in a DESCRIPTION silently truncates the model spec — and the+        # step used to report a bare bool, which hid whether 0 or 1 models actually attached.+        desc = (args.get("description") or "")[:80].replace(";", ",").replace("|", "/")         r = agent.call("add_models", {"libraryPath": args["schLib"], "name": sym_name,-                                      "models": f"{fp_name}|{args.get('pcbLib','')}|{(args.get('description') or '')[:80]}",-                                      "params": ";".join(f"{k}={v}" for k, v in (args.get("params") or {}).items()),+                                      "models": f"{fp_name}|{args.get('pcbLib','')}|{desc}",+                                      "params": ";".join(f"{k}={str(v).replace(';', ',')}"+                                                         for k, v in (args.get("params") or {}).items()),                                       "comment": args.get("comment", sym_name), "description": args.get("description", "")}, timeout=120)-        steps.append({"add_models": bool(r.get("success"))})+        d = r.get("data") or {}+        steps.append({"add_models": bool(r.get("success")), "models": d.get("models"), "params": d.get("params")})+        if r.get("success") and not d.get("models"):+            # attaching ZERO models is a silent failure: the symbol places with no footprint+            return {"success": False, "failedAt": "add_models", "steps": steps,+                    "error": "add_models attached 0 footprint models — the symbol would place with no "+                             "footprint. Check the model spec separators (';' between models, '|' between "+                             "name|pcblib|description).", **r}     for lib in (args.get("pcbLib"), args.get("schLib")):         if lib:             agent.call("open", {"path": lib}, timeout=60)