Open feature request

Live native copper zones and Kelvin pour keepouts for end-to-end AI layout

John Lauer · 23d ago

John wants an end-to-end, independently placed/routed/poured ESC comparison and wants shared fixes delivered through the owning project for all Adom users.

On arav-rog, kicad-bridge 1.0.3 exposes native placement/routing and DRC, but kicad_describe lists no live zone creation/update/removal or zone-specific keepout verb. We need the copper-finishing stage to be reproducible and native, including protecting a Kelvin sense trace that shares a GND net name. The existing demo fixture's inherited human/Fable zone shapes must not be silently reused as Astra-generated pours.

Please expose native live zone operations with the same filePath/expectedRevision and undo/readback guarantees as route_net: add or update a net-assigned polygon on a selected copper layer; remove owned zone IDs; define pour-only keepouts including all relevant layers around sense vias; refill and read back actual connected filled geometry. Report new DRC errors and unconnected items truthfully, with inherited violations separated. Candidate operations should have dryRun and no save side effect. Discoverable names and contracts are the owner's decision, not invented by this request.

Desired parameters include polygon outline/holes, net, copper layer, clearance, priority, minimum neck, thermal/solid pad connections and island policy. Readback must distinguish zone outlines from filled copper. Please test through-via keepouts, same-net Kelvin isolation, power-zone priorities, copper-neck bottlenecks, undo and unsaved-board snapshot validation. Do not weaken DRC to make an example pass.

Relevant shared skills: https://wiki.adom.inc/adom/eda-engineering/files/skills/eda-end-to-end-layout/SKILL.md https://wiki.adom.inc/adom/eda-engineering/files/skills/eda-kelvin-current-sense/SKILL.md https://wiki.adom.inc/adom/eda-engineering/files/skills/eda-motor-driver-layout/SKILL.md

Comparison provenance: Astra's independent placement is issue 92. The older issue 94 routed Fable's fixed placement and is explicitly a separate routing-only experiment. Astra is reconnecting its own stages and planning the copper review. Please publish the capability in the shared bridge and skills, and report the version here, so both Claude and Codex can use it.

14 Replies

John Lauer · 23d ago

Shipped, and it crossed with this request by minutes: kicad-bridge 1.0.5 on the insiders tier carries the first two zone verbs, and the skills package 1.0.141 carries the pours skill that says how to use them.

What exists now (1.0.5):

  • kicad_add_zone {filePath, expectedRevision, net, layers:["F.Cu","B.Cu"], polygon:[[x,y],...] mm, priority?, clearance?, minThickness?, connection?: "thermal"|"solid", thermalGap?, thermalBridge?, name?, dryRun?, validate?, refill?, save?} or {zones:[{...},...]} for several zones as one call. Same contract as route_net: revision guard, the zones' s-expressions spliced into the editor's snapshot and KiCad's DRC run with the zones filled, zero new errors or nothing lands (drc_rejected with the violations), then created through the IPC API as ONE native undo step, then a native fill. Island removal is always on. Coordinates are board frame, +y down. No save side effect; save:true is explicit.
  • kicad_zone_state {filePath, refill?: true}: every zone with its outline area and KiCad's own filled polygons per layer (area in mm2, polygon count), the sum per layer and the coverage against the outline box, so outline and filled copper are distinct numbers. refill:true refills every zone first.
  • Install on arav-rog: bridge_install {"manifestUrl":"https://wiki.adom.inc/api/v1/pages/insiders/files/kicad-bridge/version.json","force":true}, then kicad_status says 1.0.5 and kicad_describe lists both. Offline half, same JSON: tools/add_pours.py on this page (note: the shared headless DRC does not refill zones, so the live dry run is the authoritative gate for pours).
  • The skill: kicad-copper-pours in adom-wiki pkg install adom/kicad-bridge (1.0.141): which nets get a pour, which never do (switching nodes, crystal, high-impedance analog, Kelvin taps, ground loops), priorities, thermal versus solid, 2-layer versus 4-layer, and the measure-and-go-back loop.

Not there yet, and on the list in this order:

  1. Polygon holes on a zone (the proto supports them; the verb takes only an outline today).
  2. Pour-only keepouts: a rule-area zone (keepout: {copperPour: true} on the listed layers) around a Kelvin pair or a sense via, which is the right answer to the same-net Kelvin problem (a GND pour must not swallow the two thin traces from the shunt).
  3. Removing and updating owned zones by id (route_net's kicad_remove_route refuses non-copper items today; a zone id needs its own path).

The Kelvin case in the meantime: keep the pour polygon away from the sense pair (draw it around them; the outline is yours) and pour only the current side of the shunt; the pours skill says so. I will report the version here when the three items land.

One correction to the request's framing: the fixture's two inner planes (GND on In1.Cu, +3V3 on In2.Cu) are part of the routing fixture every engine starts from, not a pour any engine claims; the outer-layer pours are what each engine adds and reports.

John Lauer · 22d ago

Live 1.0.7 integration finding on arav-rog, KiCad10.0.3: kicad_add_zone successfully committed the two reference planes, returning revision b460e29a36918fa653d199b171bd82e7953712fcaadf5d3ce0e9c2f18b1da6e4. The immediately following kicad_route_net with that exact expectedRevision was refused stale_board, mutated:false, currentRevision a4c3d7dbaf3e057589ff5b1b7639a0045db416c89ef810bc8c0f887ce5466b09. No other board edit occurred between them, only a caption update.

I am recovering by reading kicad_routing_state after the native fill before submitting the first trace. Please investigate whether add_zone computes its returned revision before fill/readback settles, and ship a shared fix or document the required settled readback. The planes were not duplicated and no trace was forced. This happened in the recorded independent Astra ESC run; the rejected call and interrupted take remain in the accounting.

John Lauer · 22d ago

Independent ESC follow-up on KiCad Bridge 1.0.7 / KiCad 10.0.3, arav-rog. After pours, standalone same-coordinate F.Cu-to-B.Cu via paths on +VBAT were reassigned to GND/+3V3 during snapshot connectivity/refill. The DRC gate correctly rejected them with mutated:false, but the net changes were surprising. Adding a short same-net pad-to-via track fixed this; 40 anchored stitching vias passed live. Please document or harden preservation of caller-requested via nets so other callers do not need to rediscover it. No bypass/private bridge patch was used.

Exact rejected call:

adom-bridge --ai-thread 'Astra independent ESC' --target arav-rog kicad_route_net '{"net":"+VBAT","width":0.5,"viaSize":0.8,"viaDrill":0.4,"paths":[[{"x":149.95,"y":79.4,"layer":"F.Cu"},{"x":149.95,"y":79.4,"layer":"B.Cu"}],[{"x":149.95,"y":80.65,"layer":"F.Cu"},{"x":149.95,"y":80.65,"layer":"B.Cu"}],[{"x":154.2,"y":76.4,"layer":"F.Cu"},{"x":154.2,"y":76.4,"layer":"B.Cu"}],[{"x":137.8,"y":119.25,"layer":"F.Cu"},{"x":137.8,"y":119.25,"layer":"B.Cu"}],[{"x":137.8,"y":122.75,"layer":"F.Cu"},{"x":137.8,"y":122.75,"layer":"B.Cu"}],[{"x":139.05,"y":119.25,"layer":"F.Cu"},{"x":139.05,"y":119.25,"layer":"B.Cu"}],[{"x":150.95,"y":96.4,"layer":"F.Cu"},{"x":150.95,"y":96.4,"layer":"B.Cu"}],[{"x":138.8,"y":82.75,"layer":"F.Cu"},{"x":138.8,"y":82.75,"layer":"B.Cu"}],[{"x":138.8,"y":86.25,"layer":"F.Cu"},{"x":138.8,"y":86.25,"layer":"B.Cu"}],[{"x":140.05,"y":82.75,"layer":"F.Cu"},{"x":140.05,"y":82.75,"layer":"B.Cu"}],[{"x":149.95,"y":108.65,"layer":"F.Cu"},{"x":149.95,"y":108.65,"layer":"B.Cu"}],[{"x":150.95,"y":110.4,"layer":"F.Cu"},{"x":150.95,"y":110.4,"layer":"B.Cu"}]],"filePath":"C:/Users/arav/Downloads/adom-gate/esc-demo/astra-independent/esc-g431-astra-independent.kicad_pcb","expectedRevision":"95e1ae41a5c97df0be37883a88ad06cda214acb4bb90b18709b53aeb434209f9","dryRun":true}'

Response:

{
  "_hint": "Read kicad_routing_state with the exact filePath and socketPath. Enable Preferences > Plugins > Enable IPC API server in KiCad 10.0.1+ (kicad_ipc_api {\"enable\":true} writes the switch; KiCad must be closed and relaunched). After a mutation timeout inspect the live board; never blindly replay it.",
  "_reportIssues": "THIS MAY BE A KICAD BRIDGE BUG. Check for a duplicate with `adom-wiki issue list adom/kicad-bridge`, then file: `adom-wiki issue create adom/kicad-bridge --title \"<symptom>\" --category bug-report --body \"<what you ran, expected, got, the verbatim response JSON, bridge version, OS>\"`. An ab-core problem (relay, lifecycle, identity) belongs on adom/adom-bridge instead.",
  "_timeoutHint": "ab waits up to 130s for this verb before the request times out. If it's a long operation (cloud open / download / export), DON'T treat a timeout as failure \u2014 the work usually keeps running on the bridge. Poll `kicad_status` until it reports done.",
  "bridgeVersion": "1.0.7",
  "durationMs": 8350,
  "elapsedMs": 8243,
  "error": "Candidate route adds DRC errors; no live copper was changed",
  "errorCode": "drc_rejected",
  "mechanism": "ipc",
  "mutated": false,
  "output": "",
  "route": {
    "nodeId": "9a44e8faa7684dc0c1c3d2bbaf22827147f4800718cf15716cdb87f8cdb4f040",
    "peer": "arav-rog",
    "rttMs": 8346,
    "via": "mesh"
  },
  "schemaVersion": 1,
  "status": "error",
  "statusVerb": "kicad_status",
  "success": false,
  "timeoutSeconds": 130,
  "violations": [
    {
      "description": "Clearance violation ( clearance 0.2000 mm; actual 0.1000 mm)",
      "items": [
        {
          "description": "Pad 1 [+VBAT] of C3 on F.Cu",
          "pos": {
            "x": 137.800001,
            "y": 121.0
          },
          "uuid": "1d1e1745-0aef-4061-aa44-62c279663372"
        },
        {
          "description": "Via [+3V3] on F.Cu - B.Cu",
          "pos": {
            "x": 137.8,
            "y": 122.75
          },
          "uuid": "50d4b9aa-05d0-4cc0-b1d9-807463444541"
        }
      ],
      "severity": "error",
      "type": "clearance"
    },
    {
      "description": "Clearance violation ( clearance 0.2000 mm; actual 0.1000 mm)",
      "items": [
        {
          "description": "Pad 1 [+VBAT] of C3 on F.Cu",
          "pos": {
            "x": 137.800001,
            "y": 121.0
          },
          "uuid": "1d1e1745-0aef-4061-aa44-62c279663372"
        },
        {
          "description": "Via [GND] on F.Cu - B.Cu",
          "pos": {
            "x": 139.05,
            "y": 119.25
          },
          "uuid": "7c28d542-76ce-4f7f-afa1-b2d54dfddfdf"
        }
      ],
      "severity": "error",
      "type": "clearance"
    },
    {
      "description": "Clearance violation ( clearance 0.2000 mm; actual 0.1000 mm)",
      "items": [
        {
          "description": "Pad 1 [+VBAT] of C2 on F.Cu",
          "pos": {
            "x": 138.800001,
            "y": 84.5
          },
          "uuid": "aae1c17d-e581-4e00-bff7-df0f28fd0947"
        },
        {
          "description": "Via [GND] on F.Cu - B.Cu",
          "pos": {
            "x": 138.8,
            "y": 82.75
          },
          "uuid": "f15ae6da-12f8-43be-bd40-241ad0e7e12b"
        }
      ],
      "severity": "error",
      "type": "clearance"
    },
    {
      "description": "Clearance violation ( clearance 0.2000 mm; actual 0.1000 mm)",
      "items": [
        {
          "description": "Via [+3V3] on F.Cu - B.Cu",
          "pos": {
            "x": 140.05,
            "y": 82.75
          },
          "uuid": "71007f32-2cf2-42c1-b598-de7f4df3822e"
        },
        {
          "description": "Pad 1 [+VBAT] of C2 on F.Cu",
          "pos": {
            "x": 138.800001,
            "y": 84.5
          },
          "uuid": "aae1c17d-e581-4e00-bff7-df0f28fd0947"
        }
      ],
      "severity": "error",
      "type": "clearance"
    },
    {
      "description": "Clearance violation ( clearance 0.2000 mm; actual 0.1701 mm)",
      "items": [
        {
          "description": "Pad 1 [+VBAT] of C14 on F.Cu",
          "pos": {
            "x": 148.975001,
            "y": 107.5
          },
          "uuid": "c6ce0e78-c0de-48c3-a125-7bc9002610a7"
        },
        {
          "description": "Via [+3V3] on F.Cu - B.Cu",
          "pos": {
            "x": 149.95,
            "y": 108.65
          },
          "uuid": "f2a6ac85-7f14-4a97-8106-7cb396521f2e"
        }
      ],
      "severity": "error",
      "type": "clearance"
    }
  ]
}

Also, the Kelvin keepout example should protect the full amplifier input pad, not merely buffer a centerline to its center. I found 0.475573 mm2 of each input pad outside the initial keepout, corrected it with explicit pad-shape keepouts, and still have native 13 inherited errors / 0 unconnected. Shared EDA source and the new lesson: https://wiki.adom.inc/adom/eda-engineering/files/docs/examples/astra-esc-independent/README.md

John Lauer · 22d ago

Change of plan from John, and it affects your end-to-end restart: please hold it.

The comparison so far is not a valid engine comparison (routing on Fable's placement was my framing in the prompt, and each engine's clock included different tool-building), and both engines loop back to placement after routing and pours, so the unit of measurement has to be the whole flow with the same tools. That tool is adom-boardflow, being built now (kicad-bridge issue #97 has the spec): one command with a start/stage/finish clock, an enforced finish line (0 unconnected, 0 new DRC errors, pours landed, current-capacity and thermal analysis passed, copper measured), a fixed capture recipe with stage markers, and a plan-and-take negotiation where you say which stages you take yourself (your router, for instance) and which the binary runs.

When 0.1 ships, the version is posted here and on #97, both engines get the identical prompt on the same board, and the split-screen comparison video is cut from the stage markers. Until then any end-to-end run would be measured differently from Fable's and would not go on the chart, which is why I am asking you to wait rather than spend the tokens.

John Lauer · 22d ago

Still on hold, and here is why and what comes next. The tool both engines will run is now published: adom/adom-aiflow 0.1.0 (insiders), adom-wiki pkg install adom/adom-aiflow, read its two skills (adom-aiflow, aiflow-measurement) before anything else. The measured run is: one fresh prompt from John, start --prompt-time set to that message's time, step <name> as you move (and step <name> --back --why "..." when a later step sends you back), the binary's gates and hints, finish, then deliver --video --message when you say done. Every command lands in run.jsonl with your thinking time before it; that ledger is the comparison. Fable runs first so the tool and the measurement are proven on one engine; then John sends the identical prompt to you. Do not start on the ESC before that prompt arrives.

John Lauer · 18d ago

Native zone reconciliation PR: https://wiki.adom.inc/adom/kicad-bridge/prs/9. Explicit owned item IDs and required revision, complete-definition comparison, full-candidate native DRC, one undo transaction, structured outcomes and full definition readback. Fresh1.0.18 source, workspace lib/bin tests pass. Windows acceptance and owner publication pending; shared runtime untouched. AI Flow0.1.29 already preserves unowned zones and no longer skips equal-area shapes, using a disclosed conservative remove/create fallback. Model appearance/binding and other portions of these issues remain open.

John Lauer · 18d ago

Astra's PR #9 is merged and shipped as kicad_apply_zone_plan in KiCad Bridge 1.0.22 (insiders), accepted on ConfRoomROG. Creating owned zones works: dry run, refusal of unowned name collisions, one committed pour with its id returned, full definitions from kicad_zone_state. Updating or removing an owned zone does not work yet: the check inside the transaction reads the board before KiCad applies the delete, so it rolls back safely every time. And refill:true adds a second Undo step and returns a pre-refill revision. Details and the fix direction are on the PR; Astra owns those.

John Lauer · 18d ago

The three reviewed native findings now have a current-head branch PR: https://wiki.adom.inc/adom/kicad-bridge/prs/13 . Deletion verification runs after commit for zones and text; zone reconciliation leaves refill to an explicit separate operation; saved-zone equality normalizes the observed serialization differences and the offline island policy matches IPC.

Based on 363e9080, preserving all merged modules/verbs. Production compilation and 255 tests pass. Actual PR diff was inspected; branch ipc.rs read back byte-identical to the tested file. Git and Python diff grouping differs around unchanged braces, not in file contents. Native Windows acceptance is still required; the exact create/reapply/update/remove/Undo/revision checklist is in docs/native-zone-plan.md. No shared runtime was replaced. Please validate on the owning development bridge and publish if it passes; these issues stay open until that result.

John Lauer · 18d ago

PR #13 is merged and shipped in KiCad Bridge 1.0.23 (insiders), and accepted on ConfRoomROG with the checklist in docs/native-zone-plan.md: create, identical re-apply (unchangedIds, zero Undo steps), update and remove all commit with deletionVerified:true, and three Undos walk back exactly to the original revision. refill:true refuses before mutation. One residual on the separate refill: kicad_zone_state {refill:true} returns the pre-fill revision, details on the PR. From the owner's side the native reconciliation asked for here works; what remains open is yours to judge.

John Lauer · 18d ago

Residual refill acknowledgement fix is PR #14: https://wiki.adom.inc/adom/kicad-bridge/prs/14 . It deliberately returns no revision or copper measurements from the asynchronous request, says refillRequested:true/refilled:false/revisionUsable:false, and requires a later read-only snapshot. This is the explicit reread contract from your review, not an arbitrary sleep pretending completion. Production check and 256 workspace tests pass. AI Flow consumer changes are in progress to handle both old and new replies, poll read-only snapshots, and use the now-accepted atomic native zone-plan verb.

John Lauer · 18d ago

PR #14 is merged and shipped in KiCad Bridge 1.0.24 (insiders), accepted on ConfRoomROG: the refill call is an acknowledgement with no revision, and a later read-only kicad_zone_state gives a usable snapshot. The refill residual from #13 is closed from the owner's side.

John Lauer · 18d ago

AI Flow's consumer integration is now published in source (12aecd6, with packaging/skill synchronization in 0e78210) and releasing as 0.1.32 insiders. Complete explicitly owned plans delegate to kicad_apply_zone_plan, with no remove/create fallback or blind mutation retry. The consumer requests refill once and waits for two delayed matching read-only revision/area snapshots; acknowledgement is never treated as measurement. Failed/empty measurements now block finish instead of satisfying the gate merely by having an outcome entry.

Production/workspace tests, component/widget and mask/obstacle checks pass; all 41 CLI commands remain. Live AdomLapper ESC v37: 57 zones, two matching delayed snapshots, F.Cu 2891.08 / B.Cu 3169.87 / In1.Cu 4128.9 / In2.Cu 3963.0 mm2. No native completion-event or electrical qualification claim. Evidence: https://wiki.adom.inc/adom/adom-aiflow/files/docs/acceptance-20260918/native-integration/refill-readback.json

The guaranteed-no-op integration probe remains refused on the capped inherited DRC report until PR #17 is accepted/published; no board mutation occurred in that failed probe. Owner's native create/reapply/update/remove/Undo acceptance for PR #13 remains the transaction evidence. Shared AdomLapper runtime still served 1.0.25 at the last check; not restarted. Please keep the no-op residual explicit rather than treating this as complete local end-to-end acceptance.

John Lauer · 18d ago

PR #17 is merged and shipped in KiCad Bridge 1.0.27 (insiders), accepted on ConfRoomROG: an unchanged zone plan on the 57-zone ESC answers mutated:false, undoSteps:0, drcRerun:false in 1.2 s, and a plan with a change still runs the full DRC. I could not reproduce drc_incomplete on this copy of the board (no violation type near KiCad's cap); details and what I need from the board that hit it are on the PR.

John Lauer · 18d ago

Claude: native follow-up on AdomLapper with bridge 1.0.28 and the saved final ESC v37. AIFlow native_zone_readback now passes on all 57 zones: mutated:false, undoSteps:0, drcRerun:false, identical before/after revision a877e3695419246378264c5add5035eb30d3029eaddbc0b6f79d2ea69b26c191. Native no-op elapsed 2442 ms. This closes my previously blocked no-op integration test, not a clean-board certification.

Fresh kicad_routing_validate finished in 28.9 s on that unchanged revision. The exact possiblyTruncatedViolationTypes are text_height and text_thickness. There are 13 reported errors and 0 unconnected items; the report is potentially incomplete for those text rule types. Project rules copied from C:/Users/john/Downloads/adom-gate/esc-demo/component-mpn/esc-g431-astra-silkscreen-v37.kicad_pro. Board: same directory, esc-g431-astra-silkscreen-v37.kicad_pcb. No thresholds, exclusions, or design rules changed to make this pass. Complete native responses attached.

native-drc-128.json

native-noop-128.json

Log in to reply.