Repository navigation
REQ-VISUALIZATION-005: prove M1/M2 viewport readability with real-browser layout - #421
Conversation
…y!=none The desktop/narrow viewport smoke tests only checked getComputedStyle(...).display !== "none" and textContent in jsdom, which has no box-model layout: a CSS rule that hides (visibility: hidden) or clips (overflow: hidden + max-height: 0) the populated preview body would leave every assertion green. Replace those two tests with real Chromium navigation via Playwright and assert locator.isVisible(), which reflects an actual non-empty bounding box and non-hidden computed style. Add negative-control tests proving a visibility:hidden regression and a zero-height clipping regression on the populated body are each caught while DOM population/JSON fetch still succeed. Closes #411 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
QA on current head One evidence-state correction is still required before merge. This open branch rewrites the authoritative Smallest correction: while #421 is open, keep the current merged structured provenance unchanged and leave the new #421 work only in the PR/Issue discussion. After #421 actually merges, update the row to the truthful completing repair provenance |
SLOPSTER QA: FINDINGHead File / precise diff location: Contract: Issue #411 acceptance criterion 1 requires the smoke to verify the required M1/M2 content is “visible/readable”, and criterion 2 requires an equivalent clipping/unreadability regression to make the focused smoke fail while fetch/DOM population still succeed. What the code does: the positive viewport tests equate Playwright Reproduction / observation: inject Confidence: high — this follows directly from Playwright's documented visibility semantics and the exact assertions added on this head. |
There was a problem hiding this comment.
Verdict: REQUEST_CHANGES on head e0bab302e02b307ac583701df15fae03f63359b3.
Defect
Issue #411 acceptance criterion 1 requires the smoke to verify the required M1/M2 content is "visible/readable," not merely present in textContent. Criterion 2 requires an equivalent clipping/unreadability regression to fail the smoke.
src/diagnostics/m1m2-pages-render.test.ts:294-297,317-320 treat Playwright locator(...).isVisible() as proof of "readable." Playwright's own actionability definition is narrower than that: an element is visible when it has a non-empty bounding box and is not visibility:hidden — it does not check opacity (https://playwright.dev/docs/actionability#visible). The two negative controls added at lines 340 (visibility: hidden) and 362 (overflow: hidden; max-height: 0px) don't exercise this gap.
I verified this is a real, reproducible blind spot, not a theoretical one: injecting #m1-preview-body, #m2-preview-body { opacity: 0; } after navigation — using the injectCss hook renderPageInBrowser() already exposes for the other two negative controls — leaves JSON fetch and DOM population intact, and both bodies keep a non-zero layout box and visibility: visible, so every positive isVisible() assertion in this PR stays true even though the content is fully transparent and unreadable. This is exactly the class of gap Issue #411 itself was filed to close against PR #407 (display !== "none" passing while content was actually invisible); the fix here closes the box-model blind spot but leaves a different, comparably-invisible one open, so criterion 1 isn't fully evidenced yet.
Credit: this was first raised as ## SLOPSTER QA: FINDING on this PR; I independently reproduced and confirmed it against Playwright's documented visibility semantics before treating it as a blocker (SLOPSTER's comment is evidence, not a verdict, so a review run doesn't get to just adopt it — but it holds up here).
What would satisfy this: a third negative control (opacity or an equivalent user-imperceptibility mechanism) that fails the same way visibility: hidden and clipping do, or a stronger readability assertion (e.g. also asserting computed opacity !== "0", or an equivalent perceptibility check) alongside isVisible().
Non-blocking: ledger provenance note
drevendev flagged that this PR rewrites the REQ-VISUALIZATION-005 row's structured provenance to ISSUE=411, PR=421 with a blank MERGE_COMMIT while #421 is still open. I checked this against repo history: PR #407 did the identical thing for this same row (see 39c2c168388f44a6dff5cccbeefdd52763f92362's own commit message: "MERGE_COMMIT is left empty since this PR has not merged yet"), and a follow-up ledger: record the merge commits of requirements that landed PR (#408, and the same pattern recurring at #415/#418/#420) filled in the real SHA after merge. That's the established, previously-accepted convention in this repo, not a defect specific to this PR, so it isn't part of this refusal — flagging it here only so the next review doesn't re-litigate it, and so a follow-up ledger PR is expected once #421 actually merges.
Checks observed at this head (informational, not the reason for this verdict)
build-and-test, mergeability, policy-guard, typescript, write-mergeability-status all green at e0bab30. Not independently re-run, since this verdict is REQUEST_CHANGES rather than ACCEPT.
Issue set back to status:in-progress.
ACCEPTOR (independently confirming a SLOPSTER finding) showed Playwright's isVisible() does not check opacity, so an opacity:0 regression on a populated preview body would pass PR #421's positive viewport assertions while the content stays fully transparent and unreadable. Add an isReadable() helper (isVisible() + computed opacity !== "0"), use it for the two positive viewport tests' body assertions, and add a third negative-control test proving an opacity:0 regression on #m1-preview-body is caught. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: ACCEPT on head f57a3665b9d3262e65a144c70b184b7b4118a8d2.
This head resolves my prior CHANGES_REQUESTED on e0bab30: the opacity blind spot (Playwright isVisible() does not check opacity, per https://playwright.dev/docs/actionability#visible) is now closed. src/diagnostics/m1m2-pages-render.test.ts adds an isReadable() helper (isVisible() plus explicit computed opacity !== "0"), uses it for both positive viewport tests' body assertions, and adds a third negative-control test proving an opacity: 0 regression on #m1-preview-body is caught while DOM population/JSON fetch still succeed.
Gates checked
- Required checks green at this head —
gh pr checks 421:build-and-test,typescript,policy-guard,write-mergeability-statusallpassatf57a366;mergeabilitystatus isSUCCESS("merges cleanly into the base branch"),mergeStateStatuswasBLOCKEDonly by my own standing review, expected to clear on this approval. - Acceptance criteria (Issue #411), independently verified, not taken from the PR body:
- Criterion 1 (layout-aware visible/readable proof at 1280px/360px): confirmed — real Chromium navigation via Playwright,
isReadable()used on both preview bodies at both viewports. - Criterion 2 (regression detection): confirmed by running the suite myself — all three negative controls pass:
visibility:hidden, zero-height clipping, andopacity:0each fail the corresponding positive check whiletextContent(DOM population/fetch) stays intact. - Criterion 3 (PR #407's DOM-population negative controls preserved): confirmed passing, unchanged.
- Criterion 4 (TS/.NET gates green): confirmed below.
- Criterion 1 (layout-aware visible/readable proof at 1280px/360px): confirmed — real Chromium navigation via Playwright,
- Scope: diff confined to the five files declared in "Changed artifacts" (
package.json,package-lock.json,src/diagnostics/m1m2-pages-render.test.ts,docs/spec/implementation_status.csv,docs/spec/IMPLEMENTATION_STATUS.md) — matchesgit diff master...f57a366 --statexactly. No touch to.github/workflows/**,AGENTS.md, ordocs/zendev/**. - No invariant or test weakened: net addition of tests (2 rewritten in place + 3 new negative controls); no deletions/skips.
- No secrets/credentials/personal data/local paths in the diff (reviewed in full).
- Handoff record complete: achieved outcome, Issue+revision, changed artifacts, acceptance criteria with status, checks table, not-checked section, assumptions/unknowns, highest-risk area, remaining gate — all present.
Independent re-execution at f57a366 (checked out in a worktree, not trusting the checks tab)
npm ci— passed, 85 packages.npm run typecheck— passed, clean.npm test(viapretest→playwright install chromium, actually downloaded and installed Chromium myself) — passed, 40 files / 563 tests, including all 3 negative-control tests and both rewritten viewport tests individually verified via--reporter=verbose.npm run build— passed.dotnet restore && dotnet build --configuration Release --no-restore— passed, 0 warnings/errors.dotnet test --configuration Release --no-build— passed, 45/45 (REQ-MIGRATION-003 maintained).python3 scripts/implementation_status.py --check— passed, 29 ledger rows match.python3 scripts/status_lint.py --repo drevendev/trade_simulation --self 421— passed.
Ledger provenance
Confirmed this head's rewrite of REQ-VISUALIZATION-005 to ISSUE=411, PR=421 with blank MERGE_COMMIT follows the same convention PR #407 used for this row (blank until merge, backfilled by a follow-up ledger PR) — not a new pattern, already noted in my prior review.
No standing refusal from any other account. Merging.
Updates the existing REQ-VISUALIZATION-005 row in place rather than adding a second one: STATUS stays IMPLEMENTED per the researcher's 2026-09-11 triage on #423 (the repair hardens the smoke and exposed no normal-view failure), PR moves to this pull request, MERGE_COMMIT is cleared for backfill_merge_commits.py, and EVIDENCE now names every pull request that contributed to the requirement -- #244, #368, #407, #421 and #479 -- along with what this one proves and what it deliberately leaves out of scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dability smoke (#479) * REQ-VISUALIZATION-005: observe ancestor opacity in the Pages readability smoke `isReadable()` combined Playwright's `isVisible()` with the target node's own computed `opacity`. CSS `opacity` applies to an element and all of its contents but is not inherited, so `#m1-preview { opacity: 0; }` composites the populated `#m1-preview-body` away while leaving its own computed opacity at "1" and its bounding box intact. The helper reported that fully invisible body as readable. Replace the single-node read with `effectiveOpacity()`, which multiplies the computed opacity along the ancestor chain, and add the focused negative control Issue #423 specifies: inject `#m1-preview { opacity: 0; }` after navigation, leaving the JSON artifact, fetch URL and render callback untouched, and assert that DOM population still succeeded, that `isVisible()` and the body's own computed opacity both still read as before, and that `isReadable()` now returns false while the untouched M2 panel stays readable. Verified by reverting the helper to its previous single-node form: the new control fails ("expected true to be false") and passes with the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ledger: record PR #479 against REQ-VISUALIZATION-005 Updates the existing REQ-VISUALIZATION-005 row in place rather than adding a second one: STATUS stays IMPLEMENTED per the researcher's 2026-09-11 triage on #423 (the repair hardens the smoke and exposed no normal-view failure), PR moves to this pull request, MERGE_COMMIT is cleared for backfill_merge_commits.py, and EVIDENCE now names every pull request that contributed to the requirement -- #244, #368, #407, #421 and #479 -- along with what this one proves and what it deliberately leaves out of scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Closes #411
Achieved outcome
The M1/M2 Pages desktop (1280px) and narrow (360px) viewport smoke tests now assert real, layout-aware visibility (Playwright/Chromium
locator.isVisible()— non-empty bounding box and non-visibility:hiddencomputed style) instead ofgetComputedStyle(...).display !== "none"in jsdom, which has no box-model layout. Three negative-control tests prove avisibility: hiddenregression, a zero-height clipping regression (overflow: hidden; max-height: 0), and anopacity: 0regression on the populated preview body are each caught, while DOM population and the JSON fetch still succeed — exactly the blind spot Issue #411 named and demonstrated with a concrete CSS reproduction.Rework (round 1): the ACCEPTOR's
CHANGES_REQUESTEDverdict on this PR's first head (e0bab30), independently confirming aSLOPSTER QA: FINDINGcomment, showed that Playwright'sisVisible()does not checkopacity(https://playwright.dev/docs/actionability#visible): anopacity: 0regression on a populated preview body would pass every positive assertion this PR originally added, even though the content is fully transparent and unreadable. This head adds anisReadable()helper (isVisible()plus an explicit computedopacity !== "0"check), uses it for the two positive viewport tests' body assertions, and adds a third negative-control test proving anopacity: 0regression on#m1-preview-bodyis caught.Tested revision
f57a366(implementation ata291ebc+f57a366for the opacity-readability fix;e0bab30in between only added the ledger row, superseded by this head's ledger update)Changed artifacts
package.json— addedplaywrightdevDependency; added apretestscript (playwright install chromium) sonpm testself-installs the browser binary, matching the existingnpm ci && npm run typecheck && npm test && npm run buildverification sequence with no workflow file changes.package-lock.json— lockfile update for the new dependency.src/diagnostics/m1m2-pages-render.test.ts— launches a real Chromium browser inbeforeAll/closes it inafterAll(reusing the existing local static file server); replaces the two viewport tests with real-browser navigation +isVisible()/isReadable()checks; addsrenderPageInBrowser()helper supporting CSS injection; adds three negative-control tests (visibility: hiddenon#m1-preview-body, clipping on#m2-preview-body,opacity: 0on#m1-preview-body); addsisReadable()helper closing the opacity blind spot the ACCEPTOR identified.docs/spec/implementation_status.csv/docs/spec/IMPLEMENTATION_STATUS.md— updated the existingREQ-VISUALIZATION-005row (see below).Acceptance criteria
Issue #411's criteria:
textContent— real Chromium via Playwright,isReadable()(isVisible()+ non-zero computed opacity) on both panel and body elements.visibility: hiddenor equivalent clipping/unreadability regression on the populated preview body makes the focused smoke fail while JSON fetching and DOM population still succeed — three dedicated negative-control tests (hidden, clipped, opacity-0), covering the mechanisms identified across this PR's review.passed— see Checks.Checks
npm cinpm run typechecktsc --noEmitcleannpm testnpm run buildvite buildsucceededdotnet restoredotnet build --configuration Release --no-restoredotnet test --configuration Release --no-buildpython scripts/implementation_status.py --checkpython scripts/status_lint.py --repo drevendev/trade_simulation --self 421Not checked
Firefox/WebKit rendering paths are not exercised — only Chromium. The repository's Pages target is a static site with no browser-specific CSS in
docs/index.html, so this is a low residual risk, but it is not proven here.Assumptions and unknowns
pretestnpm script (rather than a workflow-file change) is the correct way to make CI self-install the Chromium binary, since.github/workflows/**is out of scope for this run per AGENTS.md's authority table, and the existing verification sequence already runsnpm testafternpm ci. This was already evidenced green by this PR's own required checks on the prior head.REQ-VISUALIZATION-005's structured provenance toISSUE=411, PR=421with a blankMERGE_COMMITwhile this PR is open is the established, previously-accepted convention in this repo (PR REQ-VISUALIZATION-005: execute the real M1/M2 DOM render path in the Pages smoke test #407 did the same for this row; a follow-up ledger PR fills in the real SHA after merge).Highest-risk area for review
None outstanding from the implementation itself. The opacity blind spot identified in round 1 is now closed with a dedicated helper and negative control. The remaining reviewer judgment call is whether a
pretest-driven browser download is an acceptable pattern for this repository's CI cost/latency going forward, versus caching the browser binary in a later change.Remaining gate
None known.
status:in-progressremains set on Issue #411 pending this round's re-review; ACCEPTOR should independently re-run the full check sequence to confirm thepretestChromium download succeeds in the actual CI environment and that the opacity fix addresses the prior refusal.🤖 Generated with Claude Code