Skip to content

Give four- and five-column stat grids a phone breakpoint, and guard the rule tree-wide - #5822

Merged
atomantic merged 3 commits into
mainfrom
claim/issue-5679
Sep 2, 2026
Merged

Give four- and five-column stat grids a phone breakpoint, and guard the rule tree-wide#5822
atomantic merged 3 commits into
mainfrom
claim/issue-5679

Conversation

@atomantic

@atomantic atomantic commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Eight Tailwind grids hard-coded four or five columns with no breakpoint prefix, so at a 360px viewport each cell got ~65px of outer width and its label wrapped to four or five lines. AgentList's stat bar was the worst case — it is the first thing on the Agents page, so the entire above-the-fold region was unreadable.

  • Each grid now gets a narrow phone default and opts into the wide layout at a breakpoint: AgentList (also p-6p-4 md:p-6), DailyTrendsChart, SyncDetailDrawer, LearningTab's feedback summary, the Chief of Staff ASCII-mode stat bar, and IconPicker.

  • The two Big Five readouts (ImportTab, InterviewAnalysisCard) stay five-across — they are a fixed five-trait bar chart whose cells hold one bar plus a five-character label — but shrink the gap and the label below sm.

  • New tree-wide guard client/src/responsiveGridConventions.test.js: a className carrying a bare grid-cols-N for N >= 4 must also carry a prefixed …:grid-cols-*, so the column count is conditional on width rather than frozen. It scans git-tracked non-test sources with comments masked, and holds a documented allowlist (the seven-day month grid, the two Big Five grids) plus a staleness check that fails if an exempt file stops having the grid it was exempted for.

  • client/src/AGENTS.md records the rule under "Mobile responsive", including the two traps found while writing it: a widened gap is not a column breakpoint, and a thumbnail/heatmap grid may stay four-plus wide on a phone but still needs a breakpoint so the desktop isn't stuck at the phone count.

  • A tree-scanning guard is unreachable through CI's import-graph selection, so it joins the structuralTestsFor branch in scripts/ci-test-plan.js that already fires on any client/src .js/.jsx change, and is registered in scripts/repo-scan-guards.test.js with that selector named.

Why a tree-wide guard instead of the two per-component assertions the issue proposed

Neither AgentList.test.jsx nor DailyTrendsChart.test.jsx exists, so the proposed tests would have meant standing up two heavily-mocked render suites to assert one className each. The scan test strictly dominates them: it catches a revert in either file and every new offender anywhere in the tree, which is what the issue's acceptance criterion actually asks for. It carries its own bypass probe so a green run can't come from a detector that silently stopped matching.

Test plan

  • cd client && npx vitest run src/responsiveGridConventions.test.js — 4 passing, including the probe asserting the detector flags a frozen grid-cols-4, is not fooled by gap-4 sm:gap-6, takes the widest bare token rather than the first, and ignores a class string quoted inside a comment.
  • cd client && npx vitest run src/a11yConventions.test.js src/pages/ChiefOfStaff.test.jsx src/components/sync src/components/cos src/components/digital-twin — 54 files / 696 tests passing.
  • cd server && npx vitest run ../scripts/agent-instructions-files.test.js lib/agentInstructionsFile.test.js ../scripts/repo-scan-guards.test.js ../scripts/ci-test-plan.test.js — the AGENTS.md hygiene and CI-selection guards, passing.
  • cd client && npm run lint — clean.
  • Verified against the Tailwind v4 setup in client/src/index.css: no custom --breakpoint-* is declared, so only sm/md/lg/xl/2xl are used (this repo has no xs), and text-[10px] is already in ~314 files.

Closes #5679

Eight grids hard-coded four to five columns with no breakpoint prefix, so
at 360px each card got ~65px of outer width and its label wrapped to four
or five lines. AgentList's stat bar was the worst case: it is the first
thing on the Agents page, so the entire above-the-fold region was
unreadable.

Each grid now gets a narrow phone default and opts into the wide layout at
a breakpoint. The two Big Five readouts stay five-across — they are a fixed
five-trait bar chart whose cells are one bar plus a five-character label —
but shrink the gap and the label below `sm`.

`responsiveGridConventions.test.js` enforces the rule tree-wide rather than
per component: a className carrying a bare `grid-cols-N` for N >= 4 must
also carry a prefixed `...:grid-cols-*`. The allowlist holds the month
grid (inherently seven days) and the two Big Five grids, and a companion
assertion fails if an allowlisted file stops having the grid it was
exempted for.
…nes (#5679)

Local review pass. The guard's bare-column regex had no global flag, so a
class string holding more than one unprefixed grid-cols was judged by its
first token instead of its widest. The icon picker's phone default drops
from four columns to three so the truncated icon name under each 20px tile
has room, and the convention note now says what the guard actually
enforces: a column breakpoint somewhere in the string, not a mobile
default of three or fewer (thumbnail and heatmap grids are legitimately
wider than that on a phone).
…#5679)

A tree-scanning guard is unreachable through CI's import-graph selection —
nothing imports the file that would violate it. The responsive-grid guard
can only newly fail when a client/src .js/.jsx file changes, the same
trigger the mounted-ref guard already rides, so it joins that
structuralTestsFor branch rather than the always-run list.
@atomantic
atomantic merged commit de5c459 into main Sep 2, 2026
7 checks passed
@atomantic
atomantic deleted the claim/issue-5679 branch September 2, 2026 06:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fixed four- and five-column stat grids have no breakpoint and collapse to ~65px cards on a phone

1 participant