Review: the rail shows every intent, the code column keeps a floor, and both ends of the bar stay legible - #12
Merged
Merged
Conversation
A card was ~1100px tall in an 851px rail, so the first one filled it and the other six sat below the viewport. The rail's own header read 0/7 over a single card, and pressing ] moved the diff to intent 2 while the rail kept intent 1 highlighted -- a 26-file branch looked like it had one intent, at every window width. A Button sizes its graphic by asking prefHeight(-1), and a wrapping Label answers that with the height it needs at its MINIMUM width: one word per line. The graphic now answers at the width it is actually given, and that width is bound to the cards column -- whose width the ScrollPane hands down -- rather than to the button, which is the cycle that made the question unanswerable in the first place. The two setWrapText(true) calls that turned a latent binding into an unbounded height came from the commit that made the rail categorised, so this is that commit's regression. It reached a screenshot rather than a test because the existing tests assert on the row model, and the row model was always right. Measured in the running app before and after: h=[1132 877 1135 802 1045 865 841] -> h=[67 67 67 67 79 67 67], 6722px of content -> 506px. The mark verb now prints those numbers, which is what made it legible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each rail decided its own collapse from its own width threshold, and the code column -- the only thing anyone opens Review to read -- had no claim on space at all. Measured through the diag harness at seven view widths, four of them put it under the 560px the spec gives it: 526 at 1330, 522 at 1210, 493 at 1181, 524 at 1050. It was not even monotonic: widening from 1150 to 1210 took the column from 624px to 522px, because the queue rail came back at full width on the way up. RailLayout replaces the four thresholds with one rule. Rails narrow first, then give up their width margin-first and queue-last, until the code column clears its floor. Narrowing before collapsing is what makes the result monotonic in the number of rails: there is no width at which widening the window loses you one. Pure arithmetic in its own class, so the rule is testable without a scene, and the eleven widths that were measured wrong are a test. Verified in the app afterwards at the same widths -- solve(1210) predicts 778px and the app rendered 778px. The code column's own width is deliberately not monotonic: at 1270 the margin re-opens and takes its 286px back, which is the rails returning in the reverse of the order they went. The floor is what holds across it. Implements Task 10 of docs/superpowers/plans/2026-08-03-review-ui- correctness-and-orientation.md, the one part of that plan never built. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
With every rail collapsed the bar is the only surface left, and a review is read, settled and advanced entirely from it -- so it has to work at 560px, the width the column is now guaranteed. It did not: the three actions want 327px of a 532px budget, HBox shrank every label equally, and they rendered as "Approv...", "Request c..." and "Ask the agent ...". A button whose own label is elided is not a standing action. What gives way is decided rather than proportional. The actions keep their width. The title yields, with a tooltip carrying what the ellipsis takes -- it is context, and the actions are the point. The hint goes first of all: "3 left" already appears in the progress line and on the Submit button, and the key it names lives in the shortcuts overlay, so at the floor it is the only thing on the bar that costs nothing. Two things the implementation turns on. The decision runs in layoutChildren, not a width listener: the first width the row is handed arrives before CSS, so every preferred width read there is a bare unstyled label's and the row looks roomy. And it is computed from the row's width counting the hint's own slot whether or not the hint is showing -- deciding from the laid-out result oscillates, because hiding the hint frees exactly the width that says to show it. The test pins the stage at the floor in start() and restores it after each case. TestFX reuses the stage across classes, so a scene built at 560 came up at whatever the previous class left it at, and the truncation assertions passed without measuring anything. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Nothing to review" stated a conclusion without its scope, which is indistinguishable from Review being pointed at the wrong repositories -- the exact failure this destination has already had once, when a rail showed another scope's files. The empty surface now carries a third line: "Scanned drydock and btrace", naming up to three and counting the rest, present tense while a scan is in flight, and absent entirely when there is nothing to name. That needed the names, so the view takes them instead of a bare count: setItems(assembly, List<String>) and showScanning(List<String>). The count is names.size() rather than a second parameter that can disagree with the first. The scanning state is raised before there is any assembly, so the view holds them rather than reading them off one. The line gets its own quiet style. The mono slot it would otherwise have borrowed is a code chip, and it belongs to the checkout gate's commands -- things the reader is meant to run, which this is not. Completes P3's "what was scanned, and that it found nothing" from docs/superpowers/specs/2026-08-03-review-ui-correctness-and-orientation- design.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.
Four fixes, found by running a comprehensive visual pass over Review against
docs/superpowers/specs/2026-08-03-review-ui-correctness-and-orientation-design.md— the real app driven through the
shot:diag harness at eleven windowwidths, against a six-item queue and a clean repository.
The intent rail drew one card of seven
Cards were ~1100px tall in an 851px rail, so the first filled it and the
rest sat below the viewport: a 26-file branch looked like it had a single
intent, and
]moved the diff while the rail kept card 1 highlighted. AButtonsizes its graphic by askingprefHeight(-1), which a wrappingLabelanswers with its height at minimum width — one word per line.A regression from #11, which added the two
setWrapText(true)calls thatturned a latent binding into an unbounded height. It reached a screenshot
rather than a test because the existing tests assert on the row model, and
the row model was always right.
The code column had no claim on space (plan Task 10)
Each rail collapsed on its own width threshold. Measured at seven view
widths, four put the code column under the 560px the spec gives it — 526,
522, 493, 524 — and it was not monotonic: widening 1150 → 1210 took it from
624px to 522px as the queue rail came back.
RailLayoutreplaces the four thresholds with one rule: rails narrow, thengive up their width margin-first and queue-last, until the code column
clears its floor. Pure arithmetic in its own class.
solve(1210)predicts778px; the app then rendered 778px.
This is Task 10 of the 2026-08-03 plan, the one part never built.
The verdict bar truncated its own actions
At the floor the three actions want 327px of a 532px budget, so
HBoxelided every label: "Approv…", "Request c…", "Ask the agent …". With every
rail collapsed the bar is the only surface left, so what yields is now
decided — actions keep their width, the title yields with a tooltip, and
the redundant hint goes first.
An empty Review didn't say what it looked at
"Nothing to review" without its scope is indistinguishable from Review being
pointed at the wrong repositories. It now carries "Scanned drydock and
btrace", naming up to three and counting the rest. Completes P3's "what was
scanned, and that it found nothing".
1186 tests, zero failures. Each commit compiles standalone. Cherry-picked
onto
mainrather than pushed tofix/more_reviews, whose three commits arealready in
mainas the #11 squash.🤖 Generated with Claude Code