Repository navigation
Conversation
A relationship label follows its edge, but the placement checked it as an upright box, so a turned label could be refused next to a card it did not touch, or let through over another turned label. Labels are now checked as oriented boxes (separating axes; touching is clear), each candidate spot along the edge is tried nearest-first, and the search budget covers a whole organized graph (64 labels, 160 attempts) so labels are not dropped for running out of tries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
organizeTopology takes an optional edgeGap (the visible length an edge needs between its two cards) and spread hook. Chains, cycles, rings and hubs use the gap of each pair instead of one fixed 64 px; with no options the positions are exactly the old ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
computeCompactLayout takes an optional edgeGap. Linked cards in a row and rows joined by edges get the gap their labels need; only rows with no edge to another row wrap (chains snake), rows are ordered by barycentre sweeps to cut crossings, and each card is aligned under its neighbours with isotonic regression so edges stay short. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
labelClearance.ts places every label as the renderer does over a whole layout and makes room where one would be dropped: Organize and the hierarchical rows reserve labelGap per edge at the zoom the camera will frame them, then spread by the smallest factor that frees every label (rows apart first). clearFreeCards moves only the cards the force layout placed itself. Groups over 200 cards keep only the reserved gaps. labelClearanceShapes.ts holds the new-user graphs and hard shapes (hubs, two hubs, a long chain, a dense cluster of 30, long labels) shared by the unit and browser tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Organize and the hierarchical toggle lay out through labelClearance with the measured label of every drawn edge and the camera framing; the force link distance uses the measured label, and once the simulation settles clearFreeCards frees labels by moving only unpinned cards. A new layout forgets the remembered label spots so labels are placed afresh. The "Show Mini-Map" button is now an obstacle labels and fits keep clear of. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A blocking browser sequence presses the real Organize control (the View sheet on phones), toggles hierarchical and back, and lets the force layout settle from unplaced items, on the example graphs and hard shapes. edgeLabelAudit reads every relationship label from the DOM (turned boxes, elementFromPoint, the visible gap) and counts dropped, covered and overlapping labels. Registered in the pr and full profiles and the layout CI shard; lesson recorded in the agents inbox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
Relationship labels disappeared below 60% zoom, so after Organize or the hierarchical fit (which frame a graph further out) most of them were gone. They now show while card titles show (CARD_TITLES_HIDE_BELOW, 0.34, shared with the zoom-out levels of #277 through cardTitleZoom.ts), at their full 14 px on screen. Graphs of up to 60 items are framed whole after Organize and in the hierarchical layout, down to CARD_TITLES_SHOW_ABOVE (0.38), instead of the 0.65 floor (and the phone's 0.5) that left part of the graph off screen. Each layout leaves label room for the zoom it will be framed at, found by bisection, and an organized layout taller than a wide screen (or wider than a tall one) is turned a quarter turn when that frames it closer and moves no card onto another or hides a label. Larger graphs keep the 0.65 floor. The label placement budget is back to dev's 32 labels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd text size The journey now runs on Welcome and the twelve-item launch checklist (fifteen relationships) on desktop and iPhone. At the camera the app rests on after Organize and after the hierarchical fit, every edge with both cards on screen must show its label with text of at least 11 px, clear of cards and labels; the whole graph must be on screen unless the camera is at the smallest zoom where titles and labels still show; and at least one edge must be in view, so a camera that shows almost nothing cannot pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
…thing Small graphs (up to 60 items) are now framed whole down to 0.34, the zoom where card titles and labels stop showing, instead of 0.38. When even that is too small, the camera no longer centres on an empty middle. Organize stays centred if the graph nearly fits (at least 0.8 of the floor); otherwise it frames the hub's neighbourhood. The hierarchical layout shows its top rows, prerequisites first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The layout-save notice appears after the camera has framed the graph, so a card it covers is not off screen. It is now recorded as "partly under controls" and is no longer a failure. The launch checklist runs on desktop only: at the 0.34 cutoff a phone is about 1150 graph units wide, and the hub with its seven neighbours does not fit with full labels. Compact label chips, a follow-up, are what make it fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
edgeRouteLabel now tries every spot along an edge, so a blocked label made four times the checks it used to. Each placement first keeps the obstacles and wires that reach any of its candidate spots (each one counts against the check budget, so the budget still bounds the work), then tests each spot against those with exact axis-aligned bounds before the turned-box test. The turned-box test no longer allocates. Results are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #280: Organize and the hierarchical toggle ran the search in the click handler for up to 200 cards (1.4 s for 60 cards, 2.9 s for 200). - Above WHOLE_FIT_MAX_CARDS (60) both layouts are the plain ones, framed at the 0.65 floor, whatever the floor (also for unplaced items). - One click's search shares LAYOUT_CHECKS of label checks; a spread search that runs out keeps what it has. - withFramedRoom finds the closest framed zoom from the layouts at 100% and at the lowest zoom plus at most FRAMED_STEPS more (regula falsi) instead of bisecting, and keeps looking above the lowest zoom when its layout does not fit there. - Clearing labels after the force layout settles has the same bounds. - Turning the hierarchical layout off restores the framing Organize chose. Unit tests: 60 cards and 90 relationships within a second for each layout (about 100 ms on a desktop), plain layouts above 60 cards at floor 0 and 0.65, and a four-spoke hub on a phone framed at its closest fitting zoom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When labels still collide, Organize spread each component evenly. On a phone that widened a hub's spokes past the screen: a hub with four spokes on a 390 px phone framed at 0.39 (hub card 88 px, its title broken mid-word). Each component now also tries spreading along the screen's long side only, and keeps that when it frames closer for no more area: the same hub frames at 0.49 in the unit geometry, and in the browser its card and title read again (topology-organization at 390 px). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a phone - organize-labels: each checked stage must draw every relationship of the graph (the edges-in-view check could pass with none drawn). It waits only for a Welcome graph to exist (CI had emptied it), and checks the launch checklist on iPhone too instead of skipping it (a blocking sequence may not skip): there the camera rests on the hub with no neighbour whole beside it until compact label chips (#283), so only that check is lifted. - itemSymbolVisual: a turned label overlaps a card, control or label only when its outline does. Two parallel labels beside a diagonal wire have overlapping bounds while their outlines are 34 px apart (CI, item-wires). - topology-organization: on a phone a small graph is framed whole down to the zoom where titles and labels still show, so the hub must read there (its title at 14 px, the camera at or above that zoom) instead of being 132 px wide; desktop keeps 132 px. Titles must still match exactly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # .github/workflows/ci.yml # packages/web/src/lib/README.md # tests/lib/runner/unified-cli.test.mjs
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
On a 390 px phone two compact cards and a label side by side do not fit at any zoom where the cards' titles still fit whole: below about 0.45 (in CI's fonts) "System coordinator" broke to "coordinato r", and at 0.5 the hub card was 131 px wide where topology-organization asks for 132. So a phone keeps dev's Organize camera, the 0.65 floor centred on the busiest item's neighbourhood, with label room for that zoom; the hierarchical layout keeps the phone's 0.5 (PHONE_READABLE_SCALE, now in lib/cardTitleZoom.ts). Desktops and tablets still frame a graph of up to 60 items whole down to 0.34. Fitting a whole graph on a phone needs compact label chips (#283). topology-organization.spec.ts is back to dev's version. The organize-labels journey checks for cards off screen against each stage's floor on iPhone, and measures once the "Layout saved" note has faded (it covered the bottom card for a few seconds). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spreading a component along the screen's long side only was added so a hub framed whole on a phone at 0.34 kept its title. Phones now keep the 0.65 Organize floor, and spreading one axis turns a hub's ring into an ellipse: topology-organization at 1440 px found the spokes' distances from the hub 53 graph units apart. Components spread evenly again, as before that commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Real item ids are random and break ties in the organizer and the label order. For some orders a label stayed hidden after the search said it fit: the component spread was returned with a 1.1 slack nobody checked (spreading is not monotonic: a wire can swing onto a label further out), and the hierarchical rows were never checked after spreading both ways. The slack is now kept only where it still frees every label, and each finished layout (after packing and the quarter turn) is checked as a whole and spread a little more if a label is still hidden. A unit test lays out the launch checklist and two connected hubs with ids from five seeds that hid a label before (5 of 10 cases failed), on three screens, after Organize and in the hierarchical layout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The renderer places each label starting from the spot it had in the previous frame, so labels stay steady while cards move. After Organize the camera animates to its zoom, and the spots picked on the way could box out a label that a fresh placement (the one the layouts leave room for) shows: the launch checklist on desktop lost one label in about half the journey runs. When a graph has at most 60 relationships and a label is missing, the renderer now also tries a fresh placement (dragged labels keep their spot) and keeps it when it shows more labels. Larger graphs are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both branches defined CARD_TITLES_HIDE_BELOW and CARD_TITLES_SHOW_ABOVE; graphZoomContext now takes them from lib/cardTitleZoom.ts, so the zoom-out levels and the relationship labels share one cutoff. The sequence lists, profiles, CLI test and READMEs keep both organize-labels and zoom-out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
A compact card is at most 240 graph units wide and keeps its title at 14 px
on screen, so below about 0.45 zoom a long word no longer fits a line and
fitGraphText split it ("coordinato r", "Design mockup s"). Organize now rests
at 0.34 on a desktop, so the first press showed it. Titles now break only at
spaces; a word wider than the line is cut and ends in "…" ("coordinat…")
instead of carrying on to the next line, at every zoom. When more text
follows the last line, that line ends after a whole word and "…" where one
fits. Scripts written without spaces (Chinese, Japanese) still break between
characters.
A unit test wraps seven titles at widths 40 to 320 and fails if a line
starts or ends inside a word (it failed before: "Sys" / "tem"). The
organize-labels journey fails a stage when a card title line on screen is
not whole words of the title, or the start of one before "…".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The toolchain shard, the sequence list and profiles, the CLI test and the READMEs keep both organize-labels and relationship-edit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
Independent review of 63c8f28 (whole PR against
|
| Items | dev | PR |
|---|---|---|
| 20 | 988×800 | 4828×224 |
| 100 | 988×3680 | 25308×224 |
| 200 | 988×7280 | 50908×224 |
Random 2000 cards × 4000 edges comes out 92124 units wide.
Fix: keep dev's wrapping above WHOLE_FIT_MAX_CARDS, and pin that test to dev's output. Below 60 this is a design call: a 20-item "all depend on one epic" graph was framed near 0.9 on dev and is now held at 0.34. If that is intended, say so in the PR body.
should-fix
-
The first open of an unplaced graph is framed further out than on
dev, often below the title cutoff (InteractiveGraphVisualization.tsx:2148,labelClearance.ts:430-432). The initial organization uses floor 0. When no label zoom fits,withFramedRoomreturns the most spread layout, and the camera frames it below 0.34, where neither labels nor titles show.- Fit zoom, dev → PR, desktop unless noted:
- Plan a launch: 0.370 → 0.201
- Launch checklist: 0.343 → 0.262 (iPad 0.466 → 0.194)
- Two connected hubs: 0.492 → 0.170
- Hub with 12 spokes: 0.482 → 0.321
- Long labels: 0.391 → 0.318
- This hits imported or agent-created graphs (all items with no position).
- Fix: on desktop and tablet, give it Organize's whole-fit floor and framing, or fall back to the plain organizer when nothing fits at floor 0.
- Fit zoom, dev → PR, desktop unless noted:
-
fitGraphTextdrops the rest of a long token at scale 1, even with lines free (graphSymbolLayout.ts:82). Ordinary titles do not change at scale 1: I checked 18, and the only change was titles that already overflowed 3 lines, which now end on a whole word. But a token wider than the line (a path, URL, identifier or compound word) used to wrap and show whole, and now loses its tail:Update packages/web/src/lib/labelClearance.ts→["Update","packages/web/src/lib/labelCle…"](dev showed all of it on 3 lines)PaymentGatewayRetryReconciliationHandler→ one line,PaymentGatewayRetryReconci…Investigate https://…/works…, thencrash: an ellipsis in the middle of a title
Suggestion: ellipsize only on compact cards (scale < 1), or break such tokens at
/ . - _or camelCase while lines remain.The new "no split words" test does fail on dev's
fitGraphText(System coordinator at 40: ['Sys','tem']), so it is not vacuous. -
The fresh label retry runs where it cannot help (
InteractiveGraphVisualization.tsx:3798). It compares against every eligible candidate, buteligibleignores the viewport, andplaceItemLabelsstops at 32 labels. So with 33 to 60 relationships, or any edge off screen (any zoom-in), it runs on every label pass, never wins, and doubles the label work. Compare instead against in-viewport eligible candidates, capped atITEM_LABEL_BUDGET.labels. -
clearFreeCards.hiddenNowacts on labels it never tried (labelClearance.ts:625-633). On the call that uses up the work,hiddenincludes labels skipped for budget, andstep()pushes their cards apart.spreadForLabelsandturnToScreenalready treat that case as "no answer";hiddenNowshould do the same. -
Journey coverage gaps. The journey runs only on placed graphs, for Organize and hierarchical. It does not cover hierarchical → force, the unplaced first load (Complete Neo4j migration with DOM flash fixes and external access support #3) or the settle-time clearing (Complete startup automation and external access fixes #1).
mode: 'unplaced'(organize-labels.spec.ts:46,58-65) is never used. The comment atunified.config.mjs:95("once the force layout settles … hard shapes") and the "force after / force (unplaced)" rows in the PR body describe stages the spec no longer has. The checks it does run are not vacuous.
Checked and fine
- Camera framing: desktop/tablet frame whole at 0.34 for ≤60 cards; phones keep 0.65 after Organize and 0.5 in hierarchical.
- Switching hierarchical back to force restores the earlier floor and framing.
- Organize and hierarchical pin cards, and
clearFreeCardsmoves only cards withfx == null. Saved positions are not overwritten, apart from Complete startup automation and external access fixes #1.
nits (simplicity)
- Exported but used only inside their own module:
LABEL_PADDING,labelWorldScale,labelSideOffset,spreadPoint,SPREAD_CHECKS,SPREAD_MAX_CARDS,FRAMED_STEPS(labelClearance.ts) andLABEL_SAMPLES(edgeRouteGeometry.ts). LikewiseEXAMPLE_SHAPES,HARD_SHAPESand the*_SHAPEconstants other than Welcome and Launch checklist (labelClearanceShapes.ts). SPREAD_CHECKS(4M) is the defaultworkforspreadForLabels/clearFreeCards. Every production caller passesLAYOUT_CHECKS, so the default is a trap: a future caller that omits it gets a budget more than 10× larger. Default toLAYOUT_CHECKS.labelReportis test-only code in a production module.draggedis passed through into theplaceItemLabelscandidates.
Verdict: not ready. Fix #1 and #2 first. The rest of the design is sound: the work is bounded, the results are deterministic and the retry is not per frame.
🤖 Generated with Claude Code
After the force layout settles, clearFreeCards moved free cards for every hidden label, including one between two saved cards that no free card can fix: its spread search never fitted, returned its 4x maximum, and the settled layout ran it twice, so a card an agent added to a saved graph flew to 4x and then 16x its distance and was saved there. Now only labels with a free card at one end count. The steps are kept only when they show more of those labels; the spread moves only the free cards of the groups those labels are in and is kept only when it shows every label of the cards it moves. Run again on its own result, it moves nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The label-room rows had replaced computeCompactLayout itself, and a row that edges leave never wraps there, so a graph too large to frame whole lost dev's wrapping: a hub with 100 dependents became 25564 units wide instead of 988, and 2,000 items one very wide strip. computeCompactLayout is dev's again, byte for byte, and graphs above WHOLE_FIT_MAX_CARDS use it. The label-room rows are computeLabelRoomLayout, used only up to 60 cards, where wrapping a row that edges leave would put cards on those edges and hide their labels. Golden numbers taken from dev pin the large layouts: a hub with 100 dependents is 988 x 3680, 2,000 items and 4,000 relationships 988 x 72656. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A graph whose items have no saved position is organized when it opens. That organization had been given label room down to zoom 0 as well, which spread it for the smallest labels and framed it further out than titles show: "Plan a launch" opened at 0.20 instead of dev's 0.37 on a desktop. The owner's report is about Organize and the layout toggle, so the first open goes back to dev's organizer and framing. The organize-labels journey now opens "Plan a launch" with every item unplaced and checks it rests no lower than the 0.34 where titles and labels show. The sequence comment says what the journey checks today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Breaking card titles only at spaces also cut every path, URL or identifier wider than a line, even on a full-size card with lines to spare: "Update packages/web/src/lib/labelClearance.ts" lost its file name. Such a token (something other than letters inside its punctuation, or camelCase) now breaks inside, after a separator or before a capital where it can, and shows in full while lines are left; "…" only ends the last line. An ordinary word wider than a line is still cut with "…", never split. The journey's title check accepts pieces of such tokens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The renderer's fresh-spot retry ran whenever fewer labels were placed than were drawn, which also counts labels off screen and past the 32-label cap: it then ran on every label pass where it could not show anything more. labelsMissed asks the placement itself: a label on screen was tried, found no spot, and the cap leaves room for it. The label-room lesson records the settled-layout rule, the large rows and first open kept as on dev, and the narrower retry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No conflicts: dev changed only the installer and its contract test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
The owner reported Organize and the force layout, not the hierarchical one. Its label-room rows did not wrap a row that edges leave, so a common shape, an epic with 20 tasks, went from 988 to 4828 units wide with the camera on its top rows. The hierarchical layout is dev's again for every graph: computeCompactLayout and its tests as on dev, the toggle's positions and framing as on dev, and PHONE_READABLE_SCALE back beside the phone fit that uses it. computeLabelRoomLayout, hierarchyWithLabelRoom, the rows-only spread and their tests are gone, and the organize-labels journey checks Organize and the first open of an unplaced graph only. Label room in the hierarchical layout is #283. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🧪 Comprehensive Test Suite
Full-stack smoke gate runs in the CI workflow. |
Relationship (edge) type labels went missing after "Organize around connections", in the hierarchical layout and once the force layout settled. The renderer never draws a label over a card or another label: it drops a label it cannot place. Labels were dropped for two reasons. They were hidden below 60% zoom, and Organize and the hierarchical fit frame most graphs further out than that. And the layouts left no room along an edge for its label. This PR is the minimal fix for what the owner reported, "Organize around connections" and the force layout; the hierarchical layout stays as on dev. Label room in the hierarchical layout, icon chips, hub placement, and lines through cards or on top of each other are in #283.
What changes
CARD_TITLES_HIDE_BELOW(0.34) instead of 0.6. It lives in the newlib/cardTitleZoom.ts, and the zoom-out levels of Zoom out: labelled levels from items to graphs to projects (#277) #279 (merged fromdev) now take it from there, so cards and labels share one cutoff. Labels keep their 14 px screen size at any zoom.WHOLE_FIT_MAX_CARDS), Organize frames the whole graph, down to that 0.34 zoom. This replaces the 0.65 floor that cut part of the graph off. Where even 0.34 is not enough, the camera holds 0.34, centred on the graph when it nearly fits and on the busiest item's neighbourhood otherwise. Graphs over 60 items keep the plain organizer, the 0.65 floor and the overview/LOD behaviour.topology-organizationasks for 132. So after Organize a phone keeps dev's camera: the 0.65 floor, centred on the busiest item's neighbourhood, and Organize leaves label room for that zoom. Fitting a whole graph on a phone needs compact label chips (Layouts: compact label chips on phones, hub placement in hierarchical, wires through cards #283).labelClearance.ts). That zoom comes from the layouts at 100% and at the lowest zoom, plus at most two more (regula falsi). If wires still cross labels, a component spreads evenly by the smallest factor that frees them. A tall organized layout on a wide screen, or a wide one on a tall screen, is turned a quarter turn when that frames it closer without putting cards on cards or hiding a label. After the force layout settles, only cards the simulation placed itself are moved, only for labels with such a card at one end, and a move is kept only when it shows more of those labels; saved positions never move.labelsMissed).LAYOUT_CHECKSlabel checks and five layouts per click: about 100 ms for 60 cards and 90 relationships on a desktop.fitGraphTextsplit it ("coordinato r", "Design mockup s"). Organize rests at 0.34 on a desktop, so the first press showed it. A word wider than its line is now cut and ends in "…" ("coordinat…", "Design mocku…") at every zoom. A path, URL or identifier wider than a line (anything but letters inside its punctuation, or camelCase) breaks inside instead, after a separator or before a capital, and shows in full while lines are left ("Update / packages/web/src/lib/ / labelClearance.ts"); "…" only ends the last line. Scripts written without spaces still break between characters. Unit tests wrap seven titles at widths 40 to 320 and fail if a line starts or ends inside a word (before the fix: "Sys" / "tem"), and check that paths, URLs and identifiers come back whole; the journey fails a stage when a card title line on screen splits a word.Review fixes (since the first review)
drawn === edges) and have at least one edge with both cards on screen.CI on the first push also found:
organize-labelswaited for a filled Welcome graph that earlier CI tests had emptied. It now waits only for the graph to exist.item-symbols: two parallel labels beside a diagonal wire were flagged as overlapping because their axis-aligned bounds overlap, while their outlines are 34 px apart. The check now uses the turned outlines.topology-organizationat 390 px: the hub card must be 132 px wide, and on a phone framed whole at 0.34 its title broke mid-word ("coordinato r"). Phones now keep their floors (above), and the test is dev's, unchanged.large-symbols: one zoom took 5.1 s against the 5 s limit. A browser profile of that zoom is dominated by layout reflow (getBoundingClientRectinSemanticGraphOverviewandupdateEdgePositions), not by label placement. It passed on the next push.Local journey runs then showed the launch checklist on desktop losing one label in about half the runs (the ids decide the order). The unit test
label room whatever the item idscovers five id orders that hid a label before (5 of 10 cases failed), and the renderer's fresh retry covers the order in which the camera's path placed labels. After both, the journey passed twice in a row locally.Second review fixes (re-review at 63c8f28)
Rule for this round: what the owner's report does not need goes back to dev's behaviour. Each item has a test that failed before and passes now.
clearFreeCards): only labels with a free card at one end count; steps and the spread are kept only when they show more of those labels, the spread moves only the free cards of those labels' groups and must show all their labels; a second pass moves nothingone new card in a saved graph whose saved cards hide a label: the card stays put when its label shows (before: (600, 400) → (2170, 1200)); when its own label is hidden it moves less than 1.5 label gaps from its neighbour (before: 1746 units away) and does not move again over two more passeslayoutAlgorithms.tswith its tests are dev's, byte for byte; the label-room rows and their tests are gonea graph of unplaced items opens no smaller than its titles and labels show: "Plan a launch" unplaced rests at ≥ 0.34 (with the old line: 0.197)fitGraphText): such tokens break inside while lines are left; ordinary words still never splitshows a path, URL or identifier wider than the line in full…(failed on 63c8f28)labelsMissed)a label is missed only when one on screen was tried and found no spot(the old condition counted an off-screen label and a capped one as missing)Third round: the hierarchical layout is dev's at every size. The owner reported Organize and the force layout, and the label-room rows made a common shape, an epic with 20 tasks, 4828 units wide instead of 988 with the camera on the top rows. Label room in the hierarchical layout and the review's remaining notes are on #283.
Test
organize-labelsis a blocking sequence in thepr/fullprofiles and the "toolchain, schematic, LOD, layout" CI shard, run on desktop and iPhone. It creates Welcome and a twelve-item launch checklist with fifteen relationships of mixed types (the graph that was reported), presses the real Organize control (on a phone, in the View sheet) and checks the view it rests on. It also opens "Plan a launch" with every item unplaced and checks the camera rests no lower than 0.34. At the camera the app rests on,edgeLabelAudit.tsreads every label from the DOM. It fails a stage if:elementFromPoint) or lies outside its edge's visible gap;It measures once the "Layout saved" note has faded, at the view a person is left with.
Unit tests (
labelClearance.test.ts) place labels the way the renderer does, over whole layouts of the example graphs and the hard shapes (a hub with 12 spokes, two hubs, a long chain, a dense cluster of 30, long labels) on three screen sizes: none is dropped. They include five id orders of the launch checklist and two connected hubs that hid a label before.Red before (unchanged
dev3a629e2)This is the first version of the journey run against the unchanged source. That version also measured the force layout after Organize ("force after") and graphs of unplaced items ("force (unplaced)"); the journey now checks Organize, the hierarchical layout and the first open of an unplaced graph. Each cell is the labels dropped out of the edges whose two cards were both on screen. No label was ever drawn over a card or another label: the symptom is always a missing label. "zoom" marks a camera below the old 0.6 cutoff, where every label was hidden.
Welcome is the graph a new user sees first. Before this change, all 3 of its labels were dropped after Organize on every device, and in the hierarchical layout too. On iPhone, Organize framed it at 0.65, with part of the graph off screen.
After (this branch after merging
dev25a6a5e, local run oforganize-labels: 6 passed, desktop and iPhone)Measured at the camera the app rests on after Organize. "Area" and "mean edge" are in graph units, centre to centre. "Edges in view" have both cards on screen, clear of the controls; none of them lost its label.
"Plan a launch" with every item unplaced opens at 0.374 on desktop (12/12 cards on screen) and 0.5 on iPhone, as on dev. Like dev, that first view hides most of its labels (1 of 11 shown on desktop) until the person presses Organize.
Spread for Welcome went from area 301k and mean edge 300 (desktop, organized, before) to 308k and 409. On iPhone, Organize frames it at 0.65 as before, now with the label of the edge on screen shown (before: all dropped). Earlier local runs:
item-wires13 passed (topology-organizationat 390 and 1440 px included),large-symbolspassed,semantic-lodpassed (earlier push), web unit tests 83 files / 825 tests passed, runner CLI tests 43 passed. After the third round (hierarchical as on dev): the affected unit suites (labelClearance, layoutAlgorithms, graphSymbolLayout, edgeLabelPlacement, topologyOrganization, edgeRouteGeometry, localItemLayout, graphFit) 177 tests passed,tscclean, runner CLI tests 46 passed,playwright test --listlists the journey's 6 tests.Before and after: Welcome, Organize
Launch checklist on desktop after Organize: 14 of 15 labels, none dropped among the 13 edges on screen.
Not in this PR: #283
DEPENDS_ONsets the rows, so a hub with mixed relationships (Launch plan) sits at the bottom.🤖 Generated with Claude Code