Releases: seunghyukchoe/copper-mcp
Release list
v0.12.0
What's Changed
Documentation and maintenance
- docs(release): record v0.11.0 publication by @seunghyukchoe in #233
- stray footprint copper: census, bounded envelope, named refusals by @seunghyukchoe in #230
- M3 E3: first real-editor IPC observation, and the ADR-0095 text-to-shape measurement by @seunghyukchoe in #234
- Repair live benchmark contract replays by @seunghyukchoe in #235
- test(board-ir): freeze root-zone field census contract by @seunghyukchoe in #236
- feat(routing): negotiate bounded multi-pin local lattices by @seunghyukchoe in #237
- chore(release): prepare 0.12.0 by @seunghyukchoe in #243
- chore(release): supersede 0.12.0 authorization on main source by @seunghyukchoe in #246
Other changes
- feat(board-ir): inscribe convex Edge.Cuts outline arcs, and measure that it converts nothing by @seunghyukchoe in #228
- feat(routing): repair one responsible multi-pin branch by @seunghyukchoe in #238
- chore(release): authorize v0.12.0 by @seunghyukchoe in #245
Full Changelog: v0.11.0...v0.12.0
v0.11.0
What's Changed
Documentation and maintenance
- docs(release): record v0.10.0 publication by @seunghyukchoe in #221
- feat(mcp): translate refusals to ToolError, lift the 2.1 cap (#217) by @seunghyukchoe in #222
- feat(board-ir): accept the setup fields that cannot reach copper by @seunghyukchoe in #225
- fix(benchmarks): survive EPERM from killpg on PID recycle by @seunghyukchoe in #224
- footprint container-allowlist wall: census, per-field decision, named refusals by @seunghyukchoe in #226
- chore(release): prepare 0.11.0 by @seunghyukchoe in #227
- chore(release): supersede 0.11.0 authorization on main source by @seunghyukchoe in #232
Other changes
- chore(release): authorize v0.11.0 by @seunghyukchoe in #229
Full Changelog: v0.10.0...v0.11.0
v0.10.0
What's Changed
Documentation and maintenance
- feat(routing): verify external multi-path candidates by @seunghyukchoe in #201
- Profile the complete Board IR read path by @seunghyukchoe in #204
- fix(routing): calibrate layered fill island bounds by @seunghyukchoe in #205
- docs(release): record v0.9.0 publication by @seunghyukchoe in #198
- measure(routing): census whole-board negotiated routing on the corpus (#90) by @seunghyukchoe in #210
- measure(benchmarks): close M3 frozen apply census by @seunghyukchoe in #212
- measure(board-ir): map fixed-point conversion blockers by @seunghyukchoe in #214
- measure(board-ir): add closed public setup-field census by @seunghyukchoe in #216
- chore(release): prepare 0.10.0 by @seunghyukchoe in #218
- chore(release): supersede 0.10.0 authorization on main source by @seunghyukchoe in #220
Other changes
- feat(routing): add bounded external candidate disposer by @seunghyukchoe in #199
- docs(benchmarks): record B-119 dimension refutation by @seunghyukchoe in #200
- feat(routing): bind external candidates to KiCad DRC by @seunghyukchoe in #202
- feat(routing): publish external candidate verification by @seunghyukchoe in #203
- feat(routing): verify negotiated local repair by @seunghyukchoe in #206
- feat(routing): define deferred authoritative signoff by @seunghyukchoe in #207
- Adapt routed SimpleRouteJson output for external verification by @seunghyukchoe in #208
- Explain why apply authority is withheld by @seunghyukchoe in #211
- feat(routing): admit DFM signoff on repeated DRC agreement by @seunghyukchoe in #213
- chore(release): authorize v0.10.0 by @seunghyukchoe in #219
Full Changelog: v0.9.0...v0.10.0
v0.9.0
What's Changed
Documentation and maintenance
- docs(release): record the v0.8.0 publication with its provenance by @seunghyukchoe in #177
- docs(audit): post-0.8.0 audit and the improvement plan (P0–P7) by @seunghyukchoe in #178
- measure(corpora): the third-party corpus does not convert, and its licence does not cover its data (#110) by @seunghyukchoe in #179
- feat(board-ir): a schema version moves with its accepted set (#172) by @seunghyukchoe in #181
- feat(process): the failures this project paid for become checkers by @seunghyukchoe in #184
- feat(evidence): comparability on DRC counts, typed refusal on fill (#170, #166) by @seunghyukchoe in #185
- feat(benchmarks): a cross-router table types every baseline, and no board converts by @seunghyukchoe in #183
- docs: record Step 4 third-party conversion refutation by @seunghyukchoe in #193
- chore(release): prepare v0.9.0 by @seunghyukchoe in #194
- chore(release): authorize v0.9.0 by @seunghyukchoe in #195
- chore(release): reauthorize v0.9.0 after CI repair by @seunghyukchoe in #197
Other changes
- feat(routing): a layered candidate records the model that produced it (#164) by @seunghyukchoe in #180
- docs(board-ir): every reader of pad geometry, and the direction each needs (#116) by @seunghyukchoe in #182
- feat(board-ir): accept thermal bridge angles as disclosed metadata by @seunghyukchoe in #190
- fix(placement): bracket boundary parity verdicts by @seunghyukchoe in #191
- feat(board-ir): support custom pad copper envelopes by @seunghyukchoe in #192
- test(release): allow authorized unpublished version by @seunghyukchoe in #196
Full Changelog: v0.8.0...v0.9.0
v0.8.0
What's Changed
Documentation and maintenance
- fix(board-ir): accept root board properties as counted metadata (#140) by @seunghyukchoe in #150
- fix(board-ir): a courtyard keeps out on the layer it is drawn on (#151) by @seunghyukchoe in #154
- docs(evidence): audit all mutation claims and commit a reproducible harness (ADR-0098) by @seunghyukchoe in #155
- docs(survey): close out the #116 real-board survey against a fresh measurement by @seunghyukchoe in #156
- test(security): make the excessive-agency evaluation observe a permit by @seunghyukchoe in #160
- fix(config): calibrate the fill-vertex budget and price the change (#165) by @seunghyukchoe in #168
- docs: re-verify every user-facing and architecture claim for 0.8.0 by @seunghyukchoe in #173
- docs(release): record what 0.5.0 and 0.7.0 actually published (D-196) by @seunghyukchoe in #174
- chore(release): cut 0.8.0 and recalibrate the release-gate budget by @seunghyukchoe in #175
- chore(release): authorize v0.8.0 by @seunghyukchoe in #176
Other changes
- fix(board-ir): copper text has no derivable envelope, and refuses saying so (#141) by @seunghyukchoe in #148
- feat(board-ir): convert an edge-connector pad as SMD, and count the token it discards by @seunghyukchoe in #149
- fix(board-ir): a pad refusal names its field, and seven fabrication properties convert (ADR-0099, D-189, R-144, SEC-140, B-103) by @seunghyukchoe in #157
- fix(board-ir): a custom pad refuses by name, and the name says why (#153) by @seunghyukchoe in #158
- fix(routing): close #63 as delivered, and gate the single-layer fill shrink like the layered one by @seunghyukchoe in #162
- fix(routing): a candidate replays under the model that produced it (#163) by @seunghyukchoe in #169
- docs(release): the 0.8.0 migration note, and a changelog audited rather than moved by @seunghyukchoe in #171
Full Changelog: v0.7.0...v0.8.0
v0.7.0
Real boards, and the refusals that stop them.
Upgrading from 0.6.0: read the 0.7.0 migration notes first. Five changes break something a working 0.6.0 deployment can depend on.
Highlights
ROUTER_VERSION moves to astar-grid/0.7.0. Every held candidate_id and bundle_id stops reproducing. No path geometry moved — this is the one change in the release that invalidates stored data, and it has its own migration section.
One obstacle budget was metering three different populations. 61 of 93 route refusals were the routed net's own copper charged to a budget named for copper it must avoid — a category error, not a capacity problem. Split into three discriminated budgets, with the obstacle model scoped to a routing region and the search confined to the same region, which is what makes the scoping sound rather than merely cheaper.
A locked (group …) now refuses instead of silently unlocking its members. BOARD_ITEM::IsLocked() derives lock from the parent group, so a locked group locks every member transitively with nothing in the member's own s-expression saying so. Members would have converted at locked=False past three authorization gates.
Pad zone_connect overrides that attach are accepted; the one that detaches still refuses. Accepting 0 could have made Board IR assert attachment over a deliberately isolated pad. Along the way: seven named pad refusals turned out to be unreachable dead code behind a generic allowlist check, so the message the original issue quoted was one the adapter could not emit.
Net-tie copper converts as a netless obstacle — something to route around, never a connection. The two deliberately shorted nets are never reported as connected.
Off-grid refusals now carry evidence: the pad, the lattice pitch, the signed per-axis miss in nanometres, and the largest representable step. The measurement that produced it refuted the hypothesis it was meant to confirm — re-previewing all 18 real-board off-grid refusals at exactly their own representable step, with the node budget at its ceiling, routed none of them. The lattice is where the refusal is reported, not where the constraint is.
Our own DRC payload failed our own published schema, and the schema then failed the other way too: clean: true beside a nonzero finding count validated. Both derived flags are now enforced in both directions, so a schema-only consumer cannot accept what the runtime refuses.
Honest numbers
Board IR converts 11 of the 12 boards in the #116 survey set, which is 11 of all 17 boards in that corpus as saved today. Six typed refusals across three constructs, each tracked: edge-connector pads (#138), root board properties on four saves (#140), a root copper graphic (#141).
Route preview routes 0 of 385 previews on that corpus today. An earlier 0 → 14 figure was measured on the corpus as it stood on 2026-08-07; those boards have since changed. An old-code/new-code differential on today's boards returns byte-identical verdicts across all seven codes, so nothing here regressed routing — the corpus moved, not the code.
Route preview runs one net at a time on F.Cu against the unrouted snapshot, so candidates are not mutually compatible and this is not a whole-board completion result. Placement preview ran without rules, so a clean verdict means legal-as-found, not placement quality. Neither surface makes an electrical, thermal, signal-integrity or manufacturing claim.
Gates
2,518 tests, 1 skipped, 760 subtests locally including the real-KiCad nodes; 2,438 passed with 81 environment skips across Python 3.11, 3.12 and 3.13 on hosted runners. Ruff, strict mypy over 97 source files, four repository checkers, CodeQL, dependency and secret audit, and OpenSSF Scorecard — all green on the exact source commit. The full evidence, including the one gate that could not run locally, is in the release ledger.
One thing the release build caught
The default source distribution was 124 MB across 20,452 files — it had swept in twenty-eight agent worktrees, because hatchling reads .gitignore and this repository excludes them through .git/info/exclude. The sdist now ships an explicit allowlist rather than an exclusion list: 717 files, 4.8 MB.
v0.6.0
What's Changed
Documentation and maintenance
- feat(routing): add immutable route bundle preview by @seunghyukchoe in #57
- feat(routing): add bounded multilayer proposals by @seunghyukchoe in #58
- chore: professionalize repository structure and documentation by @seunghyukchoe in #81
- feat(placement): add route-aware scoring by @seunghyukchoe in #59
- fix(kicad): harden the live IPC observation boundary by @seunghyukchoe in #86
- fix(ledgers): validate ledger and ADR identifier allocation by @seunghyukchoe in #85
Other changes
- fix(placement): refuse non-orthogonal saved poses with a typed diagnostic by @seunghyukchoe in #79
- test: pin golden identities for every content-addressed surface by @seunghyukchoe in #84
Full Changelog: v0.5.0...v0.6.0
v0.5.0
What's Changed
Features
- feat: serialize replayed candidates to disposable KiCad snapshots by @seunghyukchoe in #25
Research and performance
- test: add reproducible A*/Dijkstra routing baseline by @seunghyukchoe in #24
Documentation and maintenance
- fix: recover and harden v0.1.0 release by @seunghyukchoe in #20
- chore: upgrade CodeQL actions atomically by @seunghyukchoe in #21
- feat: add canonical Board IR v0.1 by @seunghyukchoe in #22
- docs: record measured router coverage on a real board by @seunghyukchoe in #32
- feat: ship bounded Circuit Intent schematic MVP by @seunghyukchoe in #34
- feat: multi-pin tree routing over sequential component merging by @seunghyukchoe in #35
- feat: zone fill authority — freshness-verified fill as connectivity evidence by @seunghyukchoe in #37
- chore: prepare the 0.3.0 release source by @seunghyukchoe in #38
- chore: prepare the 0.4.0 release source by @seunghyukchoe in #44
- feat(board-ir): add revision-bound footprints by @seunghyukchoe in #47
- feat(mcp): add revision-bound live route and placement proposals by @seunghyukchoe in #51
- feat: advance routing evidence and courtyard fidelity by @seunghyukchoe in #55
- chore(release): prepare v0.5.0 by @seunghyukchoe in #56
- fix(release): honor latest ready authorization by @seunghyukchoe in #60
- docs(release): correct v0.5.0 authorization by @seunghyukchoe in #61
Other changes
- feat: add bounded deterministic two-pin A* baseline by @seunghyukchoe in #23
- feat: bind route candidates to authoritative KiCad DRC by @seunghyukchoe in #27
- feat: expose a bounded non-mutating route preview by @seunghyukchoe in #28
- feat: add read-only Board IR inspection over a shared request boundary by @seunghyukchoe in #30
- feat: route around existing copper instead of rejecting it by @seunghyukchoe in #31
- feat: treat through vias as obstacles instead of a board-level veto by @seunghyukchoe in #33
- feat: via-aware cross-layer connectivity recognition by @seunghyukchoe in #36
- feat: Circuit Scene IR v0.1 — typed board observation for agents by @seunghyukchoe in #39
- feat: Scene IR slice 2 — deterministic digest-bound renders by @seunghyukchoe in #40
- fix: absolute pad rotation + six scene observation hardening fixes by @seunghyukchoe in #41
- feat: placement intent and deterministic legalizer (M4 core) by @seunghyukchoe in #42
- feat: preview_placement surface (M4 placement preview complete) by @seunghyukchoe in #43
- feat: CST splice layer and pure apply engine (M3 slices 1-2) by @seunghyukchoe in #45
- feat: apply_candidate — the first mutating surface (M3 slices 3-5) by @seunghyukchoe in #46
Full Changelog: v0.1.0...v0.5.0
v0.4.0
What's Changed
Features
- feat: serialize replayed candidates to disposable KiCad snapshots by @seunghyukchoe in #25
Research and performance
- test: add reproducible A*/Dijkstra routing baseline by @seunghyukchoe in #24
Documentation and maintenance
- fix: recover and harden v0.1.0 release by @seunghyukchoe in #20
- chore: upgrade CodeQL actions atomically by @seunghyukchoe in #21
- feat: add canonical Board IR v0.1 by @seunghyukchoe in #22
- docs: record measured router coverage on a real board by @seunghyukchoe in #32
- feat: ship bounded Circuit Intent schematic MVP by @seunghyukchoe in #34
- feat: multi-pin tree routing over sequential component merging by @seunghyukchoe in #35
- feat: zone fill authority — freshness-verified fill as connectivity evidence by @seunghyukchoe in #37
- chore: prepare the 0.3.0 release source by @seunghyukchoe in #38
- chore: prepare the 0.4.0 release source by @seunghyukchoe in #44
Other changes
- feat: add bounded deterministic two-pin A* baseline by @seunghyukchoe in #23
- feat: bind route candidates to authoritative KiCad DRC by @seunghyukchoe in #27
- feat: expose a bounded non-mutating route preview by @seunghyukchoe in #28
- feat: add read-only Board IR inspection over a shared request boundary by @seunghyukchoe in #30
- feat: route around existing copper instead of rejecting it by @seunghyukchoe in #31
- feat: treat through vias as obstacles instead of a board-level veto by @seunghyukchoe in #33
- feat: via-aware cross-layer connectivity recognition by @seunghyukchoe in #36
- feat: Circuit Scene IR v0.1 — typed board observation for agents by @seunghyukchoe in #39
- feat: Scene IR slice 2 — deterministic digest-bound renders by @seunghyukchoe in #40
- fix: absolute pad rotation + six scene observation hardening fixes by @seunghyukchoe in #41
- feat: placement intent and deterministic legalizer (M4 core) by @seunghyukchoe in #42
- feat: preview_placement surface (M4 placement preview complete) by @seunghyukchoe in #43
Full Changelog: v0.1.0...v0.4.0
v0.3.0
What's Changed
Features
- feat: serialize replayed candidates to disposable KiCad snapshots by @seunghyukchoe in #25
Research and performance
- test: add reproducible A*/Dijkstra routing baseline by @seunghyukchoe in #24
Documentation and maintenance
- fix: recover and harden v0.1.0 release by @seunghyukchoe in #20
- chore: upgrade CodeQL actions atomically by @seunghyukchoe in #21
- feat: add canonical Board IR v0.1 by @seunghyukchoe in #22
- docs: record measured router coverage on a real board by @seunghyukchoe in #32
- feat: ship bounded Circuit Intent schematic MVP by @seunghyukchoe in #34
- feat: multi-pin tree routing over sequential component merging by @seunghyukchoe in #35
- feat: zone fill authority — freshness-verified fill as connectivity evidence by @seunghyukchoe in #37
- chore: prepare the 0.3.0 release source by @seunghyukchoe in #38
Other changes
- feat: add bounded deterministic two-pin A* baseline by @seunghyukchoe in #23
- feat: bind route candidates to authoritative KiCad DRC by @seunghyukchoe in #27
- feat: expose a bounded non-mutating route preview by @seunghyukchoe in #28
- feat: add read-only Board IR inspection over a shared request boundary by @seunghyukchoe in #30
- feat: route around existing copper instead of rejecting it by @seunghyukchoe in #31
- feat: treat through vias as obstacles instead of a board-level veto by @seunghyukchoe in #33
- feat: via-aware cross-layer connectivity recognition by @seunghyukchoe in #36
Full Changelog: v0.1.0...v0.3.0