Close the CM5 autorouting verdict's last unknowns (0 unknown, per-connection certificates)#677
Conversation
Choji has used up today's reviewsYour team has reached the free plan's limit of 5 reviews per day, so Choji stepped aside on this pull request. That's a plan limit, not a reflection of the change itself. Your free reviews reset tomorrow. To have Choji review every push without waiting, upgrade to Pro for unlimited reviews. You're on the free plan · 5 reviews/day. |
…on certificates The verdict ladder ended at "16 proved-infeasible + 27 unknown" for reasons that were budget and discretization artifacts, not physics. It now reaches zero unknowns on the best CM5 board — 44 routed / 51 proved-infeasible / 0 unknown, converging to a fixed point on a second pass (45 proved, 0 newly routable) — and every certificate names the copper forming its cut. What closes them: - k = 1 is decided by reachability, not by the exhaustive DFS. A lone connection cannot trip an expansion budget: BFS returns a shortest path or an exhausted reachable component, which *is* the proof. This is what makes splitting a cluster terminate. - A cheap sequential-BFS witness pass runs before the DFS for joint instances. The DFS's first descent is a greedy walk, not a shortest path, so on a wide window it could wander for millions of expansions before its first completion — the dominant source of unknowns. - WindowBudget couples the expansion budget to a cells-per-axis cap, so a wider window keeps its pitch at the width+separation floor instead of coarsening until unrelated terminals collide in one cell. - The driver escalates instead of accepting an unknown: joint at 1x/5x/25x budget, then per connection in its own 2/8/20 mm window. A joint infeasibility is no longer charged to the individual connections — it says only that the k cannot all be routed at once, so each earns its own verdict. - The pitch is pair-aware: twins in one window are spaced by their declared gap, restoring "distinct cells ⇒ mutually legal" for pairs. Certificates got sharper, not weaker: the severed case reports whichever terminal's pocket is smaller, with the enclosing cut's size, extent, and the nets holding it; the walled-in case names the pad's layers and its blockers. Three legality gaps that let "routed" copper fail the board are now closed in the session oracle, which is what keeps the new copper DRC-clean: - probe_drill / commit_drill: hole-to-hole across layer spans and nets. Two vias on disjoint spans share no layer, so no layer-scoped copper probe ever compared them — they landed as drill collisions. - Terminals can be pinned to the layers their net actually has copper on, with a probed dog-bone escape (stub on the pad's layer, barrel checked on every layer it spans) when the search wants another layer. Stubs no longer float on an inner layer with nothing joining them to the pad. - set_strict_pair_coupling scores the intra-pair gap the way the DRC does, pads and via annuli included, with the DRC's 1.5 mm pad-breakout exemption mirrored. Opt-in: it is stricter than the geometry the pair router realizes today, so the verdict driver turns it on and pays in routability. Board DRC vs the same input: Clearance 74 (baseline floor, unchanged), Short 1315 (unchanged), MinTraceWidth 69 (unchanged), HoleToHole 0 (unchanged), UnconnectedNet 252 -> 223. NetIslands 18 -> 30 is the accounting shift for 19 nets that had no copper at all and now carry partial copper; an independent connectivity check finds zero floating groups — every committed path is galvanically attached to its net's pads or existing copper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
cf3372f to
2da37c4
Compare
|
Rebased onto Verified locally against
Overlap worth resolving before merge#672 ( One substantive difference to settle either way: #672 skips same-net holes ( #681 ( |
main gained its own drill index in #677 (`DrillElement` / `probe_drill` / `commit_drill`), so this branch's parallel `SessionHole` / `probe_hole` / `commit_hole` is dropped and its wiring re-expressed on main's API. What survives is the part #677 left unfinished: - `commit_drill` now returns a `SpanId` and the barrel is tombstoned like any other span, so rip-up-and-reroute takes the hole out with the copper. Without this the router walls itself in — every via it tried and abandoned would keep its ground forever. `probe_drill` skips dead barrels; the index compacts on the same half-tombstone rule as copper. - The check is wired into every via-placement path, not just the complete window router: the maze's in-search `via_ok` (so A* avoids bad sites instead of failing at commit), the escape/stitch `via_legal`, and `validate_and_commit`'s gate. `commit_via` indexes the barrel, which is what makes router-vs-router collisions visible at all — on main `commit_drill` had no production caller, so only pre-existing board holes were ever seen, and the CM5 failure mode (two *router-placed* vias) was still open. - `via_drill_for` / `probe_via_drill` size a candidate from its net class the way `legalize::via_geom_for` does on write-back, so no call site has to plumb drill diameters. Adopts main's net-agnostic semantics: the hole rule ignores nets, which matches `drc::check_hole_to_hole` exactly and is stricter than this branch's earlier same-net exemption. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every connection on the best CM5 board now ends ROUTED or PROVED-INFEASIBLE — no unknowns — and every certificate names the copper forming its cut.
Result
The 31 unknowns were 28 cluster-level budget trips, 1 singleton budget trip, and 2 paths the fail-closed oracle rejected — budget and discretization artifacts, as expected.
What closes them
WindowBudgetcouples the expansion budget to a cells-per-axis cap, so a wider window keeps its pitch at thewidth + separationfloor instead of coarsening until unrelated terminals collide in one cell. (Lever 2, done the right way: cap raised with the cell budget.)Certificates got sharper, not weaker. The severed case reports whichever terminal's pocket is smaller, with the enclosing cut's node count, extent, and the nets holding it; the walled-in case names the pad's own layers and its blockers. All 51 name real copper:
Three legality gaps closed in the session oracle
Routing more connections surfaced three ways "routed" copper could still fail the board. Fixing them is what keeps the new copper DRC-clean:
probe_drill/commit_drill— hole-to-hole across layer spans and nets. Two vias on disjoint spans share no copper layer, so no layer-scoped probe ever compared them; they landed as drill collisions (the durable fix for a known open item). A via barrel is also now probed on every layer it spans, and consecutive transitions at one point merge into one barrel instead of stacking drills at zero spacing.TerminalLayers— terminals can be pinned to the layers their net actually has copper on, with a probed dog-bone escape (stub on the pad's layer, barrel checked across its span) when the search wants a different layer. Previously a stub took the first free layer, which on a 10-layer board is usually not the pad's: 142 of 162 new pad-touching stub ends were electrically dangling.set_strict_pair_coupling— scores the intra-pair gap the way the DRC does, pads and via annuli included, with the DRC's 1.5 mm pad-breakout exemption mirrored. Opt-in, because it is stricter than the geometry the pair router realizes today (its dog-bone offsets and jogs are sized to base clearance); the verdict driver turns it on and pays for it in routability. Flipping the default needs the pair router's geometry fixed first — noted below.DRC (same input board,
drc_json)No new route-attributable violations. NetIslands +12 is an accounting shift: all 19 newly-listed nets had zero copper on the base board (they were UnconnectedNet entries) and now carry partial copper — some MST edges routed, the rest proved infeasible. An independent connectivity check over all 41 touched nets finds zero floating groups: every committed path is galvanically attached to its net's pads or pre-existing copper, with no zero-length traces and no coincident vias.
Verification
cargo test -p vcad-ecad-pcb— 252 passed, 0 failed (4 new tests: lone connection never unknown, severed connection proved with a named cut, pinned terminals attach on their own layer, drill probe sees holes no copper probe could).cargo clippy -p vcad-ecad-pcb --features gpu -- -D warnings— clean. (--all-targetsreports twoitems after a test modulelints inrouter/auto.rsandrouter/si_claims.rs; both are pre-existing on main, confirmed by stashing.)cargo fmt --all --check— clean.Follow-up (not in this PR)
The pair router emits dog-bone offsets and jogs that come a gap-width short of the DRC's pair rule (a leg trace 0.175 mm from its twin's via, where the DRC requires 0.245 mm mid-board). Repro:
router::pair::tests::pair_layer_transition_keeps_twin_clearancewithset_strict_pair_coupling(true). Fixing that geometry is what would let strict coupling become the default.🤖 Generated with Claude Code