The picker was hidden outright at 54px, on the grounds that a combo box there
could only show a stub of a name. True, but it left the collapsed rail with no
way to change project at all — and the audit page's own inventory of the 11
collapsible controls says the rail's fold "giữ nguyên toàn bộ".
A folder QToolButton stands in for it: same items, and choosing one moves the
combo, so _on_rail_project_pick stays the single code path. Its tooltip carries
the current project name, which the combo could not have shown anyway. It
matches the + button's width and drops its menu arrow — at 42px the arrow
would take a third of the row to say nothing.
check_nav now collapses the rail and requires a reachable picker whose menu
matches the combo item for item, then picks a row and asserts the project
actually changed. Hiding the button fails it.
15/15 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The scroll body holds [nav, RECENTS header, RECENTS], and RECENTS carries the
only stretch factor. Collapsing hides it, which leaves a fixed-height nav tree
(app.py sets one per row count) and nothing that can expand — so the box layout
centred what was left and the destinations dropped 297px down a 1048px window,
with the same gap opening below them.
A stretch spacer at the foot of the body takes the slack instead. It takes none
of it while RECENTS is visible, because RECENTS carries stretch 1 against its 0,
so the open rail is byte-for-byte what it was.
This is what "thu gọn menu lại ra giữa" meant, reported three times. I read it
as horizontal each time and measured x — which was 4px and correct throughout.
The report was about the vertical axis and I never checked it.
check_rail_align now measures the gap between the + button and the first
destination in both states: 6px/6px now, 6px/223px with the spacer removed.
15/15 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
QStyledItemDelegate hands the style decorationAlignment = AlignHCenter |
AlignVCenter. For a row with a label that is invisible — the icon sits left of
the text either way — but every rail row loses its label when the rail
collapses to 54px, and a centred decoration then lands wherever the column
happens to leave room. _NavItemDelegate overrides it to AlignLeft, so the icon
is on the row's left padding regardless of column width, style or platform.
Honest limit: this was reported from the running app and I could not reproduce
it offscreen — sweeping the column width leaves the icon at a fixed x with or
without the delegate. What is verifiable is the instruction, and centring is
the only mechanism by which Qt can put a label-less row's icon anywhere but
the left. check_rail_align now asserts the flag itself, which fails (132) the
moment the delegate is removed, alongside the column sweep.
Settings follows the rows to their new inset (padding-left 7px → 4px). Its
label still sat 3px left of Dashboard's because a button leaves less air
between icon and label than a tree row does; a 19px icon box closes that to
1px, with the 16px glyph left-aligned inside it.
15/15 checkers pass, no flakes this run.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Settings sat 7px further in than the Dashboard/Giám sát rows above it — its
QSS gave it a 6px side margin where those rows start at the rail edge. At the
collapsed 54px width that put its icon near the middle of the rail, which is
what "thu gọn menu lại ra giữa" was describing. Icon and label now start on
the same x as the rows, open and collapsed, in both themes.
The help panel's transcript is rendered HTML, so switching language re-labelled
the chrome but left the greeting — and the "AI Assistant" speaker label — in
whatever language the panel was built in. retranslate() now rewrites the
greeting (matched by identity, so a real reply is never touched) and re-renders.
The sparkle is #FDBE59, sampled from the audit page's own render. Its CSS says
.spark{color:#0F9B8A}, but the glyph is the ✨ emoji and a colour emoji ignores
CSS colour, so the page has always drawn a gold star.
Behind all three: MainWindow does not style itself — run() calls
app.setStyleSheet — so 12 of 13 checkers were measuring a window with no
padding, margins or borders. Every QSS-driven layout bug was invisible to them,
and an unstyled window reported an icon drift that does not exist. Added
_apply_theme() and wired it through.
Two checker repairs that followed:
· check_no_hscroll flagged the 9pt dialogs on sizeHintForColumn(0), which
returns 182px at 9pt, 11pt and 14pt alike. Nothing was clipped. It now
compares the painted text against the width actually on screen, and fails
on a squeezed list (24 combos) where the old test passed.
· the checkers print Vietnamese and died mid-report on a cp932 console.
New: check_rail_align (icons hold one line, both themes, both states) and
check_help_i18n (transcript follows the language). Both verified to fail
without their fix.
15/15 checkers pass. check_nav and check_design_parity segfault in Qt teardown
roughly one run in three — pre-existing, after the verdict prints, and it
happens with or without the theme change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>