15 KiB
Port-capacity policy comparison for predictable resize — 2026-09-12
Status: bounded source/design comparison for root's Gitea issue16. This report is a proposal for an isolated experiment, not an accepted policy or implemented fix. Only this .local report was written. No production/tracked files, compiler/Cargo, native application, Git or Gitea were changed. Root owns the concurrent desktop focus integration and release work.
Decision to test
Prototype capacity-aware automatic side assignment over finalized owner bounds as the leading candidate, with unchanged side choices plus adaptive spacing as the simpler control. Keep the current policy as a regression control. Do not increase inverse-search iterations: the executed inverse experiment demonstrated target rectangles that the present projector cannot represent.
The useful architectural boundary is: finalize rectangular node geometry from authored bounds, semantic port minima and visual containment before choosing automatic port sides or routing. Ports and routes may respond to the frame; their automatic choices must not feed new dimensions back into it. This boundary retains exact source/API/projection parity without a schema flag or implicitly authored port anchors. It would also make unchanged authored child rectangles visually stationary, apart from the already explicit state boundary symbols and ancestor enclosures.
This comparison does not select the final allocator or claim routing/readability success. The lead candidate must beat the simple control on concrete crowded/blocked examples before its added allocation logic is justified.
Evidence and criteria
The executed inverse experiment is documented in diagram-resize-inverse-experiment-20260912.md, with receipts under .local/native-qa/resize-inverse-r1-42511f0. All static requests resolved, but each automatic/manual port fixture had24 unresolved requests out of48. Three selected W/N/S targets have structural impossibility arguments, not merely a finite-search failure. No successful candidate needed residual corrections.
User-derived criteria are predictable eight-handle editing for good layouts, useful visual nesting, readable ports/exchanges, low cognitive load, maintainability and full graphical/textual equivalence (PROJECT_GOAL.md). The policies must preserve:
- Captured opposite edges and inactive visible axes, original inactive authored fields where possible, one selected-record resize and exact zero-motion fallback.
- Semantic port/connection identity, contract, orientation and ownership. Manual anchors remain exact authored sides and complete-edge fractions; resize must not invent anchors for formerly automatic ports.
- One deterministic core projection for desktop, SVG, Fit, hit testing and routed endpoints. No gesture-local layout regime that changes on release/reopen.
- Actual projected ports as hard routing endpoints with outward18-unit stubs and12-unit clearance, keeping authored pins. Routing must not silently move a port to make a path easier (
routing.rs:377–406;harness/release-routing-contract.md:102–117). - Existing port-edit stability: a manual anchor edit does not resize any owner or flip unrelated automatic sides (
port_layout.rs:206–207;tests/port_anchors.rs:535–603). Automatic positions on the affected side may adapt around the authored anchor.
The wire specification only requires absent anchors to use automatic positioning and preserves authored sides/fractions through resize; it does not normatively require geometry-driven capacity enlargement (docs/language.rst:1120–1155). A core automatic-layout policy can therefore change without a new model field, but its rendering change and regression evidence must be documented.
Current mechanics and a useful capacity fact
projection.rs:314–350 applies semantic-count size floors, then encloses visual children. projection/port_layout.rs:203–264 chooses sides from normalized peer facing, midpoint exit clearance, semantic preference and least current count; freezes those choices; enlarges owner dimensions for their capacity; and encloses again. That last feedback causes the resize obstacles.
The earlier semantic-count minimum already provides enough total four-side capacity for all owner ports at nominal gap28, before peer-facing choices:
- For the largest semantic/balanced vertical-side count
v, height is at least76+28(v+1)=28v+104, versus the side-capacity requirement36+28(v−1)=28v+8. - For the largest horizontal-side count
h, width is at least28(h+1)=28h+28, versus28h+8needed on that side. - Therefore the original semantic/balanced assignment fits each side, and later enclosure only increases available lengths. With capacity
0for edge length<36, otherwisefloor((length−36)/28)+1, total capacity is sufficient. This is a source-level argument over current ordinary-node floors, not a claim that all clear exits or arbitrary manual placements have sufficient capacity.
The lead candidate can use this existing space rather than adding a worst-case square floor. It must still handle ports whose clear-side options are restricted and manual anchors crowded onto one side.
Material alternatives
| Policy | Predictable bounds | Readability/routing tradeoff | Assessment |
|---|---|---|---|
| Current peer-driven side choices, then grow dimensions | No: verified unreachable fixed-edge targets and nonmonotone feasible ranges | Preserves28-unit capacity for automatic shadow choices, but can enlarge unrelated owners/ancestors and still cannot guarantee arbitrary manual spacing | Reject as the complete resize foundation |
| Keep current side choices; remove capacity growth and fit spacing on those sides | Yes, with existing semantic/content floors | Smallest change and strongest preservation of preferred facing. Eight neutral ports on a160-high side have124 usable units, about17.7 spacing;100 concentrated neutral ports on the existing804-high owner have about7.76 spacing, below14-unit square glyph width | Essential simple control; insufficient default if readable free sides are available |
| Allocate automatic shadow choices within finalized side capacities; adapt spacing only when clear capacity/manual constraints force it | Yes | Retains28 spacing when a clear capacity assignment exists; some ports face a less direct side and routes may become longer. Needs deterministic scarcity handling and post-placement routing evaluation | Leading candidate for a bounded prototype |
| Static worst-case size sufficient for all ports on every side | Yes | Gives eight ports a232×232 minimum and100 ports roughly2808×2808, versus the present balanced728×804. It defeats compact layouts to reserve mostly unused space | Reject as the ordinary default |
| Static semantic/round-robin sides with no peer steering | Yes | Very simple, but can send a lone neutral port to Left while its peer is Right, increase detours, and discard useful existing clear-exit behavior | Reject as the ordinary default; useful conceptual baseline only |
Do not add an implicit “locked size”/manual resize schema flag merely to bypass the current growth pass. That introduces two projection regimes and migration/source/API obligations before simpler policies are tested. Similarly, freezing automatic sides only during a drag breaks preview/reopen parity; persisting those frozen choices silently changes automatic ports into manual anchors.
Lead candidate, precisely bounded
- Retain current semantic-count minima, fold rules and first visual-enclosure pass. Freeze these node bounds for port layout. Remove only the second port-choice-driven owner enlargement/re-enclosure from the experimental policy.
- Compute each port's current peer information, semantic preference and clear-side set over those final bounds. Compute nominal capacities from edge lengths. Preserve the existing preferred side when it has capacity and a clear exit.
- Assign shadow automatic sides for every port, including manually anchored ports, independently of the manual anchor list. Apply authored side/fraction overrides only afterward. This deliberately retains some unused shadow capacity when a port is moved manually; using that newly free space to reshuffle other sides would violate the existing anchor-edit stability contract.
- Prefer clear capacity over an already-full preferred side. Use deterministic stable IDs and the existing semantic/least-count tie behavior where applicable, so100 unconnected neutral ports remain balanced25 per side and renaming/list reordering does not change geometry.
- Do not call a greedy miss “no clear capacity.” A small alternating reassignment over four side bins can repair an assignment that used scarce capacity poorly. Greedy-versus-reassignment is an experimentable implementation choice: add reassignment only when the explicit scarcity fixture demonstrates its value, rather than introducing a generic flow library.
- If no all-clear capacity assignment exists, preserve clear exits before nominal gap: select a deterministic clear overflow side and use spacing adaptation, with a measurable crowded outcome. If no side is clear, retain the current deterministic fallback and its recoverable routing warning. Do not choose a blocked stub solely because that side has free capacity or enlarge the owner behind the user's handle.
- Apply manual overrides and use the existing anchor-respecting
automatic_positionsas the initial position allocator. It already degrades its desired gap when anchors are crowded (port_layout.rs:319–397). Do not claim a guaranteed28 gap around arbitrary authored offsets: two manual anchors may coincide legally.
A scarcity counterexample for the assignment layer has capacities L8/R8/T≥4 and no admissible Bottom: eight ports allow L/T and prefer L, nine allow L/R, and three allow R/T. Assigning the first eight to L can strand the ninth L/R port although moving one earlier port to T gives a feasible assignment.20 neutral ports have minimum height244, whose L/R capacities are8, and sufficient top capacity. A concrete model fixture must realize those clear-side sets using peer blockers and distant peers before this becomes executed core evidence. Simple “fewest clear sides first” is not enough here because all sets have two sides.
Counterexample gates
Geometry and parity. Re-run all eight inverse handles, including old absolute forbidden rectangles224×242 at(0,−10),214×232 at(10,0), and224×222 at(0,0). The new policy should realize those exact valid rectangles. Also use each policy's own baseline, including zero motion, smaller valid records, enclosure-displaced origins, allocated descendants, folds, state headers and partially shown ancestors. Moving a peer, hiding a line or editing an anchor must not change rectangular node bounds; filters already run after port geometry (projection.rs:521–529). Check accepted source/API records and full preview/reopen equality.
Readable clear space. Use8,20 and100 neutral ports all facing the same peer(s), plus asymmetric function inputs/outputs. When a clear nominal-capacity assignment exists and there are no crowding manual anchors, capacity-aware placement must maintain the28-unit target within each side; pure spacing adaptation is expected to fail on the100-port case. Current component glyphs are14×14 world units (diagram.rs:1282–1295), so merely showing nonidentical coordinates is not a readability evaluator. Measure adjacent distances and overlaps, then inspect labeled native workflows at ordinary and low zoom later.
Scarce exits. Test the20-port assignment counterexample, a narrow peer gap, and all-clear-capacity exhausted while one clear side remains. Preserve the existing narrow-gap no-warning example (tests/port_anchors.rs:511–533). Compare the final outward stubs and routed paths, not just the midpoint predicate: current clear_exit examines only the side midpoint against connected peers, whereas final ports may lie near corners and routing considers unrelated obstacles too (routing.rs:627–647). A free midpoint can conceal a blocked actual port stub. New blocked routes where the control has a clear readable route are a material failure requiring a position/assignment refinement.
Manual precision/stability. Anchors at0,.25,.5,1, near-coincident anchors, all ports manually placed on one side, and anchors moved between sides. Retain exact metadata and final fractional border position. Keep all nodes and unrelated automatic sides stable on an anchor-only edit. If manual choices force physical crowding, show that condition honestly; do not move authored anchors or fail an otherwise valid resize.
Determinism and route quality. Permute construction/list order, rename elements, translate a group, fold/reopen, filter exchanges and replay source/API edits. Compare port sides, endpoints, route warnings, total length, bend/crossing counts, and authored-pin preservation. Use small realistic OA/SA scenes as well as the synthetic extremes; reduced dimensions alone do not establish better layouts. Automatic side changes at capacity thresholds are permitted but must not cause owner-size oscillation, repeated flips for a stationary pointer or pathological label/route churn.
Upgrade footprint. Removing the dynamic growth pass can shrink previously auto-expanded views on reopening unchanged authored source. The verified224×160 fixture would now stay224×160. Inventory affected examples and document this rendering change. Do not silently normalize every placement or rewrite existing sources to manufacture old-version pixel equivalence. Manual fractions remain exact, but their physical separation and existing route-pin relationships must be inspected in the new geometry.
Smallest next prototype
After root claims the bounded implementation and grants a compiler lease, use an isolated experimental core copy/worktree and separate build artifacts. Keep tracked production inputs untouched initially. Introduce three temporary comparison modes at the existing port-layout boundary: Current, SameSidesAdaptSpacing, and CapacityAware. Use the same actual semantic minima, enclosure, position allocation and router for all modes; a narrow experiment-only entrypoint may pass the policy through projection. Do not duplicate the projector in a desktop-only solver.
First prove Current reproduces the identified core output, then test the eight-port geometry and100-port readability controls, followed by the scarcity/narrow-gap/manual cases. Record candidate projections plus actual routing, not hypothetical performance. If a simple greedy capacity allocator fails the scarcity fixture, test the small deterministic alternating reassignment before promoting it. If both no-feedback modes create serious new blocked/crossed routes, investigate actual slot clearance rather than reinstating silent owner enlargement.
Only after these comparisons pass should root select the policy, extract shared geometry/minimum facts for the production resize planner, update the derived projection contract and port tests, and proceed to handle/UI evaluation. The previous finite-seed inverse planner is reusable; its residual loop has no demonstrated value. This preserves progress toward complete eight-handle editing without promoting an unverified port policy or treating a reduced positive-edge feature as completion.