From 91d90d48fb571b015526653a4a01f917bb5b7de4 Mon Sep 17 00:00:00 2001 From: Kpa-clawbot Date: Mon, 25 May 2026 14:56:43 -0700 Subject: [PATCH] =?UTF-8?q?fix(#1364):=20drop=20over-aggressive=20.mc-pill?= =?UTF-8?q?=20max-width=20=E2=80=94=20restore=20multi-digit=20count=20visi?= =?UTF-8?q?bility=20(#1365)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Red commit: 482ffe69e668c65413d6fb00d0c5b41436534df1 (CI: pending) ## What Drops `max-width: 4ch` from `.mc-cluster .mc-pill` in `public/style.css`. Keeps `overflow: hidden` + `text-overflow: ellipsis` as belt-only graceful degradation. ## Why #1362 added `max-width: 4ch` as defense-in-depth for the `999+` JS cap. But `4ch` is applied to the BOX including the `1px 3px` padding, so effective text width is ~2.5ch — enough for `R6` but not `R60`. Result: post-merge regression on staging where multi-digit cluster pills render `R…` instead of `R60`/`C30`. The JS cap in `public/map.js` already clamps counts to `999+` (max 5 chars: `R999+`). That's the load-bearing safety. The CSS `max-width` was overcaution and went too aggressive. Option A from the issue: drop the cap entirely, keep ellipsis as graceful-degrade if JS ever fails. ## TDD red→green - RED: `test-issue-1364-pill-no-clamp.js` asserts `.mc-pill` CSS does NOT contain `max-width: 4ch` (regression guard) and DOES contain `overflow: hidden` + `text-overflow: ellipsis` (graceful degradation). Fails on the unchanged CSS. - GREEN: deletes the `max-width: 4ch;` line from `.mc-pill`. Test passes. Wired into `.github/workflows/deploy.yml` alongside the #1360 test. ## Visual verification Open `/map` zoomed-out on staging. Cluster pills must render full counts (`R60`, `C30`, `R250`, capped `R999+`) — no `R…` ellipsis. No horizontal scrollbar even on synthetic 4-digit injection. Fixes #1364 --------- Co-authored-by: openclaw-bot --- .github/workflows/deploy.yml | 1 + public/style.css | 11 +++--- test-issue-1360-pill-letter-count.js | 4 +-- test-issue-1364-pill-no-clamp.js | 53 ++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 test-issue-1364-pill-no-clamp.js diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 841f8d2d..4a5dec44 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -108,6 +108,7 @@ jobs: node test-issue-1293-marker-shapes.js node test-issue-1356-map-a11y.js node test-issue-1360-pill-letter-count.js + node test-issue-1364-pill-no-clamp.js - name: Verify proto syntax run: | diff --git a/public/style.css b/public/style.css index aa3d073c..c5e34429 100644 --- a/public/style.css +++ b/public/style.css @@ -3387,10 +3387,13 @@ th.sort-active { color: var(--accent, #60a5fa); } .mc-cluster .mc-pill { display: inline-block; min-width: 12px; padding: 1px 3px; border-radius: 3px; - /* #1360 follow-up: defense-in-depth cap for pathological 4+ digit counts. - JS caps the rendered text at "999+" (max 4 chars); this bounds visual - width if a stray render slips through. */ - max-width: 4ch; overflow: hidden; text-overflow: ellipsis; + /* #1364: removed the prior `max-width` cap — it clamped the BOX + (including the 1px 3px padding) to ~2.5ch of text, ellipsizing `R60` + to `R…`. JS in map.js already caps counts at "999+" (max 5 chars: + `R999+`), which is the load-bearing safety. `overflow:hidden` + + `text-overflow:ellipsis` stay as belt-only graceful-degrade if the + JS cap is ever bypassed. */ + overflow: hidden; text-overflow: ellipsis; /* Audit: bump 9px → 10px, monospace, dark text on every Wong hue. #1a1a1a on all 5 Wong hues passes SC 1.4.3 small-text (≥4.5:1). Sized in rem (0.625rem = 10px @ default 16px root) so user diff --git a/test-issue-1360-pill-letter-count.js b/test-issue-1360-pill-letter-count.js index 5cc229f7..a6e4c5e9 100644 --- a/test-issue-1360-pill-letter-count.js +++ b/test-issue-1360-pill-letter-count.js @@ -80,8 +80,8 @@ const pillMatch = cssSrc.match(pillRuleRe); assert(pillMatch, '.mc-cluster .mc-pill rule found in style.css'); if (pillMatch) { const body = pillMatch[1]; - assert(/max-width\s*:/.test(body), - '.mc-pill declares max-width (bounds pill width for overflow)'); + // #1364: dropped `max-width` — it over-clamped multi-digit counts. + // Graceful-degrade ellipsis assertion stays. assert(/text-overflow\s*:\s*ellipsis/.test(body), '.mc-pill declares text-overflow: ellipsis (graceful clip)'); } diff --git a/test-issue-1364-pill-no-clamp.js b/test-issue-1364-pill-no-clamp.js new file mode 100644 index 00000000..634b1512 --- /dev/null +++ b/test-issue-1364-pill-no-clamp.js @@ -0,0 +1,53 @@ +/** + * #1364 — regression(map): #1362 pill max-width:4ch over-clamps multi-digit + * counts → `R…` instead of `R60`. + * + * The defense-in-depth `max-width: 4ch` added in #1362 ellipsizes pill + * content because the 4ch box includes left/right padding (1px 3px), + * leaving ~2.5ch for text — enough for `R6` but not `R60`. + * + * Fix (Option A from issue): drop `max-width` entirely. JS already caps + * at "999+" so CSS guard was overcaution. Keep `overflow:hidden` + + * `text-overflow:ellipsis` as graceful-degrade if JS ever fails. + */ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +let passed = 0, failed = 0; +function assert(cond, msg) { + if (cond) { passed++; console.log(' ✓ ' + msg); } + else { failed++; console.error(' ✗ ' + msg); } +} + +const cssSrc = fs.readFileSync(path.join(__dirname, 'public', 'style.css'), 'utf8'); +const pillRuleRe = /\.mc-cluster\s+\.mc-pill\s*\{([\s\S]*?)\}/; +const pillMatch = cssSrc.match(pillRuleRe); + +console.log('\n=== #1364: .mc-pill no longer clamps multi-digit counts ==='); + +assert(pillMatch, '.mc-cluster .mc-pill rule found in style.css'); + +if (pillMatch) { + const body = pillMatch[1]; + + // Primary regression guard: NO max-width: 4ch (or any max-width that would + // clamp `R999+`). Issue acceptance criterion: "assert .mc-pill CSS does + // NOT contain max-width: 4ch". + assert(!/max-width\s*:\s*4ch/.test(body), + '.mc-pill does NOT declare `max-width: 4ch` (regression guard for #1364)'); + + // Graceful degradation: keep belt-only overflow guards in case JS cap + // is bypassed by a hypothetical regression. + assert(/overflow\s*:\s*hidden/.test(body), + '.mc-pill keeps `overflow: hidden` as graceful-degrade'); + assert(/text-overflow\s*:\s*ellipsis/.test(body), + '.mc-pill keeps `text-overflow: ellipsis` as graceful-degrade'); +} + +console.log('\n=== Summary ==='); +console.log(' Passed: ' + passed); +console.log(' Failed: ' + failed); +console.log('\n#1364 ' + (failed === 0 ? 'PASS' : 'FAIL')); +process.exit(failed === 0 ? 0 : 1);