← All Pull Requests

Allow unchanged native zone plans without a redundant DRC run #17

Merged opened by John Lauer 2026-09-18
Merges astra/zone-noop-readback → master

AI Flow's native integration probe hit drc_incomplete on the final 57-zone ESC even with ownedItemIds:[] and zones:[], a guaranteed no-op. No live board changed. kicad_apply_zone_plan currently reruns two DRC snapshots before discovering that no mutation is needed; inherited report truncation therefore blocks its idempotent path.

This patch returns the exact-native-definition no-op before DRC, with mutated:false, undoSteps:0 and drcRerun:false. It explicitly does NOT certify DRC cleanliness. Any actual create/update/remove still takes full candidate preflight. A dry run with changes still runs DRC. Base: 6e873f2b7afa57d5d5552909b2eb0cd544edacba (1.0.25), one focused function hunk. Preserves all shipped modules and verbs; preserves the merged graphics module.

Production cargo check and 258 workspace tests pass. Native acceptance pending: rerun the no-owned/no-desired plan against the capped-report ESC; expect unchanged revision and mutated:false without DRC. Repeat an identical owned plan. Confirm a changed plan still rejects DRC findings. No shared runtime replaced. Evidence: source acceptance example crates/aiflow-bridge/examples/native_zone_readback.rs in AI Flow; actual old reply was drc_incomplete, mutated:false after 57 seconds.

Diff Skip to comments (1)

rust/crates/kicad-core/src/ipc.rs+12−1
@@ -931,6 +931,17 @@ pub fn apply_zone_plan(ctx: &Ctx, args: &Value) -> RResult<Value> {     let (text, board, revision) = s.snapshot()?;     check_revision(args, &revision)?;     let plan = crate::zone_plan::prepare(&text, &board, args)?;+    if plan.remove.is_empty() && plan.create.is_empty() {+        // No candidate differs from the current board. A capped inherited DRC+        // report must not turn an idempotent read into a failed mutation.+        return Ok(json!({+            "success":true,"mutated":false,"undoSteps":0,"revision":revision,+            "dryRun":args["dryRun"]==true,"unchangedIds":plan.unchanged,+            "ownedItemIds":plan.unchanged,"itemIds":[],"removedIds":[],+            "drcRerun":false,"_hint":"Native zone definitions already match; no edit or DRC rerun. This is not a DRC-clean certification."+        }));+    }+     let before = drc_snapshot(ctx.kicad_cli.as_deref(), &s.source_path(), &text)?;     let check = drc_snapshot(ctx.kicad_cli.as_deref(), &s.source_path(), &plan.candidate)?;     let added = new_errors(&before, &check)?;@@ -942,7 +953,7 @@ pub fn apply_zone_plan(ctx: &Ctx, args: &Value) -> RResult<Value> {         .with("violations", json!(added))         .with("mutated", json!(false)));     }-    if args["dryRun"] == true || (plan.remove.is_empty() && plan.create.is_empty()) {+    if args["dryRun"] == true {         return Ok(             json!({"success":true,"mutated":false,"dryRun":args["dryRun"]==true,"revision":revision,"unchangedIds":plan.unchanged,"wouldRemoveIds":plan.remove,"wouldCreate":plan.create.iter().map(zones::ZoneSpec::public).collect::<Vec<_>>(),"drc":check,"undoSteps":0}),         );

Comments

John Lauer 2026-09-18

Merged on the wiki (ae92505), shipped as KiCad Bridge 1.0.27 (insiders), accepted on ConfRoomROG against the open 57-zone esc-g431-astra board, all read-only.

check result
ownedItemIds:[], zones:[] success:true, mutated:false, undoSteps:0, drcRerun:false in 1.2 s (the reply you quoted took 57 s to reach drc_incomplete)
dry run adding one small pour went to DRC as it should (73 s on this board) and came back drc_rejected with the real added findings, mutated:false

One thing I could not reproduce: drc_incomplete itself. On this copy of the board kicad_routing_validate reports possiblyTruncatedViolationTypes: [] (38 lib_footprint_issues warnings, 23 silk_over_copper, 7 clearance errors, 6 courtyards; nothing near KiCad's 199-per-type cap). So the capped report your probe hit came from a different board state, most likely the routed one with hundreds of clearance markers. The cap is KiCad's DRC engine, not the bridge, and on such a board a plan that actually changes something will still be refused. If you have that board, the exact possiblyTruncatedViolationTypes from kicad_routing_validate on it is what I need to decide whether the delta check can safely ignore a capped type that carries only warnings.

Closing.

Log in to comment.