Skip to content

SYN-136 - Bug: via-in-pad cannot be declared by a board or a profile, only by a CLI flag - #138

Closed
JeffMboya wants to merge 57 commits into
absmach:mainfrom
JeffMboya:SYN-136
Closed

JeffMboya wants to merge 57 commits into
absmach:mainfrom
JeffMboya:SYN-136

Conversation

@JeffMboya

Copy link
Copy Markdown
Contributor

What type of PR is this?

This is a feature

What does this do?

Adds requires via_in_pad, the design's half of a decision that lived only at the command line:

  • ManufacturerProfile.via_in_pad — what the tier sells
  • requires via_in_pad — what the board needs
  • E-SYNTH-PROCESS-002 — refusal when they disagree

Which issue(s) does this PR fix/relate to?

Have you included tests for your changes?

Yes

Did you document any new/modified features?

Yes

Notes

Via-in-pad was one boolean answering two questions: can this process fill and cap a via in a pad, and may this board use one. Conflating them meant a board exported against an advanced tier inherited a permission it never asked for, and a board that asked on a standard tier had nowhere to be told no.

The filled-via tier carries JLC's standard floors and nothing else. Filling a via buys the capability, not a finer drill, so a board cannot reach geometry it never paid for by asking for the fill — there is a test pinning that.

--krt-allow-via-in-pad survives as an operator override and still outranks the profile, because a human passing it has taken responsibility for one panel.

The Class C board declares the requirement. Its README keeps the pre-declaration routed numbers and says so: the engine is now given the permission, which KRT encodes as a clearance sentinel, so the copper may differ. CI measures that.

The check measured centre-to-centre against `Pad::radius_nm`, which is
half the pad's *long* side. That radius exists for connectivity, where
over-reaching is the safe direction, and it is wrong for a violation:
on a 1.95 x 0.6 mm SOIC pad it reaches 0.975 mm from the centre while
the copper reaches 0.3 mm across the narrow axis.

Every Class-A board failed on it. a3_protected_power_entry was rejected
for a via 0.268 mm clear of U1.2's edge, against the 0.1 mm same-net
clearance Synth had asked the router for; the router had over-delivered
and was blamed for it.

Pads now carry their board-frame orientation and answer
`contains_point` exactly, by shape. The old test could not have caught
this: it used square pads, where the long and short half-dimensions are
the same number, and placed the via dead centre.

(cherry picked from commit d25cba0)
The exported `.kicad_pro` stated `min_clearance` and `min_track_width`
and nothing else. Three parties read those rules and all three were
reading a board that declared almost nothing:

- `kicad-cli pcb drc` has no rule to apply where the key is absent,
  which is why it passed boards Synth called unfabricable;
- the external router is asked to preserve "the board's declared
  minimums" and can only preserve what the project states;
- `synth-router`'s independent validation judges the result against the
  full profile.

With no `min_through_hole_diameter` the router had no drill floor, took
the 0.15 mm rung its fabrication tier allows, and Synth then rejected
the board against the profile's 0.3 mm. The rules are now derived from
the board's declared manufacturer, so the three agree by construction.

`min_via_diameter` follows from drill plus two annular rings, the
relationship KiCad itself enforces, rather than being a fourth number
to choose. `min_hole_to_hole` has no profile field and is left out.

(cherry picked from commit 77d810b)
A `.kicad_pcb` carries no design rules or net classes; they live in the
sibling `.kicad_pro`, which every KiCad tool finds by swapping the
extension. The preserved baseline is `<stem>.synth.kicad_pcb`, so the
router looked for `<stem>.synth.kicad_pro` while the export had written
`<stem>.kicad_pro`. That file has never existed.

So every board, every engine, every run has been routed against the
engine's own defaults rather than the board's rules. KiCadRoutingTools
reported it plainly once asked: `board_floors: {}`, and it created a
Default net class because "project had none".

With the project copied alongside, a3 goes from two sub-minimum drills
to none, and from three fab-tier escalations to zero. Best-effort: a
board exported without a project still routes, where a missing baseline
is unrecoverable.

(cherry picked from commit 5e6ad65)
A footprint's `(at x y angle)` angle is anticlockwise on screen, and
KiCad's y axis points down, so a pad offset transforms by -angle. The
reader applied +angle, putting every pad with a non-zero offset on the
wrong side of its footprint.

The independent validation pass then looked for copper where no copper
was, and reported nets open on boards the engine had routed correctly.
On the new Class-A board it rejected three: a 1x2 JST rotated 90 had
pad 2 read 5 mm from its own copper, and the 1x4 probe connector had
two. Pad 1 of each sits at offset (0, 0), where rotation cannot matter,
which is why one pin of a connector worked and the rest did not.

It survived because the corpus is mostly symmetric two-pad passives.
At +-90 those produce the same *set* of pad positions and merely swap
which pad is which, so every net still closes. Only an asymmetric
multi-pad part shows it.

The fixture that should have caught it certified it instead: its B.Cu
segment was drawn to the point the reader's own arithmetic reported, so
the reader was checked against itself. Its coordinates are corrected
here and the note says to check such numbers against a routed board.

The front-side transform is measured against copper KiCadRoutingTools
produced. The mirror composition for bottom-side footprints is reasoned
only: the placer puts every footprint on the front, so no board
exercises it.

(cherry picked from commit ba3ccd8)
`ice40hx4k_bg121` is the registry's first ball-grid part: a Lattice iCE40
HX4K on an 11 x 11 grid at 0.8 mm pitch, which is what absmach#40 case 1 asks
escape routing to be demonstrated against. All 121 balls are declared
and checked both ways against the stock symbol and footprint, so neither
load-time rule can fail on it. The symbol `extends` its HX8K sibling and
carries no pins of its own; both the pin check and the schematic loader
follow that chain, so the part names the device it is.

Twenty-eight pins are marked required: every supply and ground ball plus
CRESET and CDONE. An untied ball on a BGA is not a cosmetic omission.

`hdmi_a_receptacle` gives the four TMDS pairs somewhere to go. Polarity
lives in the electrical types, because `diff_pair_positive` requires
`differential_positive` and the two have to agree for the part to load.
The lane shields and GND are `ground_reference`, not `power_input`: as
supplies they read as power pins wanting their own decoupling, which is
what E-SYNTH-KG-001 reported. No part had used that type before.

The FPGA's general-purpose I/O declares both I2C roles because an FPGA's
I/O is soft and any pin can serve either. That is weaker than a
fixed-function part, where a capability pins down one function and a
wrong connection is caught; the registry cannot say "any of these pins,
any of these roles, one at a time". Noted on the part.
Writing the Class-C board walked into all three.

`osc_smd_25mhz` named `Oscillator:SiT8008B` and
`Oscillator_SMD_SiTime_SiT8008-4Pin_5.0x3.2mm`. Neither exists in KiCad
10.0.6. The stock pair for the same 4-pin 5.0 x 3.2 mm SiTime part is
`SiT8008xx-1x-xxE` and `Oscillator_SMD_SiT_PQFN-4Pin_5.0x3.2mm`; the pin
map already matched OE/GND/OUT/Vdd on pads 1-4 and is unchanged. Its
declared dimensions were 5.0 x 5.0, the body is 5.0 x 3.2 and the
courtyard 6.0 x 4.32.

`tvs_array_5v` declared pad 8 on a 6-pad SOT-363, which fails
E-SYNTH-PIN-001, and its description said SOIC-8. `mp2307_buck` named a
footprint that does not exist and left the exposed thermal pad out of
the pin map.

The last two are the same corrections already made under absmach#87 on the
qualification branch, brought here because this board cannot ground a
thermal pad or clamp an input through a pad that is not there.
`diff_pair` could already bound the two halves of one pair with
`max_skew`. Nothing could bound one net against another, which is what a
length-sensitive bus needs: absmach#40 case 2 asks for a length-matched
interface and there was no way to declare one.

`netclass "TMDS" { match_length 0.25mm }` says every net in the class
must come back the same routed length, within that tolerance.

It is measured, not merely recorded. `check_length_matching` sums copper
per net from the same geometry the connectivity pass walks, and reports
the class with its spread and the two nets at the extremes. A declared
constraint nothing checks is the complaint in absmach#65, so the tolerance
reaches the independent validation and blocks there.

Vias are not counted: they add board thickness, which is common to every
net in a class, and the tolerances here are about planar routing. A net
with no copper is skipped rather than measured as zero, because it is
already reported as an open net and would otherwise also be named the
shortest member of its class.

`Length::to_nm` comes with it, so a tolerance compares against integer
copper geometry without a round trip through `f64`.
…it stops

An iCE40 HX4K on a 121-ball BGA driving HDMI, written from a prompt
through the MCP server. It carries absmach#40's four cases: the BGA escape, the
four TMDS pairs at 100 ohm with `max_skew` and `couple tight`, the lanes
matched net-to-net with the new `match_length`, and two rails from one
5 V input.

Validate reports no errors and the knowledge graph no missing support
circuit. Four warnings were acted on rather than silenced: the TVS
channels were spent on D+/D- that this power-only inlet never connects
while CC sat unprotected, three rails carried more load than their
decoupling supported, and the HDMI lane shields were typed as supplies
so they read as power pins wanting their own capacitors.

It does not route, and the board says why. Synth pours ground and
nothing else, so the 3.3 V rail's thirty pads and the core rail are
traces across a dense four-layer BGA board; the router leaves 29 open
nets, almost all supply. That is the limit on absmach#40 case 4, not a router
defect, and granting via-in-pad does not move it.

The placement sidecar holds one override: the placement review refused
to route until J2 was turned parallel to the board edge, and named the
rotation. `synth_place_with_hints`, which the same message says to
rerun, takes region/edge/near and no rotation, so the recommendation can
only be applied through a layout override.
A registry change that completes a part's pin map moves the rendered plot
of every design using that part. The assertion fired on the first one, so
regenerating the goldens meant running the suite once per design to learn
the next name.

Collect them all and print the golden and live fingerprints side by side.

(cherry picked from commit 5359106)
`every_language_constraint_is_supported_unsupported_or_unverified` reads
the attribute list straight off the AST and fails on anything the
descriptor does not place, so adding `match_length` to `NetclassAttr`
without listing it left it unclassified. It is listed as supported,
which is what it is: declared, lowered, and measured against the routed
copper.

A good guard. It is the reason a new constraint cannot quietly ship
without saying whether Synth stands behind it.
…elines

`keywords_recognized` lexes a fixed source and compares the whole token
stream, so adding `match_length` to that source without adding
`KwMatchLength` to the expected list failed it. Another guard worth
having: the keyword vocabulary cannot grow silently.

The two schematic baselines are CI's own numbers from this branch's run,
because both depend on KiCad symbol geometry this machine does not have.
All ten golden fingerprints moved — `main` is red on the same drift at
79daf6f and absmach#116 is the fix in flight there — and the feather placement
moved by hundredths of a millimetre, which is the corrected oscillator
courtyard propagating to its neighbours.

Every old value in the placement snapshot was checked against the file
before being replaced. An earlier attempt at this skipped that and had
crossed two snapshot regions in the log, which would have written
numbers no run ever produced into a release baseline.
Two defects, both of which made a declared tolerance read as satisfied.

Only the CLI populated `length_groups`. Both MCP routing entry points
left it empty, and an empty group list makes `check_length_matching`
iterate nothing and report nothing — indistinguishable from a pass. The
derivation now lives on `RouteRequest` and all three callers use it, so a
fourth caller cannot quietly skip it.

And declaring a `netclass` puts no net in it: nets join one through
`class "NAME"` on a `connect`, `net` or `power` statement. No board in
this repo did that, so every netclass in the corpus is inert — the
widths and clearances on a1, a2, a3, b1-b5, c1 and c2 have never applied
to anything either. c3's eight TMDS lane connects now carry
`class "TMDS"`, and the IR confirms the eight nets and the 0.25 mm
tolerance reach the netclass.

The claim in the earlier commit that this is "measured, not merely
recorded" is true of the mechanism and not yet evidenced by this board.
Tightening the tolerance to 0.001 mm still reports nothing, because
seven of the eight lanes have no copper: the class has one measurable
net, and one net cannot be mismatched against itself. c3 will exercise
the check when it routes, which waits on absmach#117.

The unit test is the evidence that exists today.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 14, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 14, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
@JeffMboya

Copy link
Copy Markdown
Contributor Author

Closing: every piece of this has been re-landed as a reviewable PR, as the review asked.

What it was Where it went
via-in-pad declared by board and profile #155
a netclass declares its via geometry #170
grid-array escape engine #161
a component declares how its pins escape #164
plane pour gets its nets and layers #181
every manufacturer minimum in the project #167
the project beside the board the engine reads #168
pads read as placed, via-in-pad by real copper #169
a plane rail per inner layer #160, merged
a through via as the span it crosses #153, merged
the first BGA part, and an HDMI receptacle #156, merged
three parts that mismatched their KiCad libraries #159
stitching a boxed-in plane pad #166
the Class-C FPGA board #171

Two things did not come across, deliberately:

The CI render job added here was also dropped here; board images are rendered locally and attached to the board PR instead.

Splitting it this way turned up five defects the monolith had buried, each now its own issue or PR: #157, #158, #165, the --escape-clearance default under the board's floor, and an escape { layers … } typo that failed silently at route time.

@JeffMboya JeffMboya closed this Oct 14, 2026
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 16, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 16, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 17, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 17, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 17, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 20, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 20, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 20, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 20, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
JeffMboya added a commit to JeffMboya/synth that referenced this pull request Oct 21, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
rodneyosodo pushed a commit to JeffMboya/synth that referenced this pull request Oct 30, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
rodneyosodo pushed a commit to JeffMboya/synth that referenced this pull request Nov 2, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
rodneyosodo pushed a commit to JeffMboya/synth that referenced this pull request Nov 2, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
rodneyosodo pushed a commit to JeffMboya/synth that referenced this pull request Nov 2, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
rodneyosodo pushed a commit to JeffMboya/synth that referenced this pull request Nov 2, 2026
`escape { method underpad  layers "In1.Cu", "In2.Cu" }` on a component, or
`escape { off }` to leave a package to the general router. Geometric
selection stays the default: the block overrides it rather than replacing
it, and precedence is `off` first, then what the design declared, then the
geometry.

Needing an escape is a property of the package, but *how* to escape it is a
design decision — which layers it may use, and whether a part the geometry
would pick should be left alone. Before this the engine's choice was the
only one available, and a board had no way to disagree with it.

`method` and `off` are contextual identifiers so a design already using
those words as names keeps parsing. `layers` cannot be: it is the reserved
keyword that declares the board's copper count, so the sub-setting arrives
as `KwLayers` and is matched as such.

E-SYNTH-PARSE-040 names an attribute the block does not take, and
E-SYNTH-PROCESS-004 an escape method this build does not know; both ship
their diagnostic pages.

Taken from the absmach#138 monolith, minus the parts that belonged to work which
has not landed: the `match_length` length groups, which absmach#145 closed in
favour of a netclass `max_skew`, and the netclass via-geometry constants.
The MCP call sites are re-derived against main's `evaluate_candidate_mcp`
refactor rather than the inline body they were written for, and the
candidate evaluator takes the intent too, because a declared `off` would
otherwise change which placement wins.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: via-in-pad cannot be declared by a board or a profile, only by a CLI flag

1 participant