Launching the app from the working copy left .cowork_history/ next to the
source, and one transcript rode along into the previous commit and up to the
remote. It is the user's data, not code. Untracked and ignored, along with
.cowork_local/ for the same reason.
The file stays in the history of e5bd679 — removing it there rewrites the
branch, which is the user's call.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Section 16 of the audit page draws the three actions on the title row, a
magnifier inside the search box, caps section headings, and names its complaint
outright: "Ô icon trong lưới hiện tại không có viền/hover rõ khi rê chuột hay
khi đang chọn" — you could not tell which cell you were about to pick.
So: Thêm / Dán / Xoá move from the strip under both grids (where they read as
belonging to the custom grid alone) up beside the title; the search box gets its
magnifier; the two headings become caps through the same #navSectionHdr style
the rail uses; and #iconGrid cells take an accent border on hover and on
selection, the card language Agent and Công cụ already use.
Wording follows the drawing too: "ICON TÍCH HỢP" rather than "Icon có sẵn", and
"Tìm icon theo tên…" rather than "Tìm icon có sẵn…".
Left alone, and worth a decision: the drawing labels the buttons "+ Thêm icon"
and "Xoá", where the app says "Thêm tệp SVG" and "Xóa tùy chỉnh". The longer
labels say which file type is wanted and that only custom icons can be deleted,
so shortening them to match the drawing would cost more than it gains.
check_icons_screen covers the four points. Its first version passed a mutation
that dropped the buttons from the header layout — unparented they sit at (0,0),
which read as "the same row" — so it now requires the vertical centres to line
up AND each button to start right of the title.
20/20 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Some screens scroll sideways, some don't" had two causes, and both were a
number that was right on one monitor.
The lanes. _KanbanColumn set a 150px floor with a comment claiming seven of
them fit a 1280 window; measured, the row wanted 1242px where 1280 leaves 1091,
so a 1280 screen scrolled and a 1920 one did not — this machine has one of each.
The floor is gone. The seven lanes share the board through the layout's
stretch, which is a proportion of whatever width there is, and the only pixel
question left — how narrow before scrolling beats squeezing — is answered from
the font: eight characters of a title plus padding, so it holds at 125%/150%
scaling too. No horizontal scroll now at 1280×720 through 1936×1048, at three
rail widths each, including the rail dragged to its maximum.
Each lane also grew its own scrollbar: QListWidget's column hint runs 1-6px past
its viewport, and which lanes overflowed changed with the window width — 36 of
38 widths had at least one. Cards word-wrap, so there was never anything to
reach sideways; the bar is off.
The rail. Its 360px ceiling was a quarter of a 1440 screen and more than that of
a 1280 one. It is now 22% of the window, capped at 360 — and recomputed on
resize, which is its own bug fixed: read once at construction off a not-yet-sized
window, it sat at 162px on every monitor, so the handle barely moved.
check_kanban_scroll covers five screen sizes × three rail widths. A rail dragged
to maximum on a 1280 screen still scrolls the board — that is the user's own
trade, so it is reported rather than failed.
19/19 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A1 — hiding the assistant from the dot. The old build kept a chevron button
beside the dot wired to _hide_to_edge; the redesign moved that action into the
panel's ⋯ menu, so hiding went from one click to open-panel → ⋯ → Ẩn. The
drawing has no button there (26px, no text, no chevron), so the reach comes
back as a right-click on the dot, with the tooltip saying so.
A2 — per-part cost. Folding Input/Output/Cache into the total tile's sub-line
carried their token counts but not their prices, which live only on those three
cards, so the cost breakdown left the screen entirely. The wireframe asks for
the tiles anyway — "$0.31 Tổng chi phí · 57 lượt / 395.4K Tổng token / 292.8K
Input / 102.7K Output / 108.9K Cache" — so they are back as tiles, each with its
price, and the turn count rides on the cost tile's label as drawn.
The dot on Cowork. _update_dock_guard lifted it whenever a composer existed,
testing only the vertical axis. On a wide window the composer ends at the chat
column's right edge — x=1688 against a dot at x=1892 — so the dot rose 156px to
clear something that was never under it, and Cowork became the one screen where
it was not in the corner. It now lifts only when the two actually overlap:
18px from the bottom at 1936px wide, still lifted at 1200 and 900 where the
composer does reach under it.
Also: open_tooltip and show_tooltip still said "App Assistant" after the rename.
check_dock_corner covers the corner rule at three widths and fails if the lift
comes back unconditionally.
18/18 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Showing Cowork and GraphRAG always, greyed, instead of letting them appear and
vanish, moved the gate from "the row is absent" to "the row is disabled". That
guards the rail — Qt will not select a disabled row — but it guards only the
rail, and _goto is also reached from a RECENTS click and from startup restore.
Called with a gated sub-tab it opened the page while the workspace's own tab
strip still had it hidden.
_goto now asks WorkspaceTab.subtab_available() — the same isTabVisible state
that greys the row — and shows "Chọn project trước" in the status bar instead
of navigating. One gate, one place, whatever triggered the jump.
check_project_gate runs against an EMPTY home, because with any project on disk
the gate is open and the test proves nothing. It asserts the gated rows are
disabled and say why, that clicking them does nothing, that _goto refuses them,
and that + new chat and the project picker are off. Dropping the _goto guard
fails it with "_goto mo duoc 'Cowork' trong khi cong dang dong".
17/17 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rail was setFixedWidth, so the handle QSplitter draws between it and the
content was inert — it looked draggable and did nothing when dragged.
The expanded rail is now a range (132–360px) instead of one number, so the
handle has something to give. Collapsing still pins it at 54px exactly, and a
width dragged to is remembered across the fold rather than snapping back to the
150px default. Long project names and RECENTS threads are what a wider rail
buys.
check_rail_resize drives the splitter the way the handle does and asserts the
rail follows, clamps at both ends, folds to 54px and comes back to the chosen
width. Restoring setFixedWidth fails it — the first attempt at that mutation
passed, because setMaximumWidth on the next line quietly undid it.
16/16 checkers pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>