framework: LED.cathode mandatory + close WaterAlarm regression - #29
Closed
raeq wants to merge 1 commit into
Closed
Conversation
3 tasks
There was a problem hiding this comment.
Pull request overview
This PR tightens LED modeling fidelity by making LED.cathode mandatory, then updates WaterAlarm demos, exports, goldens, and regression tests so floating LED cathodes are caught during circuit construction.
Changes:
- Makes
LED.cathodea mandatory port and documents the physical-fidelity requirement. - Grounds WaterAlarm and WaterAlarmSplit LED cathodes and regenerates affected artifacts/goldens.
- Adds regression coverage for mandatory LED cathodes and updates fixtures/import tests affected by stricter validation.
Reviewed changes
Copilot reviewed 41 out of 46 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/components/passives/led.py |
Makes cathode mandatory and updates LED port docs. |
demos/water_alarm/water_alarm.py |
Wires both LED cathodes to ground. |
demos/water_alarm_split/water_alarm_split.py |
Wires controller-board LED cathodes to ground. |
tests/components/test_led.py |
Adds mandatory-port and floating-cathode regression tests. |
tests/framework/test_framework.py |
Updates topology fixture for grounded LED cathode. |
tests/framework/test_circuit_autocollect.py |
Updates fixtures to satisfy stricter mandatory-port validation. |
tests/framework/import_kicad/test_import.py |
Updates minimal import netlist to include driven power/ground nets. |
tests/golden/yosys/water_alarm.json |
Updates LED cathode net assignments. |
tests/golden/yosys/water_alarm_assembly.json |
Updates assembly LED cathode net assignments. |
tests/golden/spice/water_alarm.cir |
Grounds LED cathodes in SPICE golden. |
tests/golden/spice/water_alarm_assembly.cir |
Grounds assembly LED cathodes in SPICE golden. |
tests/golden/mermaid/water_alarm.mmd |
Adds LED cathode-to-ground edges. |
tests/golden/mermaid/water_alarm_assembly.mmd |
Adds assembly LED cathode-to-ground edges. |
tests/golden/kicad/water_alarm.net |
Adds LED cathode nodes to GND net. |
tests/golden/kicad/water_alarm_assembly.net |
Adds assembly LED cathode nodes to GND net. |
tests/golden/kicad_sch/water_alarm.kicad_sch |
Adds GND symbols for LED cathodes. |
tests/golden/dot/water_alarm.dot |
Adds LED cathode-to-ground graph edges. |
tests/golden/dot/water_alarm_assembly.dot |
Adds assembly LED cathode-to-ground graph edges. |
tests/golden/breadboard/water_alarm.breadboard.svg |
Adds breadboard ground jumpers for LED cathodes. |
tests/golden/assembly_guide/water_alarm.md |
Adds assembly steps for LED cathode ground jumpers. |
demos/water_alarm/docs/WaterAlarm.yosys.json |
Regenerates Yosys export. |
demos/water_alarm/docs/WaterAlarm.svg |
Regenerates graph SVG export. |
demos/water_alarm/docs/WaterAlarm.net-report.md |
Updates GND net reader count/details. |
demos/water_alarm/docs/WaterAlarm.net |
Adds LED cathodes to GND net. |
demos/water_alarm/docs/WaterAlarm.mmd |
Adds LED cathode-to-ground edges. |
demos/water_alarm/docs/WaterAlarm.md |
Adds LED cathode grounding assembly steps. |
demos/water_alarm/docs/WaterAlarm.kicad_sch |
Adds GND symbols for LED cathodes. |
demos/water_alarm/docs/WaterAlarm.dot |
Adds LED cathode-to-ground graph edges. |
demos/water_alarm/docs/WaterAlarm.cir |
Grounds LED cathodes in SPICE export. |
demos/water_alarm/docs/WaterAlarm.breadboard.svg |
Adds breadboard ground jumpers. |
demos/water_alarm_split/docs/WaterAlarmAssembly.yosys.json |
Regenerates assembly Yosys export. |
demos/water_alarm_split/docs/WaterAlarmAssembly.svg |
Regenerates assembly graph SVG. |
demos/water_alarm_split/docs/WaterAlarmAssembly.net-report.md |
Updates assembly GND net readers. |
demos/water_alarm_split/docs/WaterAlarmAssembly.net |
Adds assembly LED cathodes to GND net. |
demos/water_alarm_split/docs/WaterAlarmAssembly.mmd |
Adds assembly LED cathode-to-ground edges. |
demos/water_alarm_split/docs/WaterAlarmAssembly.dot |
Adds assembly LED cathode-to-ground graph edges. |
demos/water_alarm_split/docs/WaterAlarmAssembly.cir |
Grounds assembly LED cathodes in SPICE export. |
demos/water_alarm_split/docs/WaterAlarmAssembly__ControllerBoard.kicad_sch |
Adds controller-board GND symbols. |
demos/water_alarm_split/docs/ControllerBoard.yosys.json |
Updates controller-board LED cathode nets. |
demos/water_alarm_split/docs/ControllerBoard.svg |
Regenerates controller-board graph SVG. |
demos/water_alarm_split/docs/ControllerBoard.net-report.md |
Updates controller-board GND readers. |
demos/water_alarm_split/docs/ControllerBoard.net |
Adds controller LED cathodes to GND net. |
demos/water_alarm_split/docs/ControllerBoard.mmd |
Adds controller LED cathode-to-ground edges. |
demos/water_alarm_split/docs/ControllerBoard.kicad_sch |
Adds controller LED cathode GND symbols. |
demos/water_alarm_split/docs/ControllerBoard.dot |
Adds controller LED cathode-to-ground graph edges. |
demos/water_alarm_split/docs/ControllerBoard.cir |
Grounds controller LED cathodes in SPICE export. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Found while reviewing WaterAlarm's breadboard SVG: the LEDs in the
design had no ground connections drawn. Investigation revealed
`LED.cathode` was declared `mandatory=False` with the docstring claim
*"floating = GND"* — a "structurally inert under graph evaluation"
shortcut that lets demos write electrically-broken circuits and have
them pass ERC.
A real LED with a dangling cathode does not light. This is exactly
the kind of physical-fidelity violation `CLAUDE.md` lists as
disallowed.
- `src/components/passives/led.py`: `cathode` becomes
`mandatory=True`. Docstring updated to drop the "floating = GND"
claim and explain the contract.
- `tests/components/test_led.py`: regression tests pin both ports
as mandatory and confirm `Circuit.__init__` raises
`UnconnectedPinError` end-to-end when a cathode is left
floating.
- `demos/water_alarm/water_alarm.py` and
`demos/water_alarm_split/water_alarm_split.py`: cathodes wired
to the GND rail. (Bench builds still need a series current-limit
resistor; the logic-level demo doesn't model V_F or current.)
- `tests/framework/test_circuit_autocollect.py`,
`tests/framework/test_framework.py`, and
`tests/framework/import_kicad/test_import.py`: fixtures that
leaned on the broken default updated so they still pin down the
specific error each test exists to catch.
- Demo docs regenerated for the two WaterAlarm variants.
raeq
force-pushed
the
framework-led-cathode-mandatory
branch
from
May 19, 2026 16:05
89570e4 to
a265d46
Compare
raeq
pushed a commit
that referenced
this pull request
May 19, 2026
Continuation of the LED.cathode regression fix (#29). Resistor, Capacitor, Inductor, and every Diode subclass had their terminals declared `mandatory=False` with the same "structurally inert under graph evaluation" justification — letting demos declare BOM-only timing / decoupling / pull-up parts without wiring them, then ship breadboard SVGs and netlists where those parts sat orphaned. A real resistor / capacitor / inductor / diode with a dangling terminal does nothing. Marking the ports mandatory closes the silent regression at the framework layer. - `src/components/passives/{resistor,capacitor,inductor}.py` and every diode subclass under `src/components/diodes/` now declare their terminals `mandatory=True`. - `tests/components/test_{resistor,capacitor,inductor}.py`: regression tests pin the new contract per component. - `tests/components/test_diode_mandatory_terminals.py` (new): parametrized over D1N4001 / D1N4007 / D1N4148 / D1N4728A / D1N4733A / D1N4742A / D1N5817. - Six demos (`backup_power`, `bldc_motor`, `dice`, `doorbell_protector`, `fan_cooling`, `isolated_rs232`) had declared-but-unwired passives — each now wires them either to their datasheet-correct net (e.g. DoorbellProtector's flyback diode anode joins the relay coil_minus net) or as an isolated 0-Ω passthrough with `dynamically_driven=True` where the part is genuinely BOM-only and the voltage-only simulator can't honour its behaviour. Comments at each call site explain which kind. - Test fixtures across CLI, refdes, format-roundtrip, kicad import, and per-format renderer tests updated so they still pin down the specific error each one exists to catch without tripping the new mandatory-pin check first. - All demo docs regenerated; goldens refreshed. After this commit the breadboard SVGs show every BOM part connected to something — no more orphaned caps and resistors floating without jumpers.
3 tasks
raeq
pushed a commit
that referenced
this pull request
May 19, 2026
Found while reviewing WaterAlarm's breadboard SVG: the LEDs in the
design had no ground connections drawn. Investigation revealed
`LED.cathode` was declared `mandatory=False` with the docstring claim
*"floating = GND"* — a "structurally inert under graph evaluation"
shortcut that lets demos write electrically-broken circuits and have
them pass ERC.
A real LED with a dangling cathode does not light. This is exactly
the kind of physical-fidelity violation `CLAUDE.md` lists as
disallowed.
- `src/components/passives/led.py`: `cathode` becomes
`mandatory=True`. Docstring updated to drop the "floating = GND"
claim and explain the contract.
- `tests/components/test_led.py`: regression tests pin both ports
as mandatory and confirm `Circuit.__init__` raises
`UnconnectedPinError` end-to-end when a cathode is left
floating.
- `demos/water_alarm/water_alarm.py` and
`demos/water_alarm_split/water_alarm_split.py`: cathodes wired
to the GND rail. (Bench builds still need a series current-limit
resistor; the logic-level demo doesn't model V_F or current.)
- `tests/framework/test_circuit_autocollect.py`,
`tests/framework/test_framework.py`, and
`tests/framework/import_kicad/test_import.py`: fixtures that
leaned on the broken default updated so they still pin down the
specific error each test exists to catch.
- Demo docs regenerated for the two WaterAlarm variants.
raeq
added a commit
that referenced
this pull request
May 19, 2026
…31) Found while reviewing WaterAlarm's breadboard SVG: the LEDs in the design had no ground connections drawn. Investigation revealed `LED.cathode` was declared `mandatory=False` with the docstring claim *"floating = GND"* — a "structurally inert under graph evaluation" shortcut that lets demos write electrically-broken circuits and have them pass ERC. A real LED with a dangling cathode does not light. This is exactly the kind of physical-fidelity violation `CLAUDE.md` lists as disallowed. - `src/components/passives/led.py`: `cathode` becomes `mandatory=True`. Docstring updated to drop the "floating = GND" claim and explain the contract. - `tests/components/test_led.py`: regression tests pin both ports as mandatory and confirm `Circuit.__init__` raises `UnconnectedPinError` end-to-end when a cathode is left floating. - `demos/water_alarm/water_alarm.py` and `demos/water_alarm_split/water_alarm_split.py`: cathodes wired to the GND rail. (Bench builds still need a series current-limit resistor; the logic-level demo doesn't model V_F or current.) - `tests/framework/test_circuit_autocollect.py`, `tests/framework/test_framework.py`, and `tests/framework/import_kicad/test_import.py`: fixtures that leaned on the broken default updated so they still pin down the specific error each test exists to catch. - Demo docs regenerated for the two WaterAlarm variants. Co-authored-by: subzero <subzero@noreply.com>
raeq
pushed a commit
that referenced
this pull request
May 19, 2026
Continuation of the LED.cathode regression fix (#29). Resistor, Capacitor, Inductor, and every Diode subclass had their terminals declared `mandatory=False` with the same "structurally inert under graph evaluation" justification — letting demos declare BOM-only timing / decoupling / pull-up parts without wiring them, then ship breadboard SVGs and netlists where those parts sat orphaned. A real resistor / capacitor / inductor / diode with a dangling terminal does nothing. Marking the ports mandatory closes the silent regression at the framework layer. - `src/components/passives/{resistor,capacitor,inductor}.py` and every diode subclass under `src/components/diodes/` now declare their terminals `mandatory=True`. - `tests/components/test_{resistor,capacitor,inductor}.py`: regression tests pin the new contract per component. - `tests/components/test_diode_mandatory_terminals.py` (new): parametrized over D1N4001 / D1N4007 / D1N4148 / D1N4728A / D1N4733A / D1N4742A / D1N5817. - Six demos (`backup_power`, `bldc_motor`, `dice`, `doorbell_protector`, `fan_cooling`, `isolated_rs232`) had declared-but-unwired passives — each now wires them either to their datasheet-correct net (e.g. DoorbellProtector's flyback diode anode joins the relay coil_minus net) or as an isolated 0-Ω passthrough with `dynamically_driven=True` where the part is genuinely BOM-only and the voltage-only simulator can't honour its behaviour. Comments at each call site explain which kind. - Test fixtures across CLI, refdes, format-roundtrip, kicad import, and per-format renderer tests updated so they still pin down the specific error each one exists to catch without tripping the new mandatory-pin check first. - All demo docs regenerated; goldens refreshed. After this commit the breadboard SVGs show every BOM part connected to something — no more orphaned caps and resistors floating without jumpers.
3 tasks
raeq
added a commit
that referenced
this pull request
May 19, 2026
Continuation of the LED.cathode regression fix (#29). Resistor, Capacitor, Inductor, and every Diode subclass had their terminals declared `mandatory=False` with the same "structurally inert under graph evaluation" justification — letting demos declare BOM-only timing / decoupling / pull-up parts without wiring them, then ship breadboard SVGs and netlists where those parts sat orphaned. A real resistor / capacitor / inductor / diode with a dangling terminal does nothing. Marking the ports mandatory closes the silent regression at the framework layer. - `src/components/passives/{resistor,capacitor,inductor}.py` and every diode subclass under `src/components/diodes/` now declare their terminals `mandatory=True`. - `tests/components/test_{resistor,capacitor,inductor}.py`: regression tests pin the new contract per component. - `tests/components/test_diode_mandatory_terminals.py` (new): parametrized over D1N4001 / D1N4007 / D1N4148 / D1N4728A / D1N4733A / D1N4742A / D1N5817. - Six demos (`backup_power`, `bldc_motor`, `dice`, `doorbell_protector`, `fan_cooling`, `isolated_rs232`) had declared-but-unwired passives — each now wires them either to their datasheet-correct net (e.g. DoorbellProtector's flyback diode anode joins the relay coil_minus net) or as an isolated 0-Ω passthrough with `dynamically_driven=True` where the part is genuinely BOM-only and the voltage-only simulator can't honour its behaviour. Comments at each call site explain which kind. - Test fixtures across CLI, refdes, format-roundtrip, kicad import, and per-format renderer tests updated so they still pin down the specific error each one exists to catch without tripping the new mandatory-pin check first. - All demo docs regenerated; goldens refreshed. After this commit the breadboard SVGs show every BOM part connected to something — no more orphaned caps and resistors floating without jumpers. Co-authored-by: subzero <subzero@noreply.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Found while reviewing WaterAlarm's breadboard SVG (from #28): the LEDs in the design had no ground connections drawn. The framework's
LED.cathodewas declaredmandatory=Falsewith a "floating = GND" shortcut that lets demos write electrically-broken circuits and have them pass ERC. A real LED with a dangling cathode does not light — this is exactly the physical-fidelity violation CLAUDE.md lists as disallowed.LED.cathodenowmandatory=True. The framework raisesUnconnectedPinErroratCircuit.__init__if a design declares an LED with an unwired cathode.red_led.cathodeandgreen_led.cathodeto ground. (Bench builds still need a series current-limit resistor; the logic-level demo doesn't model V_F or current.)tests/components/test_led.py— the second one (test_floating_cathode_refused_at_circuit_construction) is the end-to-end test that would have caught the WaterAlarm bug originally.Test plan
uv run pytest— 4362 passed.uv run mypy src/ demos/clean.Based on #28 (Phase 2.6 breadboard visualiser).