Repository navigation
fix(pcb-sch): Keep children of dual-registered ids in hierarchical layout - #1219
detail-app[bot] wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Stale comment
Not approved: Cursor Bugbot and Cursor Security Agent completed with no findings, but this is a functional hierarchical-layout behavior change rather than a small fixup, so human review is still required. Reviewers were not assigned.
Sent by Cursor Approval Agent: Pull Request Router and Approver
d2aa313 to
ee41c0c
Compare
There was a problem hiding this comment.
Stale comment
Not approved: Cursor Bugbot completed with no findings and Cursor Security Agent was not running, but this is a functional hierarchical-layout behavior change rather than a small fixup, so human review is still required. Reviewers were not assigned.
Sent by Cursor Approval Agent: Pull Request Router and Approver
ee41c0c to
ab1905c
Compare
There was a problem hiding this comment.
Not approved: Cursor Bugbot completed with no findings and Cursor Security Agent was not running, but this is a functional hierarchical-layout behavior change rather than a small fixup, so human review is still required. Reviewers were not assigned.
Sent by Cursor Approval Agent: Pull Request Router and Approver
|
Closing because the entire |


Detail bug report: View on Detail
Bug
In
crates/pcb-sch/src/hierarchical_layout.rs, two functions made contradictory decisions about an id registered in bothcomponent_sizes(a leaf) andmodule_hierarchy(a module):find_root_itemstreated the id as a module and exiled its children from the root set (they were expected to be laid out when the module was recursed into).layout_module_recursivecheckedcomponent_sizesfirst, placed the id as a leaf, and returned before recursing intomodule_hierarchy.The children were therefore exiled from the roots by one decision and never laid out by the other, so they were silently absent from
layout()'s result — no panic, noResult, no log. The defect is an internally inconsistent resolution of an overloaded id, not a missed documented contract (the module doc-comment is silent on dual-registration).Fix
Two
component_sizes.contains_key(module_id)guards, aligning the two readers ofmodule_hierarchywithlayout_module_recursive's existing leaf short-circuit:find_root_items— skip exiling a module's children from the root set when that module id is also a registered leaf. The children stay as ordinary roots, matching the leaf interpretationlayout_module_recursivealready picks, so they are no longer stranded.update_child_positions— return early when the module id is also a leaf. Once the children are reinstated as roots, this function would otherwise re-offset them by the module's packed position, silently corrupting their positions whenever the module packs off-origin.Both guards are a strict no-op for any well-defined (single-registration) input:
component_sizes.contains_key(module_id)isfalsewhenever each id is registered at most once, so the existing layout tests are unaffected. The fix introduces no new panic orResultpath and alters behavior only for the self-contradictory dual-registration corner.Testing
Four regression tests were added to the inline
testsmodule, plus a smalllayout_entrieshelper:["C1","M","R1"](was["M"]).update_child_positionscorruption.Routine checks all pass:
cargo nextest run -p pcb-sch(187 passed, 0 skipped, 0 failed — 183 pre-existing + 4 new), doctests,cargo check --workspace --locked,cargo clippy -p pcb-sch --all-targets --all-features -- -D warnings, workspace-wide clippy, andcargo fmt --all -- --check.End-to-end verification (not versioned): I temporarily added reproducer tests matching the bug report's scenarios, ran them with
--nocapture, then removed them so no one-off harness remains in the tree. The dual-registration output is byte-for-byte equal to the leaf-only baseline for both module sizes and both setter orders, and the printed coordinates match the report's expected fixed values exactly (e.g. forM=(4,4)packing off-origin:C1 pos=(0,0) M pos=(13,0) R1 pos=(0,13), identical with and without the redundantadd_module). Degenerate inputs (empty input, cycles, self-cycle, diamond) all produce the same output as before the fix — the guards are no-ops since no id is in both maps. The repo's pre-commit hooks (prek run --all-files:ty,cargo fmt,clippy,pcb fmt stdlib) all pass.A
CHANGELOG.mdentry was added underUnreleased→Fixed.Automatic Fixes PRs can be configured here.
Note
Low Risk
Scoped to schematic hierarchical layout in pcb-sch for a dual-registration edge case; guards are no-ops for typical inputs and are covered by new tests.
Overview
Fixes hierarchical schematic layout when the same id is registered as both a leaf component (
set_component_size) and a module (add_module).layout_module_recursivealready treated those ids as leaves and never packed module children, butfind_root_itemsstill removed those children from the root set, so they disappeared fromlayout()output with no error.The PR adds matching
component_sizesguards infind_root_items(do not exile children of dual-registered module ids) andupdate_child_positions(do not re-offset children that were laid out as separate roots). Behavior for normal single-registration modules is unchanged.Four regression tests plus a
layout_entrieshelper cover stranded children, position parity with a leaf-only baseline (including off-origin packing), pure-module packing, and dual-registered ids nested under a real parent module. CHANGELOG records the fix under 0.4.50.Reviewed by Cursor Bugbot for commit ab1905c. Bugbot is set up for automated code reviews on this repo. Configure here.