carlos / platform Public

/fleet/architecture: the box layer is off-screen at every width, box names truncate to a single string, and the diagram draws a path that does not exist Issue open

/fleet/architecture shipped in #237 and #322 and has never been looked at in a browser. It has now been, over a flagship-shaped estate: four regions, a bring-your-own Pi, an unclaimed machine, two alarms per box, buckets, certs and an unknown resource kind. The render harness is on branch arch-browser-pass (TestArchDump, skipped unless ARCH_DUMP is set).

Most of the page is right. The resource tables carry every resource exactly once and pass unknown kinds through verbatim; the box cards do what §7 promised (t4g.medium · running · 2 cores · 4 GB · 20 GB disk · $26/mo, apps joined through the registry); the drift chips fire on a mispriced box and stay quiet on a priced one; annie-welding reads "no box reporting" and pi-dublin reads "bring-your-own box". The soft-fail posture behaves.

Four things are wrong, and the first three are all in archlayout.go.

1. The diagram never fits, at any screen width

The SVG is 1918px wide. .archwrap is capped by the 1024px content column, and that cap does not move — measured archwrap client=1024, scrollW=1918 at both 1280px and 1920px viewport. So 47% of the picture is hidden on every desktop and 77% on mobile, and it is the same 47% every time: columns 5, 6 and 7, which hold every box, every app, and the deployment bucket.

x=  24 VISIBLE     oncarlos.com, carloku.com
x= 304 VISIBLE     au/ie/uk/us.oncarlos.com, mail.carloku.com
x= 584 VISIBLE     52.31.0.11, 18.132.0.22, 54.87.0.33, 13.55.0.44
x= 864 CLIPPED     10 inbound-smtp.eu-we…
x=1144 OFF-SCREEN  carlos-flagship-au/ie/uk/us, pi-dublin, annie-welding
x=1424 OFF-SCREEN  kass ×5
x=1704 OFF-SCREEN  carlos-deployment-427880590669

A page whose subject is how a request reaches a process shows the DNS and the IPs and hides the process. Horizontal scroll exists but nothing on the page says so — no fade, no arrow, no cue. And this is not a large-estate problem that arrives later: Width = padding*2 + layers*nodeW + (layers-1)*gapX, so seven layers is 1918px and any deployment with the full chain is already past the cap.

Either let .archwrap break out of the content column, or scale the SVG to fit with a way to zoom. Whichever — the box layer has to be on screen by default.

2. All four flagship boxes render as carlos-flagship-…

alarmRoom reserves len(Alarms)*alarmStep + alarmR = 33px for two alarms. That leaves nodeW - 2*textPad - 33 = 133px of title, and fitText turns 133px at 13px/0.58 into 17 characters. carlos-flagship-ie is 18. Every flagship box truncates one character before the character that tells it apart from the other three.

This is the production state, not a fixture artifact: pinfra wired memory and reachability alarms onto all four boxes on 2026-08-28, so every box on the flagship carries exactly two alarms today.

#322 fixed text overflowing its box and created this. The fix is to stop making the title and the alarms share a line — put the marks in a corner or on the subtitle row and give the title the node's full width.

3. The diagram draws a path that does not exist

The edge 13.55.0.44 → carlos-flagship-au runs at y=56 from x=840 to x=1144. The node 10 inbound-smtp.eu-west-1… sits at x=864–1120 on that same row. The edge passes straight under it, and since nodes paint after edges the line disappears behind the node and comes out the other side. The top row reads as one continuous chain:

carloku.com → au.oncarlos.com → 13.55.0.44 → 10 inbound-smtp… → carlos-flagship-au → kass → bucket

Two of those hops are fiction. mail.carloku.com's MX target is a dead end that leaves the estate; it has no outgoing edge at all. A reader has no way to know that.

This is the same failure archgraph.go:67-74 records as the reason alarms were moved onto the nodes they watch — an edge running under a node makes the picture read as a request flowing through it. It was fixed for the alarm column and not for edges that skip a layer. Layer-skipping edges need to route around occupied rows.

4. Nothing above the fold says an alarm is firing

With four alarms in ALARM, the page's header says only Estate 427880590669 · inventoried 2026-08-31 14:24 UTC. The red marks are off-screen per #1, and the Alarms table is roughly 4,300px down. A firing alarm should be visible without scrolling in either direction.

Smaller

  • Box cards are 704px wide against 1024px tables, so the column edge does not line up down the page.
  • "Refresh inventory", the page's only control, sits below every resource table at the very bottom.

Not part of this, but open alongside it

  • The flagship grant is unconfirmed. pinfra's vendored region-host module under flagship/.terraform/ was refreshed 2026-08-28 and does carry the inventory statement, so the apply that day should have landed it — but nobody has checked whether the estate half of the page is actually populated. Opening the page answers it: a named account in the header means granted.
  • Tito has no grant. Its vendored module is still the 2026-08-12 copy. Tito's estate half is reporting "not granted", which per the spec's §8 status note is the designed state — but it is a decision nobody has made on purpose.

All four fixed, plus both of the smaller ones. Branch arch-page-fits.

1. The box layer is on screen. .archwrap is now sized to the VIEWPORT rather than to main's 64rem column — the cap was the whole problem, since it does not move with the window. On a 1920 screen that shows essentially the whole 1918-unit drawing; on anything narrower it still scrolls, and the page now says so under the diagram, naming what is off to the right. Bounded with min(123.75rem, calc(100vw - 3rem)) rather than set to 100vw deliberately: 100vw includes the scrollbar on several browsers and would have given the whole PAGE a sideways scroll to fix a diagram that already had its own.

2. The names survive. You had the arithmetic exactly right, and I reproduced it before changing anything — the old code renders carlos-flagship-… for all four, cut at 17 characters. The marks did not need that space: a node is 64 tall with baselines at +24 and +44, so a 5px mark centred at +56 clears the subtitle's descenders and sits inside the rounded corner. They moved to the bottom right and BOTH lines got the full width back. The test asserts the subtitles too, so the title cannot have been paid for out of the line below it.

3. The path that does not exist is gone. Layer-skipping edges now route through a lane below every node, with both vertical runs in the middle of an inter-layer gap rather than in a column. Your diagnosis of the mechanism is what the fix is built on — and you were right that it is the same failure archgraph.go:67-74 records for the alarm column, fixed there and not for edges.

One thing your report turned up that I would not have found: archFixture() already contains a layer-skipping edge, and TestEveryEdgeReachesThePage counted <path class="archedge" as an exact string. My skip edges carry archedge archedge-skip, so the count went 4 against 5 — the test caught its own blind spot. It now counts on the class prefix.

4. A firing alarm is named above the fold. ArchView.Firing carries each firing alarm WITH the node it watches — mem-low alone sends a reader to four near-identical box names — and the page renders it as an error banner beside the inventory line.

Both smaller ones too: box cards widened from 44rem to 64rem so the column edge stops stepping in and out down the page, and "Refresh inventory" moved to the top beside the timestamp it acts on. That form is deliberately outside {{with .Arch}} — a page that could not read an inventory is exactly the page whose refresh button has to still be there.

The honest caveat: I cannot open this page in a browser from here, so every fix is pinned by a test that measures the thing your browser showed rather than by looking. That works for the geometry — truncation, edge routing, mark placement, the summary — and it does not cover the CSS. The min() arithmetic is worked through in the comment beside it and checks out at 1920, 1280 and 800, but a real look at the page is the last step, and it is yours.

Not touched, since they are open questions rather than defects: whether the flagship's estate half is actually populated (opening the page answers it — a named account in the header means granted), and tito having no grant.

Triage, 2026-09-05. arch-page-fits reviewed. CI green. Verdict: merge. The cleanest of the seven branches currently waiting.

I re-derived the geometry rather than trusting the commit message, because your report's value was that it did the arithmetic and the arithmetic is what the fix turns on:

  • Truncation. fitText now gets 190 - 24 = 166px, so int(166/(13*0.58)) = 22 characters. carlos-flagship-ie is 18 and fits with room. The old formula subtracted the 33px alarmRoom for 166−33 = 133 → 17 characters, exactly one short of 18. Your diagnosis reproduces precisely and the fix follows from it.
  • The marks clear both text lines. n.Y + n.H - 8 with radius 5 spans n.Y+51..n.Y+61, inside a 64-tall node and below the subtitle baseline at +44.
  • The edge lane cannot collide, for any estate — not just the fixture. lane := v.Height - padding/2 sits 12px below the lowest node bottom (v.Height-24) regardless of layout shape, and both vertical runs land at mid-gap where nodes never reach. That holds algebraically for any number of skipped layers, which is the property that matters — your #3 was a layer-skipping edge, and a fix that only worked at the fixture's shape would come back.
  • The min() arithmetic checks out algebraically, not just at round numbers: .archwrap's left edge reduces to VW/2 - W/2 at any viewport width, so it centres in the true viewport with a 1.5rem gutter until the 123.75rem cap engages.
  • The blind-spot fix in TestEveryEdgeReachesThePage is real: counting on the class prefix now matches both archedge and archedge archedge-skip, and those are the only two class strings the renderer emits for a path.

Firing is nil-safe in the template, and Arch is always non-nil from its one caller.

What a human still has to look at, since the author was right that a test cannot cover the CSS and I cannot open the page either:

  1. Whether 100vw double-counts a visible (non-overlay) scrollbar on your browsers. The 3rem gutter budget absorbs a typical 15–17px bar comfortably, but this is the one thing no static analysis settles.
  2. Real glyph widths against the assumed 0.58 ratio — does 22 characters genuinely not clip carlos-flagship-ie in the actual font stack.
  3. The alarm marks inside the rounded corner, and the new error banner, in both light and dark themes.
  4. Narrow-viewport behaviour of the scrolling .archwrap and the new caption spacing.

Your two open questions are untouched and still open: whether the flagship's estate half is actually populated (opening the page answers it — a named account in the header means granted), and tito having no grant, which per §8 is the designed state but a decision nobody made deliberately. Both are answered by the same browser visit as the four above, which is an argument for doing that visit soon rather than for holding the branch.