← Commit history

v0.1.25: check-id filtering fixed, read_board exposed

John Lauer ·f1b86d89a3 ·1mo ago ·parent 35c118d
7 files changed +49−13
CHANGELOG.md+4
@@ -1,5 +1,9 @@ # Changelog +## 0.1.25 — 2026-09-01+- **`checks:[...]` now filters on the ID you actually see.** The selector was derived from the Python function name (`_chk_components_outside_board`) while findings report `components_outside_board_outline`, so filtering by the visible name silently ran ZERO checks and returned a clean review. Each check now declares its own ID, the reply lists `availableChecks`, and an unrecognised name comes back as `unknownChecks` instead of being ignored.+- **New verb `altium_read_board`** — the raw read (components, nets, layers, copper, rules, occupancy, outline) in one round trip. It existed only in the Rust bridge, which meant nobody could see what a check saw; a review's silence had to be taken on trust. Now it can be inspected directly.+ ## 0.1.24 — 2026-09-01 - **`read_board` gains an `outline` section** — the board extent, read through the SAME guarded pattern the library reader already uses, because a library's internal board has a nil `BoardOutline` and touching `BoundingRectangle` on it halts the engine (measured 2026-08-30). It reports which source it used: `boardOutline` (the real outline's bounding box) or `boardBounds` (everything on the board, including strays outside it). - **Two review checks unlocked by it**, both named for what they actually measure:
adom-bridge-altium-manifest.json+4−4
@@ -1,9 +1,9 @@ {   "name": "altium",-  "version": "0.1.24",-  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.24/adom-bridge-altium-v0.1.24.zip",-  "sha256": "db394b52c27eb6c501c25dc2779b05133ec1d70ec587baf3be41b3a9ddf10870",-  "size": 124096,+  "version": "0.1.25",+  "url": "https://wiki.adom.inc/download/adom/altium-bridge/0.1.25/adom-bridge-altium-v0.1.25.zip",+  "sha256": "480d7fea5b48f0b5423096278512b2a4f597f04674806a095de31e6a464904b1",+  "size": 124534,   "verbPrefixes": [     "altium_"   ],
adom-bridge-altium-v0.1.25.zipadded
⋯ 1 unchanged line ⋯
bridge.json+2−1
@@ -2,7 +2,7 @@   "manifest_version": 1,   "name": "altium",   "displayName": "Altium Designer",-  "version": "0.1.24",+  "version": "0.1.25",   "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",@@ -91,6 +91,7 @@     "altium_place_on_pcb",     "altium_place_on_sch",     "altium_progress",+    "altium_read_board",     "altium_read_rules",     "altium_read_schematic",     "altium_read_symbol",
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "altium-bridge",-  "version": "0.1.24",+  "version": "0.1.25",   "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.24+0.1.25
src/server.py+37−6
@@ -1630,9 +1630,19 @@ def _chk_components_near_board_edge(board, sheet, margin_mil=20):     return out  -BOARD_CHECKS = [_chk_placeholder_values, _chk_single_pin_nets, _chk_unused_mechanical_layers,-                _chk_off_grid_components, _chk_duplicate_designators,-                _chk_components_outside_board, _chk_components_near_board_edge]+# (id, fn). The ID is what appears in a finding's `check` field, so `checks:["..."]` filters on the+# name the caller actually sees. Deriving it from the Python function name instead was a trap: the+# function is `_chk_components_outside_board`, the finding says `components_outside_board_outline`,+# and filtering by the visible name silently ran NOTHING (2026-09-01).+BOARD_CHECKS = [+    ("placeholder_values", _chk_placeholder_values),+    ("single_pin_nets", _chk_single_pin_nets),+    ("unused_mechanical_layers", _chk_unused_mechanical_layers),+    ("off_grid_components", _chk_off_grid_components),+    ("duplicate_designators", _chk_duplicate_designators),+    ("components_outside_board_outline", _chk_components_outside_board),+    ("components_near_board_edge", _chk_components_near_board_edge),+]  # Named so a clean result is not mistaken for a complete one. REVIEW_NOT_IMPLEMENTED = {@@ -1670,8 +1680,8 @@ def h_review_board(args):     wanted = args.get("checks")     findings = []     ran = []-    for fn in BOARD_CHECKS:-        name = fn.__name__.replace("_chk_", "")+    unknown = sorted(set(wanted or []) - {n for n, _ in BOARD_CHECKS})+    for name, fn in BOARD_CHECKS:         if wanted and name not in wanted:             continue         ran.append(name)@@ -1685,8 +1695,10 @@ def h_review_board(args):     counts = {}     for f in findings:         counts[f["severity"]] = counts.get(f["severity"], 0) + 1+    out_unknown = {"unknownChecks": unknown} if unknown else {}     return {"success": True, "board": board.get("board"),             "findings": findings, "counts": counts, "checksRun": ran,+            "availableChecks": [n for n, _ in BOARD_CHECKS], **out_unknown,             "notImplemented": REVIEW_NOT_IMPLEMENTED,             "roundtripMs": r.get("roundtripMs"),             "_hint": ("A clean result means the checks that RAN found nothing — see notImplemented for "@@ -1694,6 +1706,24 @@ def h_review_board(args):                       "Add includeSchematic:true to also read the current sheet.")}  ++def h_read_board(args):+    """The raw board read: components, nets, layers, copper, rules, occupancy, outline — ONE round+    trip. This is the primitive every board view is derived from; exposing it means a caller can see+    exactly what a check saw, instead of inferring it from the check's silence."""+    g = _need_licensed()+    if g:+        return g+    r = agent.call("read_board", {"sections": args.get("sections") or "components,nets,layers,copper,rules,occupancy,outline",+                                  "limit": args.get("limit", 2000)},+                   timeout=float(args.get("timeout", 90)))+    d = r.get("data") or {}+    if not d.get("ok"):+        return r+    return {"success": True, "board": d.get("board"), "sections": d.get("sections"),+            "data": d, "roundtripMs": r.get("roundtripMs")}++ # ---- licence lifecycle: status, ensure-licensed, trial setup (John 2026-08-31) ------------  def h_license_status(args):@@ -2261,6 +2291,7 @@ _VERB_CATALOG = {     "close": "WM_CLOSE the main window; reports a save prompt instead of answering it; force:true taskkills.",     "activate_document": "Make an ALREADY-OPEN document current by invoking its document-bar tab through UIA — no cursor, no foreground.",     "layers_in_use": "How many layers the board ACTUALLY has: copper layers carrying primitives, densest first (a floor, not the stack).",+    "read_board": "The raw board read (components, nets, layers, copper, rules, occupancy, outline) in ONE round trip.",     "review_board": "Design review over one board read: placeholder values, single-pin nets, unused mechanical layers, off-grid parts, duplicate designators.",     "read_schematic": "Components + pins of the CURRENT schematic sheet (one round trip).",     "cross_check": "Schematic sheet vs board: what is drawn but not placed, and placed but not drawn.",@@ -2328,7 +2359,7 @@ COMMAND_HANDLERS = {     "window_info": h_window_info, "state": h_state, "check_dialogs": h_check_dialogs,     "dismiss_dialogs": h_dismiss_dialogs, "launch": h_launch, "close": h_close,     "activate_document": h_activate_document, "layers_in_use": h_layers_in_use,-    "instances": h_instances, "review_board": h_review_board, "read_schematic": h_read_schematic, "cross_check": h_cross_check,+    "instances": h_instances, "review_board": h_review_board, "read_board": h_read_board, "read_schematic": h_read_schematic, "cross_check": h_cross_check,     "agent_start": h_agent_start, "agent_stop": h_agent_stop, "agent_status": h_agent_status,     "agent_recover": h_agent_recover,     "eval": h_eval, "run_command": h_run_command, "run_script": h_run_script,