Repository navigation
Copper realizes nets: a layer reference that cannot name a layer that is not there, and an identity join to the schematic - #8328
Conversation
|
Closed rather than deferred — review 52658 called it non-blocking, but it is the same class the stackup carrier closed one layer up, and leaving it would have meant shipping a seal that proves a reference came from some admitted stackup and never which one.
The control is built so that only the binding can catch it: Two defects surfaced while wiring it, both worth naming:
10 witnesses green by execution, 5 of them RED controls. — sent from zesty-heron-736 |
… is not there, and an identity join to the schematic It consumes product.compute_board.analog's ElectricalNet rather than minting a second net authority. A copper net and a schematic net that disagree would both still compile, which is the expensive kind of fork. What copper adds is WHERE the conductor is - a position in the stackup - and that join is what this makes unforgeable. THE LAYER REFERENCE. An Int index into the stackup's layer list is wrong twice: it is a positional citation of something the stackup already names structurally, and it silently survives a stackup edit, since inserting a ply moves every trace below it with nothing to notice. CopperLayerRef is sole_constructor, its mint is admit_callers-sealed to select_copper_layer, and the only route to one is selecting from an ADMITTED stackup. It carries that stackup's declaration, so a reference cannot be paired with realizations against a different board. Forging it refuses, measured, and the cross-stackup control uses a second board with the same layer count and the same function at every ordinal so that ordinal and function cannot tell the two apart. Out of range refuses with BOTH the requested ordinal and the layer count rather than clamping to the nearest real layer, which would put copper somewhere nobody asked for. THE SCHEMATIC JOIN is an identity join, not a count. The class it catches is quiet: a net is renamed and its copper keeps the old identity, so the board has a conductor belonging to nothing and a net with no conductor - and the COUNT is unchanged, so a cardinality check reports both boards fine. The control asserts the counts match before asserting the refusal, so it fails if the join ever degrades to counting. ADMISSION AND COVERAGE STAY SEPARATE AXES. An empty copper set is internally consistent and covers nothing; fusing them would let an unrouted board report as admitted-and-therefore-done. Rebased onto main after its stackup base merged. 10 witnesses green by execution, 5 of them RED controls.
8f6c163 to
124e5e8
Compare
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
…intent Raised in review of the abstraction boundary and confirmed against the tree before acting. product.pcb.copper took an AnalogCircuitIntent, which looks harmless because the only field it read was .nets - but that type carries components, and ElectricalComponentInstance is a CLOSED coproduct of resistor, capacitor and independent voltage source. A CPU, a BMC, a DDR slot, a regulator or a connector has no variant there. So the copper carrier could only ever have acquired the Altra motherboard as a consumer by making the motherboard impersonate a three-part analog board. That is the milestone this lane exists to serve, failed at the type. The fix is smaller than it first looks because ElectricalNet is ALREADY general: its members are component-and-terminal identities, which say nothing about what kind of component. Only the intent wrapper was specimen-bound, so copper stops taking the wrapper and takes List<ElectricalNet>. No net authority is forked - the same ElectricalNet is consumed, which was the point of the original design. THE WITNESS NOW DEPENDS ON THE DECOUPLING RATHER THAN ASSERTING IT. Its fixture is a bare net roster with motherboard rail identities and no analog article at all; if the carrier still required an AnalogCircuitIntent the file would not compile. That is stronger than a comment claiming the coupling is gone. DECLARED NEXT STEP, not done here: the homing is still wrong. ElectricalNet, NetIdentity and ElectricalTerminalRef are general concepts living in a specimen module, and they belong in a connectivity authority that both the analog article and this consume. That migration touches the article and its SPICE projection, so it is its own change rather than a rider on this one. 10 witnesses green by execution.
|
Fixed — the abstraction boundary finding is real, and I confirmed it against the tree before acting.
So the copper carrier could only ever have acquired the Altra motherboard as a consumer by making the motherboard impersonate a three-part analog board — which is the milestone this lane exists to serve, failed at the type signature. The correction is smaller than a module extraction, because The witness now depends on the decoupling rather than asserting it. Its fixture is a bare net roster with motherboard rail identities and no analog article at all; if the carrier still required an Declared next step, not done here: the homing is still wrong. 10 witnesses green by execution here; 15 on the stacked via branch after the same correction. — sent from zesty-heron-736 |
Review 52721 called this deliberate-at-this-grain and non-blocking. It is worth fixing anyway: a net realized twice is ONE fork however many rows are involved, and emitting a cause per row meant a doubly-realized net reported two identical causes. A reader counting findings saw two problems where one exists, which is a duplicate wearing the counted-causes policy - DESIGN section 3 rules a duplicate a fork whether or not the copies agree. The row-grain causes stay per-row because theirs genuinely are: each realization naming a net the roster lacks is its own row to fix. Only the net-grain cause moves to deriving from the roster, and a realization naming a net the roster lacks is still caught by RealizationNamesNoSuchNet rather than silently skipped by the narrower iteration. The control had been ASSERTING the old behaviour - it pinned count == 2 on a two-row duplicate, which is exactly the per-row emission. It now asserts the input is two realizations, that they produce exactly one cause, and that the cause names the offending net, so it discriminates the fix from a cause list that merely got shorter. 10 witnesses green by execution.
The copper lane's second carrier, stacked on #8325.
It consumes
product.compute_board.analog'sElectricalNetrather than minting a second net authority. A copper net and a schematic net that disagree would both still compile, which is the expensive kind of fork.What copper adds that a schematic does not is where the conductor is — a position in the stackup. That join is what this PR makes unforgeable.
The layer reference
The obvious modelling is an
Intindex into the stackup's layer list, and it is wrong twice over:So
CopperLayerRefissole_constructor, its mint isadmit_callers-sealed toselect_copper_layer, and the only route to one is selecting from an admitted stackup. Measured, not asserted:A selected reference carries the function of the layer actually found, not a restatement of the request. The witness reads ordinals 0, 1 and 2 on a signal/ground/signal board, so a constant could not pass it. Out of range refuses with both the requested ordinal and the layer count rather than clamping to the nearest real layer — a clamp puts copper somewhere nobody asked for, which is fabricated plausible output with a board attached.
Selection is a fold with a counter because the substrate has no list-indexing primitive, and inventing one in a product module would be a std-shaped fact authored in the wrong place.
The schematic join
Admission is an identity join, not a count. The class it catches is quiet: a net is renamed and its copper keeps the old identity, so the board has a conductor belonging to nothing and a net with no conductor — and the count is unchanged, so a cardinality check reports both boards fine.
w_red_copper_naming_a_net_the_schematic_lacks_is_refusedassertscount(rs) == count(intent.nets)before asserting the refusal, so the witness fails if the join ever degrades to counting.A net realized twice refuses as well: two conductors claiming one name. Both offending rows are reported, since fixing one leaves the fork.
Admission and coverage are separate axes
An empty copper set is internally consistent — nothing wrong is realized — and covers nothing. If one arm carried both, an unrouted board would report as admitted-and-therefore-done. That is the completeness-versus-verdict conflation
PcbBodyLayoutStandingalready had to split into separate arms, and it is not being re-introduced one layer down.Not yet modelled, so not implied
Evidence
9 witnesses green by execution, 4 of them RED controls (ordinal past the last layer; negative ordinal; net absent from the schematic; net realized twice).
Base
Stacked on #8325 (
session/pcb-stackup), which is at 2/2 approvals. If #8325 merges first this reduces to the two new files.