From f5cc6cdd50a7ff4ebc7c1bcf0bd1cd4989e4e522 Mon Sep 17 00:00:00 2001 From: halaprix <6533433+halaprix@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:18:52 +0200 Subject: [PATCH] fix(web): stop trace stack/memory/calldata words bleeding across columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .ss-trace h3, .ss-trace ol, .ss-trace li and .ss-trace li code were descendant selectors targeting an ancestor class, `.ss-trace`, that no element in the app actually carries — the v1.1 cockpit redesign moved the Trace tab's wrapper to `.ss-probe-trace`/`.ss-probe-body`, and this block was never updated to match. So the rules that clip each stack/memory word to one line (overflow: hidden; text-overflow: ellipsis; white-space: nowrap) never applied; a 64-char hex word rendered at browser defaults (display: inline; white-space: normal; overflow: visible) and spilled across the Stack/Memory/Calldata grid columns. Retargeted the four selectors to `.ss-trace-panes`, the class that actually wraps these lists in MachineStatePanes.tsx, and removed the now-fully-orphaned base `.ss-trace { border; padding; margin-top }` rule alongside it — it matched zero elements for the same reason. Verified against the real dev build: before the fix, a stack word's computed style was `display: inline; overflow: visible; white-space: normal` and it wasn't confined to its pane's width; after, it's `display: block; overflow: hidden; white-space: nowrap` and stays inside its column. Added a geometry assertion to the existing X5 trace test so a word's right edge can never exceed its own pane again. Co-Authored-By: Claude Opus 5 (1M context) --- apps/web/e2e/trace.spec.ts | 8 ++++++++ apps/web/src/app/app.css | 15 ++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/web/e2e/trace.spec.ts b/apps/web/e2e/trace.spec.ts index 97a7e85..fd177e3 100644 --- a/apps/web/e2e/trace.spec.ts +++ b/apps/web/e2e/trace.spec.ts @@ -42,6 +42,14 @@ test('the trace pane shows machine state at the cursor (X5)', async ({ page }) = await expect(facts).toContainText('#6'); const stackHeading = await page.locator('[data-testid="trace-stack"] h3').textContent(); expect(stackHeading).toMatch(/Stack \([1-9]\d*\)/); + + // Regression: a full 32-byte word must stay inside its own pane, never + // bleeding into Memory or Calldata beside it (missing `.ss-trace-panes` + // selector scoping once let long hex words render unclipped). + const stackPane = page.locator('[data-testid="trace-stack"]'); + const paneRight = (await stackPane.boundingBox())!.x + (await stackPane.boundingBox())!.width; + const wordBox = await stackPane.locator('li code').first().boundingBox(); + expect(wordBox!.x + wordBox!.width).toBeLessThanOrEqual(paneRight + 1); }); test('step modes navigate the timeline by keyboard (X6)', async ({ page }) => { diff --git a/apps/web/src/app/app.css b/apps/web/src/app/app.css index d9fda61..f6bc893 100644 --- a/apps/web/src/app/app.css +++ b/apps/web/src/app/app.css @@ -1463,13 +1463,6 @@ input[readonly] { } /* ===== Trace inspector ===== */ -.ss-trace { - border: var(--ss-border); - border-radius: var(--ss-radius); - padding: var(--ss-space-2); - margin-top: var(--ss-space-2); -} - .ss-trace-scrub { display: flex; align-items: center; @@ -1490,7 +1483,7 @@ input[readonly] { margin-top: var(--ss-space-2); } -.ss-trace h3 { +.ss-trace-panes h3 { font-family: var(--ss-font-ui); font-size: 0.72rem; letter-spacing: var(--ss-tracking-label); @@ -1499,7 +1492,7 @@ input[readonly] { margin: var(--ss-space-2) 0 var(--ss-space-1); } -.ss-trace ol { +.ss-trace-panes ol { list-style: none; margin: 0; padding: 0; @@ -1510,14 +1503,14 @@ input[readonly] { border: var(--ss-border); } -.ss-trace li { +.ss-trace-panes li { display: flex; gap: var(--ss-space-2); padding: 1px var(--ss-space-1); overflow: hidden; } -.ss-trace li code { +.ss-trace-panes li code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;