-
Notifications
You must be signed in to change notification settings - Fork 0
Review 5547
Review #5547 — Toast shadow clipping
freddymeta · collaborator · OPEN · view on GitHub
#5547 — fix(Toast): the card's shadow is no longer clipped away
b962d810bdebad86f382853ced4bb2db7a820e08
LOOP VERSION: 1.4.1 AUDIT RUBRIC: 1.12
Gate 1 read 1.4.1 from the Mac source of truth. The task named 1.4.0, but 1.4.1 had become current before this review began; the patch only makes the same loop self-contained and does not change judgement.
LANE: full WHY: this intentionally changes pixels and the clipping primitive, so browser paint, exit clipping, pointer hit testing, stacking, and scroll-container semantics all require direct evidence.
Clear. The head is in facebook/astryx, freddymeta has write permission, and the exact two changed paths are one component source file plus one changeset. No dependency, lockfile, workflow, install hook, executable script, credential, environment, or build-network path changed.
The Toast card already declares its elevation shadow, but the inner grid-collapse wrapper clips exactly at the card border box. A person therefore sees a flat Toast, and a theme-authored shadow cannot paint outside the card.
The exact parent reproduced the defect: all 15 sampled pixel rows below the card were 255,255,255 even though the computed box-shadow was present.
VERDICT: clear
The inner grid item remains the collapse clip, but changes from overflow: hidden to overflow: clip and extends its clip edge by 32px. Because clip does not zero a grid item's automatic minimum size, min-height: 0 keeps the row able to collapse. The chosen primitive restores the shadow in Chromium, but it also depends on engine support and extends descendant hit testing during exit.
SOLUTION (2 decisions · 3 declarations in 16 added runtime lines of 42 changed lines)
- Change the clip primitive and extend its edge by 32px so the existing Toast shadow can paint.
- Explicitly zero the grid item's minimum block size so the exit row still reaches zero.
VERDICT: BLOCKS — the selected primitive does not restore the shadow in WebKit and broadens Chromium's exit hit boundary.
OWNER: ToastViewport owns the stack, the collapse row, and its clipping boundary; Toast remains the painted and themed surface.
TIER 1: browser-native grid transitions, overflow: clip, and overflow-clip-margin.
TIER 2: none.
SEAMS: top-layer popover viewport, nested dialog viewport, stacked sibling order, endContent actions, all four positions.
BEHAVIOR UNIT: inline CSS declarations — the behavior is a browser layout/paint contract, so the focused boundary probes are the testable unit.
| seam | driven result |
|---|---|
| top-layer portal | exact head remained :popover-open; the outer viewport stayed overflow: visible and the Toast remained at the same 400×52 geometry |
| stack paint/order | a middle Toast overlapped the later sibling during collapse, but the later sibling's dismiss target still won hit testing in both parent and head |
| action during exit | Chromium exact head kept an out-of-clip Undo action hit-testable and a real pointer click fired it; exact parent did not |
| scroll-container semantics |
hidden → clip removes the inner scroll container; this private grid item has no scroll API, sticky descendant, or scroll-linked behavior, so no reachable scroll regression was found |
| candidate boundary | resetting only the exit-state clip margin to 0 restored the old action hit boundary while leaving the resting shadow frame pixel-identical |
The owner remains correct and no portal/z-index owner moves. The cross-engine and pointer behavior of the chosen clip primitive is not safe yet.
VERDICT: BLOCKS — the clipping boundary changes beyond shadow paint.
In Chromium, every stock and themed Toast gets the intended elevation; the exact-head centerline changes from white to a 14px shadow falloff. In WebKit 26.5, overflow-clip-margin is unsupported and every sampled row remains white, so WebKit 26.5 users keep the original defect.
During Chromium dismissal, content admitted by the 32px clip margin remains hit-testable outside the collapsed row. A Toast action can therefore fire after dismissal has begun while the surface is mostly transparent.
Two open Toast layout PRs — #5353 and #5541 — also touch this wrapper. They will need to rebase around whichever cross-browser clipping shape lands, but they do not prevent this author from correcting the exact head.
VERDICT: BLOCKS — WebKit 26.5 users do not receive the fix, and Chromium users gain an unintended exit action window.
No public prop, type, export, default, callback, role, DOM attribute, or call shape changes.
| change | public? | class | doc'd? | verdict | |
|---|---|---|---|---|---|
| — | no API change | — | — | — | clear |
OSSIFICATION: the 32px clip allowance is private layout implementation, not a new theme target or public promise. Its engine dependence still has to be corrected before landing.
VERDICT: clear
No theme target, token, variable, selector, or state reflection changes. The existing astryx-toast target remains on the element that paints the shadow, and --shadow-med remains the source of the default value. The 32px clip allowance is component-owned clipping, not theme surface.
The intended result reaches existing shadows only in engines that implement overflow-clip-margin; WebKit leaves the same theme paint clipped.
VERDICT: BLOCKS — existing theme shadow output remains unreachable in WebKit.
BEHAVIOR: yes — Chromium pointer hit testing expands outside the collapsing inner box; an exiting Undo action can now fire where the parent rejected the same click.
API: no — signatures and semantics exposed to TypeScript are unchanged.
VISUAL: yes — the resting shadow is intentionally restored in Chromium; the card also paints farther outside the shrinking row during exit. WebKit remains visually unchanged and therefore unfixed.
THEME: no surface break — no target/token changes, but existing shadow overrides remain clipped on WebKit.
VERDICT: BLOCKS — the behavior delta is unintended and the stated visual goal is engine-incomplete.
EFFECTS: zero added or moved. RENDER: no React render-path change. LISTENERS/OBSERVERS: zero added. LAYOUT: no JavaScript reads/writes or forced reflow; CSS paint may extend up to 32px around at most five visible Toasts. BUNDLE: no dependency and only three runtime CSS declarations in the reviewed source change.
No performance or resource regression was found. The paint-area cost was not separately timed because there is no hot O(N) JavaScript path and wall-clock paint timing would not be an actionable invariant.
VERDICT: clear
VISUAL CHECK: manual frames required WHY: the PR intentionally changes visible shadow pixels, and the exact-head visual job reported no compared Toast change because 16 shots had no baseline.
The decisive pair was opened and inspected. The before image has a hard white edge directly under the card; the after image has a soft gray falloff through row +14, with no card geometry change.
| Sensor | Before | After |
|---|---|---|
| Build | parent 58f95421362527e586c078b9377b1fcab2274910
|
head b962d810bdebad86f382853ced4bb2db7a820e08
|
| Receipt | JSON | JSON |
| Story | core-toast--default |
same |
| Theme / mode / direction | neutral / light / LTR | same |
| Viewport / media | 900×520 @1; forced colors off; reduced motion off; fine pointer; hover | same |
| Semantic state | one 400×52 info Toast; role=status; aria-live=polite; one dismiss control |
same |
| Geometry | x484, y452, 400×52, visible in viewport | same |
| Settled / errors | fonts loaded; 0 animations; no page/Storybook error | same |
| Pair check | all sensors match except Build | same |
| Exact parent — shadow clipped | Exact head — shadow visible |
|---|---|
![]() |
![]() |
Pixel receipt: at the card centerline, row +1 changes 255 → 229, +6 255 → 245, +10 255 → 251, +14 255 → 254, and rows +15/+16 return to white. The exact PR delta is banked as exact-pr.diff.
Cross-engine control: WebKit 26.5 exact head reports CSS.supports(...) = false, no computed clip margin, and 15/15 white rows below the card. The exact parent is identically clipped.
VERDICT: BLOCKS — Chromium proves the intended pixels, while WebKit proves the stated cross-browser outcome is not achieved.
No role, accessible name, live-region policy, focus handoff, string, locale, or logical-direction declaration changes. Exact-head pr-a11y and pr-rtl passed. The new pointer reach is a behavior regression rather than a change to the accessibility tree; it is carried in ARCHITECTURE, IMPACT, and BREAKING instead of double-counted here.
VERDICT: clear
| slot | verdict |
|---|---|
| PROBLEM | clear |
| SOLUTION | BLOCKS — engine support and hit testing |
| ARCHITECTURE | BLOCKS — clipping boundary widens beyond paint |
| IMPACT | BLOCKS — WebKit remains broken; Chromium exit action stays live |
| API | clear |
| THEMING | BLOCKS — shadow remains clipped in WebKit |
| BREAKING | BLOCKS — unintended pointer behavior |
| PERFORMANCE | clear |
| VISUAL | BLOCKS — stated result does not reach WebKit |
| A11Y & I18N | clear |
GOAL: partly met — Chromium restores the 14px shadow falloff with unchanged 400×52 geometry; WebKit 26.5 leaves all sampled rows white.
DISPOSITION: both negative findings block this head. A cross-browser clipping shape must restore the resting shadow, and exiting content must not remain pointer-active outside the collapsing box.
ADVICE: proven bounded direction — an inspected candidate that resets the clip margin only while exiting makes the out-of-box Undo click stop firing and preserves the resting Chromium frame pixel-for-pixel; it does not solve WebKit, so the final mechanism still needs a cross-browser paint path. candidate-exit-clip.diff · candidate action receipt · pixel control.
AUTHOR CAN PROCEED: yes — acceptance is concrete: the stock resting shadow paints in Chromium and WebKit, the collapse reaches zero, and an action outside the shrinking clip cannot receive a real pointer click during exit.
WORST OUTCOME: “WebKit 26.5 users still get no Toast shadow, while Chromium users can activate an almost-gone Toast action after dismissal starts.” → request changes
JUDGEMENT NEEDED: none
request changes
- [BLOCKS] WebKit 26.5 ignores
overflow-clip-margin, so the shadow remains fully clipped. → WebKit 26.5 users receive no visible fix ·packages/core/src/Toast/ToastViewport.tsx:101 - [BLOCKS] Chromium applies the 32px margin to hit testing during exit.
→ a real click can fire an action outside a 2.73px collapse box while the Toast is 23% opaque ·
packages/core/src/Toast/ToastViewport.tsx:101
Independent confirmation: the exact parent rejects the same action click, and the exact candidate exit-only 0px margin rejects it while leaving the resting frame byte-identical.
Thanks — the Chromium shadow and collapse both work.
ToastViewport.tsx:101still needs a cross-engine fix. WebKit 26.5 does not supportoverflow-clip-margin; all 15 sampled rows below the card stayed white, so the shadow remains clipped. In Chromium, the 32px margin also expands hit testing during exit: with the clip box 2.73px tall and the toast 23% opaque, a real click on the out-of-bounds Undo action fired; the parent did not.Could we preserve the old exit hit boundary and make the resting shadow visible in WebKit too?
[Reviewed by Robohands]
Public review length: 90 words (request-changes cap: 150).
None. Both failures come from the same declaration and are clearer together in the summary.
- The head is 20 commits behind current
mainbut GitHub reports it mergeable; age is under one day, so this is not a staleness finding. - #5353 and #5541 overlap the Toast wrapper, but neither makes this exact-head cross-engine/pointer result disappear.
- The 13-line inline comment largely repeats the PR body; omitted as polish because the two behavior defects decide the verdict.
- Focused Vitest:
ToastViewport.test.tsx— 13/13 passed. - Strict ESLint on
ToastViewport.tsx— passed. - Core TypeScript
--noEmit— passed. - Changeset gate — 28 changesets valid; this
[fix]/ patch entry passed. - Exact-head CI: build, test, lint, Storybook, a11y, RTL, theme layers, sandbox, and Vercel green;
review-requiredremains pending as expected. - Chromium manual pair: passing
captureWithSensors()receipts; pair equality checked with only Build differing. - Chromium action probe: parent
hit=false/fired=false; headhit=true/fired=true; candidatehit=false/fired=false. - WebKit 26.5 paint probe:
overflow: clip,overflow-clip-marginunsupported, 0/15 non-white rows on both parent and head. - Full reproducibility bundle: assets/pr-5547.
TIME total 42m setup 6m — exact-head worktree, fresh fork/public wiki clones, fast install, Storybook reading 9m — body/test plan, current kit, audit 1.12, rulings, design/API guidance, source/history/overlapping work measuring 18m — Chromium frames, pointer action A/B, candidate arm, WebKit control, focused checks writing 6m — R16 presentation, public text, evidence receipts waste 3m — corrected one generic readiness selector and one transparent-surface sensor expectation before banking evidence
- Firefox was not run after WebKit independently falsified the cross-engine claim; another passing engine would not change either blocker.
One artifact-only critic pass found four presentation defects and they were corrected: the page title now links the PR, the WebKit result no longer overclaims every Safari build, the unsupported bundle-report claim was removed, and the time ledger now sums. The critic also rechecked both blocks against independent controls, the 90-word cap, the signature, every slot verdict, AUTHOR CAN PROCEED, and the exact-head anchor. No verdict changed.
Nothing was posted to the PR. This run made no GitHub review, comment, merge, auto-merge, or contributor-branch push. Only this fork-wiki review record and its evidence assets will be published.
Head reviewed: 5df116926a18b8f399f8c0caa854756334a5becc
Previously reviewed head: b962d810bdebad86f382853ced4bb2db7a820e08
PR merge-base / head's main parent: 5b5f1903a8eeccde0e404062a44a168e81677279
Verdict: request changes (drafted; no public PR action)
LOOP VERSION: 1.5.0
AUDIT RUBRIC: 1.13
The original Round 1 record remains unchanged above. This is a fresh re-review under the versions current when this gate began.
LANE: full. This round must re-drive two prior cross-engine/interaction blocks, inspect a merged-main conflict resolution, and validate intentional paint plus exit hit testing.
Step 0 passed. The current PR patch is three safe paths: one Toast source file, its test, and a changeset. No dependency, lockfile, workflow, package script, executable tool, credential, environment read, or build-network path changed.
Our Round 1 request at b962d810 asked for two outcomes at ToastViewport.tsx:101: restore the resting shadow in WebKit 26.5, and prevent an out-of-bounds Undo action from firing during Chromium exit. Rubyycheung's design approval said the intended elevation and dismissal motion were correct.
The new head merges #5353 from main and resolves the Toast conflict. Relative to exact base 5b5f1903, the PR is three files, +102/−13:
- keep
overflow: hiddenthrough entry and exit, then switch tovisibleafter the opening grid transition; - track settled Toast ids in viewport state;
- set the exiting wrapper to
pointer-events: none; - add a lifecycle test and rewrite the changeset around the new mechanism.
Current origin/main is three unrelated commits ahead at a7ad8f98; its Toast source and story blobs are byte-identical to the exact PR base, so main has not invalidated this patch.
WHY 1: The collapse wrapper clips at the Toast card's border box, hiding the shadow the card already declares. WHY 2: A person sees a flat transient message instead of the intended separation from the page beneath it. WHY 3: Toast is a temporal overlay; losing elevation weakens the visual cue that it sits above the task in progress.
USER-FACING PROBLEM: A person receiving a Toast sees its elevation disappear even though the theme supplies it.
PROBLEM SEVERITY: polish. The message and actions remain usable; the defect is the intended elevation treatment.
VERDICT: clear
The stack keeps the existing clipping boundary while a row opens or closes, then releases only the paint boundary after entry finishes. Dismissal restores clipping before collapse. The viewport owns that lifecycle because it already owns the row transition and removal.
- Track settled Toasts and switch the inner wrapper from
hiddentovisibleafter the real grid transition — the cross-engine shadow fix. - Remove pointer hit testing from the entire wrapper as soon as dismissal starts — additional behavior intended to prevent the old out-of-clip action.
BURDEN: medium. One private Set, one transition handler, and one post-entry state update are added; no Effect, listener, observer, timer, public surface, or extra layout read appears.
BURDEN MATCH: proportionate after one deletion. The lifecycle state is the bounded cost of retaining entry/exit clipping while showing the resting shadow. Whole-wrapper pointer-events: none is broader than the failing state and is unnecessary once overflow: hidden returns for exit.
VERDICT: BLOCKS — the pointer guard lets a second click activate obscured app UI while the Toast remains fully visible
OWNER: ToastViewport owns stack-row transition, clipping, and removal; Toast owns the painted surface
TIER 1: CSS @starting-style + grid transition; React event/state lifecycle
TIER 2: none
SEAMS: top-layer viewport, stacked rows, action Toast, all placements, nested dialog viewport
BEHAVIOR UNIT: inline — one transition boundary and one private id set; focused browser probes are the behavioral test
| Seam | Driven result |
|---|---|
| Entry → settled, Chromium 149 | starts hidden; real grid transitionend observed; settles visible; 10/15 sampled rows below card contain shadow |
| Entry → settled, WebKit 26.5 | starts hidden; real grid transitionend observed; settles visible; 10/15 rows contain shadow |
| Late exit, Chromium | current head restores hidden; Undo center is outside the 2–3px inner box; Undo hit/fire are both false |
| Immediate exit, Chromium | current head is still 52px high and opacity 1, but pointer-events: none sends the second dismiss click to the control underneath |
| One-line candidate | deleting only pointerEvents: 'none' restores main's immediate interception and keeps the late Undo hit/fire false |
The lifecycle owner is correct. The new pointer rule broadens the boundary beyond the defect.
VERDICT: BLOCKS — the interaction boundary regresses until the proven one-line correction is applied
The fix now reaches both tested engines: Chromium 149 and WebKit 26.5 show the existing stock shadow after settling, while entry and exit remain clipped. The two exact Round 1 failures are resolved.
At current head, a person who clicks Dismiss twice can activate a control obscured beneath the Toast on the second click while the Toast is still fully visible. Main and the one-line candidate instead let the still-visible dismiss control intercept that click.
VERDICT: BLOCKS — a person can activate unavailable UI underneath a still-visible Toast
No prop, type, export, default, callback, role, DOM attribute, theme target, or call shape changes. The settled-id set is private implementation and adds no ossified surface.
VERDICT: clear
No token, target, variable, or selector contract changes. The existing astryx-toast painting surface and --shadow-med value are unchanged; this patch makes their output visible after entry in both tested engines.
VERDICT: clear
- Behavior: yes, unintentionally at exact head — the whole exiting Toast stops intercepting pointers immediately, so a second click can reach obscured app UI. The previous out-of-clip Undo behavior is fixed.
- API: no.
- Visual: yes, intentionally — the existing shadow becomes visible at rest. Entry and exit remain clipped; card geometry stays 400×52 in the measured default.
- Theme: no — existing targets, tokens, and overrides retain their meaning.
- Empty/loading/error/disabled/controlled/boundary: not newly reachable; this diff changes Toast entry/settled/exit only.
VERDICT: BLOCKS — concrete interaction regressions cannot be downgraded when they activate obscured UI
EFFECTS: zero added or changed.
RENDER: one post-entry setSettledIds state update per settling Toast; dismissal's settled/exiting updates occur in the same event.
LISTENERS/OBSERVERS: none added.
LAYOUT: no JavaScript layout read/write in production; CSS still owns the transition.
BUNDLE: no dependency; 51 runtime additions and 13 removals relative to the exact base.
The added render is the mechanism that releases the clip after the browser transition; no hot or user-sized loop is introduced.
VERDICT: clear
VISUAL CHECK: manual frames required
WHY: the patch intentionally restores shadow pixels, and Toast lacked a compared visual baseline in the PR report.
| Case | Main control | Current head | Result |
|---|---|---|---|
| Chromium 149, settled default Toast | ![]() |
![]() |
sampled rows below card: 0/15 → 10/15 non-white |
| WebKit 26.5, settled default Toast | Round 1 exact-head evidence: 0/15 rows | ![]() |
10/15 rows now contain the shadow |
Canonical receipts sit beside every PNG. Pair check confirms story, theme, mode, direction, viewport/media, semantic state, geometry readiness, animation state, and errors match across the compared arms; only Build differs for main/current. Chromium and WebKit both observed the real grid transition before settled overflow: visible.
The frames were recropped after the first capture used the pre-#5353 right-edge position and contained white space; the final files above contain the Toast and shadow pixels.
VERDICT: clear — the requested cross-engine paint outcome is now measured
Exact-head pr-a11y and pr-rtl are green. No role, name, live-region policy, focus handoff, string, locale, or direction declaration changes. Keyboard activation remains on the exiting control; the new defect is pointer click-through and is owned by IMPACT/BREAKING rather than duplicated here.
VERDICT: clear
- Exact head and current base confirmed before execution;
git diff --checkclean. -
ToastViewport.test.tsx: 31/31 passed. - Targeted ESLint on source and test: passed with zero warnings/errors (Node's pre-existing module-type warning only).
- Exact-head CI: build, test, lint, Storybook, a11y, RTL, theme layers, sandbox, dependency, scope, and Vercel checks green; review gate remains pending because our prior request-changes is still open.
- Chromium 149 and WebKit 26.5 paint probes passed with canonical receipts and zero page errors.
- Chromium main/head/candidate exit probes passed with real pointer clicks and zero page errors.
- Reproduction bundle.
| Slot | Verdict |
|---|---|
| Problem | clear |
| Solution | BLOCKS — whole-wrapper pointer guard activates obscured UI |
| Architecture | BLOCKS — interaction boundary regresses |
| Impact | BLOCKS — second dismiss click activates unavailable UI |
| API | clear |
| Theming | clear |
| Breaking | BLOCKS — user-facing interaction regression |
| Performance | clear |
| Visual | clear — Chromium + WebKit |
| A11y & i18n | clear |
GOAL: met. WebKit 26.5 and Chromium 149 both transition hidden → visible and paint 10/15 sampled shadow rows at rest; Chromium exit returns to hidden, and the formerly out-of-bounds Undo action neither hits nor fires.
DISPOSITION: both Round 1 blockers are satisfied. The click-through regression blocks this head now; deleting pointerEvents: 'none' is the independently verified correction.
ADVICE: proven remedy. Delete pointerEvents: 'none' at ToastViewport.tsx:128. The banked one-line candidate restores main's immediate interception while preserving current head's WebKit shadow and late exit boundary.
AUTHOR CAN PROCEED: yes. No human decision is withheld; the concrete acceptance criterion is that a second click within the still-visible Toast remains intercepted while the late out-of-clip Undo remains unreachable.
WORST OUTCOME: “A person who clicks Dismiss twice can activate a control obscured beneath the still-visible Toast.” → request changes.
JUDGEMENT NEEDED: none — the design owner already approved the intended elevation; the remaining correction restores main's interaction boundary.
Gate 1 found the code issue but failed the screenshot-receipt rules: it included changed CSS in semantic-state equality and captured the old right-edge coordinates after #5353 moved the Toast left. Gate 2 regenerated matching receipts and preserved both independent confirmations, but incorrectly let the re-review rule downgrade concrete user harm. Gate 3 applies the standing impact floor: activating obscured UI is a user-facing interaction regression and blocks. PASS — request changes.
One confirmed blocker remains at the current head. No public action was taken.
Thanks — both requested fixes now pass in Chromium and WebKit.
A person who clicks Dismiss twice can activate an obscured control underneath while the Toast is still fully visible.
pointerEvents: 'none'atToastViewport.tsx:128removes the whole exiting Toast from hit testing immediately. Main intercepts that second click, and deleting this declaration preserves the WebKit shadow and late-exit Undo fix.Could we drop it before this lands?
[Reviewed by Robohands]
None. The single blocking finding is clearer in the request-changes body and already carries its exact line.
- Current
origin/mainis three unrelated commits ahead of the merge base; Toast source and story blobs are identical, so no rebase-only finding exists. - The merged #5353 changes explain the large history delta but are already main; the current PR patch remains three files.
- Closed #5541 is superseded by #5353 and no longer competes with this fix.
Nothing was posted. This corrected re-review made no GitHub review, comment, merge, auto-merge, label, issue, or contributor-branch push. Only the fork-wiki record and its evidence are published.
TIME total 26m
setup 4m exact-head worktree, fresh wiki clones, safe fast install, warm main
reading 7m full history, prior review, current kit/rubric, merged-main delta, repo rules
measuring 9m Chromium/WebKit paint, main/head/candidate pointer A/B, focused checks
writing 6m presentation, three critic gates, verdict correction, wiki record
waste 3m cancelled a stray Safari process and recaptured a stale-position white crop
warm main reused: yes — a7ad8f98; Toast source/story match exact base
re-measures: 2 — corrected semantic-state receipts and the post-#5353 crop
- Firefox was not run; the prior engine-specific failure was WebKit, and WebKit 26.5 is verified directly at this head.
Head reviewed: 5eaa259f0d11e557d116e883dbcfdb7d0765c18a
Previously reviewed wiki head: b962d810bdebad86f382853ced4bb2db7a820e08
Prior posted request-changes head: 5df116926a18b8f399f8c0caa854756334a5becc
Prior approved head with notes: a022b53ea1a345b71ec060781111abc8cc42ab8b
Verdict: approve (drafted; no public PR action)
LOOP VERSION: 1.6.0
AUDIT RUBRIC: 1.13
LANE: full. This is a visual and interaction delta re-review after request-changes: every prior finding, the stale settled-id note, the corrected changeset claim, and the affected Toast interaction radius were rechecked.
Step 0 passed before install/build. The effective PR file list is one Toast source file, its test, and one changeset; no dependency, lockfile, workflow, package script, executable tool, credential, environment-read, or build-network path changed.
Round 1 at b962d810 blocked on overflow-clip-margin: WebKit 26.5 ignored it, and Chromium kept out-of-row Undo hit-testable during exit. Round 2 at 5df11692 verified the hidden/visible mechanism fixed those, then blocked pointer-events: none because a second Dismiss click could activate obscured UI underneath. The approved note at a022b53e asked for stale settled ids to be pruned on overwrite and the changeset's hit-testing claim corrected.
The a022b53e → 5eaa259f delta is three PR files, +91/−18: add withoutId, prune a replaced toast's settled id when uniqueID overwrites, reuse the helper for dismissal/exit cleanup, add the overwrite lifecycle test, and rewrite the changeset sentence. The overflow mechanism and wrapper pointer-events: auto boundary are unchanged from the prior approved head.
WHY 1: Toast's collapse wrapper clips at the card border box, hiding the shadow the card already declares.
WHY 2: A person sees a flat transient message instead of the intended separation from the page beneath it.
WHY 3: Toast is a temporal overlay; losing elevation weakens the cue that it sits above the task in progress.
USER-FACING PROBLEM: A person receiving a Toast sees its elevation disappear even though the theme supplies it.
PROBLEM SEVERITY: polish — the message and actions remain usable; the defect is the intended elevation treatment.
VERDICT: clear
The stack clips each Toast while the row opens or closes, then releases only the paint boundary after entry finishes. Dismissal restores clipping before collapse. The viewport owns that lifecycle because it already owns the row transition and removal.
SOLUTION (2 decisions · private implementation only)
- Track settled Toast ids and switch the inner wrapper from
hiddentovisibleafter the real grid transition. - Prune a replaced Toast's settled id when a
uniqueIDoverwrite swaps in a new row.
BURDEN: medium — one private Set, one transition handler, and one post-entry state update per settling Toast; no new Effect, listener, observer, timer, public surface, or layout read.
BURDEN MATCH: proportionate — the state is scoped to the private row lifecycle needed to keep entry/exit clipped while the settled shadow paints.
VERDICT: clear
OWNER: ToastViewport owns stack-row transition, clipping, and removal; Toast owns the painted surface
TIER 1: CSS grid transition, React event/state lifecycle
TIER 2: none
SEAMS: top-layer viewport, stacked rows, action Toast, uniqueID overwrite, all placements, nested viewport
BEHAVIOR UNIT: inline — one transition boundary and one private id set; focused browser probes and unit tests cover it
| Seam | Driven result |
|---|---|
| Settled shadow, Chromium | main remains hidden; head settles visible; 0/15 → 13/15 sampled rows below the card contain shadow |
| WebKit prior finding | mechanism unchanged from the prior approved head, whose WebKit 26.5 measurement showed the settled shadow visible |
| Second Dismiss click | wrapper remains pointer-events: auto; an underlying control placed directly behind the dismiss point received 0 clicks |
uniqueID overwrite |
toast id changes astryx-toast-1 → astryx-toast-2; replacement starts hidden, then settles visible
|
The lifecycle owner remains correct and the stale-id cleanup lives at the overwrite seam that creates the dead id.
VERDICT: clear
The two blocking interaction/browser findings are resolved: Chromium paints the resting shadow and the still-visible exiting Toast keeps intercepting pointer clicks. The WebKit-affecting mechanism did not change after the prior WebKit pass; this round's WebKit runner launched 26.5 but closed before opening a page, so the exact-head WebKit recheck was not repeatable in this run.
The overwrite fix has no visible end-user change unless a toast is replaced after it settled; in that state the replacement now starts clipped and releases the clip on its own transition instead of inheriting stale settled state.
VERDICT: clear
No prop, type, export, default, callback, role, DOM attribute, theme target, or call shape changes. The settled-id set and withoutId helper are private implementation.
VERDICT: clear
No token, target, variable, or selector contract changes. The existing astryx-toast painting surface and --shadow-med value are unchanged; the patch makes that already-declared output visible after entry.
VERDICT: clear
- Behavior: intended — settled Toast shadows paint; exit clipping and wrapper pointer interception are preserved.
- API: no.
- Visual: intended — the existing shadow becomes visible at rest. Chromium 149 shows 0/15 → 13/15 sampled non-white rows below the card.
- Theme: no — existing targets, tokens, and overrides retain their meaning.
- Empty/loading/error/disabled/controlled/boundary: not newly reachable; this diff changes Toast entry/settled/exit and overwrite cleanup only.
VERDICT: clear
EFFECTS: zero added or changed.
RENDER: one post-entry setSettledIds update per settling Toast; overwrites and dismissals prune one id.
LISTENERS/OBSERVERS: none added.
LAYOUT: no JavaScript layout read/write in production; CSS owns the transition.
BUNDLE: no dependency.
The private Set is bounded by visible/to-be-exited Toast rows, and this round specifically removes the overwrite leak.
VERDICT: clear
VISUAL CHECK: manual frames required
WHY: the patch intentionally restores shadow pixels, and the exact-head visual gate awaits human visual acceptance.
| Sensor | Main control | Exact head |
|---|---|---|
| Build | e6507a95fb13cae83f94e2d4b58009eaf584f1c6 |
5eaa259f0d11e557d116e883dbcfdb7d0765c18a |
| Story | core-toast--deduplication |
same |
| Theme / mode / direction | neutral / light / LTR | same |
| Viewport/media | 900×520 @1; forced colors off; reduced motion off; fine pointer; hover | same |
| Semantic state | one settled Toast, 400×52, no page/Storybook errors | same |
| Clip state | hidden |
visible |
| Main — shadow clipped | Exact head — shadow visible |
|---|---|
![]() |
![]() |
Pixel receipt: main has 0/15 non-white rows below the card; exact head has 13/15, falling from 232 at row +1 through 254 at row +13.
VERDICT: clear
REMEDY SEARCH: not triggered — no proven visual defect
Exact-head pr-a11y and pr-rtl are green. No role, name, live-region policy, focus handoff, string, locale, or direction declaration changes. Pointer click-through was rechecked as behavior and no longer reproduces.
VERDICT: clear
- Focused test:
ToastViewport.test.tsx— 32/32 passed. - Targeted ESLint on
ToastViewport.tsxandToastViewport.test.tsx— passed with zero warnings/errors, aside from Node's module-type runtime warning. -
git diff --checkon the PR files — passed. - Exact-head CI: build, test, lint, Storybook, a11y, RTL, theme layers, sandbox, dependency, scope, Vercel, and review-required passed.
- CI still pending on
visual-acceptance: stable visual changes await/accept-visual.
| Slot | Verdict |
|---|---|
| Problem | clear |
| Solution | clear |
| Architecture | clear |
| Impact | clear |
| API | clear |
| Theming | clear |
| Breaking | clear |
| Performance | clear |
| Visual | clear |
| A11y & i18n | clear |
GOAL: met. Chromium exact head restores the 13-row shadow falloff; the WebKit mechanism is unchanged from the prior approved WebKit-measured head; the second Dismiss click no longer reaches an underlying control; overwrite starts a fresh clipped row and then settles it independently.
DISPOSITION: Round 1 findings fixed; Round 2 click-through fixed; approved-head notes fixed. No negative finding remains.
ADVICE: omitted — no author-facing correction remains.
AUTHOR CAN PROCEED: yes — remaining external gate is visual acceptance, not an author code change.
WORST OUTCOME: none found.
JUDGEMENT NEEDED: none — the design owner already approved the intended elevation, and this round only validates the requested mechanics.
Gate 1 failed the visual slot because WebKit could not open a page in this run and the first image receipt did not display to the model. The corrected presentation limits the current-run engine claim to Chromium, carries prior WebKit evidence only for unchanged code, and states the exact verification gap. R1e passes: every prior finding and later note is named and disposed. R16g passes for the former blockers via source diff + browser interaction + focused tests. PASS — approve.
No code-review blocker remains. No public action was taken.
Thanks — this addresses my remaining notes. The overwrite path starts clipped, settles independently, and the changeset now matches the current hit boundary. Good to approve once visual acceptance clears.
[Reviewed by Robohands]
None.
- The last commit is a merge from
main; the effective PR delta still only touches the Toast source/test and changeset. - The visual-acceptance workflow is pending because stable visual changes await
/accept-visual; that is not a code-review finding. - WebKit 26.5 could not be rerun in this round because it closed before page creation twice; the code that mattered for the prior WebKit finding is unchanged since the approved WebKit-measured head.
Nothing was posted. This re-review made no GitHub review, comment, merge, auto-merge, label, issue, or contributor-branch push. Only this fork-wiki record and its public-safe evidence assets are published.
TIME total 17m
setup/rules 3m memory, loop 1.6.0, rubric 1.13, fresh wiki clones, safety scan
build/server 4m fast install, one @astryxdesign/build build, exact-head Storybook, warm main reused
browser/a11y 6m Chromium visual/interaction probes; CI a11y/RTL read; WebKit retry failed before page creation
focused tests 1m ToastViewport test, ESLint, diff check
code/history 2m old→new delta, prior reviews, source/tests/changeset
critique/wiki 1m self-critic, wiki append, index update
CI wait 0m exact-head checks already complete except visual-acceptance pending
waste 2m one wrong Vitest cwd and two WebKit launch retries
re-measures 2 main/head sensor correction; focused click-through probe with target placed under the click point
- Exact-head WebKit 26.5 browser evidence could not be recaptured: WebKit launched and then closed before opening a page in both headless and headed runs. The WebKit-affecting overflow code is unchanged from the prior approved head that was measured in WebKit.






