Round 4 found the raw column dumped onto the Branding row and asked whether the sheet behind it — the ONE-playbook-row-TWO-sheets door V-12 specifies — actually holds the detail the row can't. Round 4 answered that from source code. This round opens the doors and photographs what's actually inside: the offerings sheet works as designed (it's just empty here), the FAQ sheet works as designed, and the two Branding sheets do not agree with the row that opens them — one shows a clean flow that's never seen the row's text, the other shows the exact same wall of text, unclamped.
The prior harness lost 03-what-you-sell-truncation and
05-branding-voice-look at 1440px only (4 of 6 states). Root cause:
getByText(/what you sell/i) and getByText(/^branding$/i) both match
TWO nodes with identical label text — the section's own <h3> heading, and
the sticky BrainJumpNav pill of the same name. BrainJumpNav.tsx renders
the pill row twice — once in an lg:hidden block (mobile-stacked
groups), once in a hidden lg:flex block (desktop wrapping row) — and the
lg:hidden clone comes FIRST in DOM order. .first() always resolved to
that clone, which is genuinely display:none at 1440px — so
isVisible() returned false and the capture step was silently skipped. At 375px the
same clone is the visible one, so it worked there by coincidence, not by correct scoping.
page.getByRole('heading', { name: /^what you sell$/i })
page.getByRole('heading', { name: /^branding$/i })
Verified: 6/6 states capture cleanly at both widths now. Two further races surfaced once the
harness started opening sheets (fixed in the same pass, both in
tests/e2e/brain-parity-capture.spec.ts):
getByRole('button', { name: 'Close' }).first()
is unscoped — the page mounts a root-level toast/notification region
(“Notifications (F8)”) ahead of the header in the DOM, and a stray toast close
control can out-rank the sheet's own ✕ for .first(), leaving the real
dialog open to intercept the next click. Fixed by scoping to
page.locator('[role="dialog"]').first().getByRole('button', { name: 'Close' }).ModalWrapper unmounts a closed sheet synchronously
(if (!isOpen) return null, no exit animation) — but the harness's own
200–300ms fixed waits weren't reliably ordered against React's commit, so the next
section's click occasionally landed while the previous dialog was still in the DOM. Replaced
with an explicit waitFor({ state: 'hidden' }) poll on [role="dialog"].
Result: 20 captures across both widths (10 states × 2, one state —
04b-faq-sheet — needed a further trigger-matching fix below before it stopped
reporting a false UNREACHABLE).
Added: open the offerings depth sheet (“view all N →”), the FAQ depth sheet
(same), the “(sound)” door, and the “(look)” door — screenshot each,
close with the sheet's own ✕ (Escape as fallback), never type into a field, never tap
a paid or write action inside. One trigger-detection bug surfaced along the way worth naming: the
FAQ sheet's open door for a SHORT list (this account has 1 FAQ, below the 5-item
“view all” threshold) is EditableListBlock's aria-label="Edit this
section" — an accessible NAME with no matching visible TEXT node, so
container.getByText(/edit this section/i) never found it and the sheet was
misreported UNREACHABLE. Fixed by falling back to getByRole('button', { name: pattern })
when the text search comes up empty.
fullPage: true against a position: fixed; bottom-0
sheet. Chromium's full-page capture temporarily expands the viewport to the document's full
scroll height and repaints; a fixed-position element then anchors to THAT expanded viewport, not
the real one. The sheet screenshots below genuinely show every pixel the sheet renders, but the
vertical proportions (how much page peeks above/below the sheet) are a capture artifact, not what
a founder's actual browser window shows. Treat these as reliable evidence for
content (what fields exist, what text is in them) and unreliable evidence for
overlay geometry (peek-gap height, split-pane width ratio) — a viewport-clipped
screenshot would be needed to grade the latter, which this round did not capture.
V-12 (brain.html:3403) is explicit: the row stays short because the sheet behind it
holds the real material. Round 4 established the row is over-full on the Branding facets. This
round opens all four sheets to check the other half of that promise, one surface at a time.
ServiceRow is mounted NON-readOnly here
(PlaybookPage.tsx never passes readOnly to this
PlaybookDepthSheet) — Name / Price / Dates / Description /
Details / Booking link all render as editable fields. Confirms R4-02's read of the
code exactly: this IS the only surface details can ever appear on. For THIS
offering (the first of 10, “1:1 Sessions available Online and in person”), both
Description and Details are empty placeholders — no stored content, not a hidden field.
The left pane is the B13 co-pane digest (BrainCoPaneDigest), confirming the
40/60 split DOES engage at this width — see §6 on f13.description/details as editable fields
— R4-02 already said as much (“only inside an editable textarea”), this round
is the first to prove it with a screenshot instead of a code read. What's unconfirmed is whether
ANY of this account's 10 offerings actually has details populated — the harness
captured the sheet's top scroll position only (offering #1), not all 10, and this run's rails
forbid a DB read to check directly. Open question, not a claim either way.
FaqCandidatePicker (NOT the FaqCandidateChips
component named in the task brief — a distinct, always-mounted sibling, see §7)
renders 3 tap-to-answer starter questions above the list regardless of whether the list is
empty. Below it, the single stored FAQ renders in FULL, editable, unclamped — both the
Question and Answer fields carry the entire text the row below truncates. This is a genuine
MATCH for V-12's row/sheet split: the sheet holds what the row can't, exactly as specified.
The content itself is still wrong (see R4-03 below) — that's a categorisation bug, not a
sheet-depth bug.HowYouSoundSheet is in GENERATE mode (“Pick it by ear”, “Hear how
you sound”, a blank “what we already have” paste box, a tone-chip question)
because profile.brand_voice_v2 is empty — a completely different field from
the tone/custom_instructions column the row reads
(PlaybookPage.tsx:1371, per R4-01's root cause). See R5-01 below.hasStyleCard === false Instagram-only branch
from a second angle: the read action itself is gated on a website_url this
account doesn't have. Tier 2 (“THE VIBE”) renders the exact same raw, unclamped,
multi-image-concatenated paragraph the row shows — word-for-word. See R5-02 below.Verdict vocabulary per the parity plan: MATCH / MISMATCH-KNOWN / MISMATCH-NEW / UNREACHABLE, worst-of-both-widths. Only frames this round's read-only walk could actually reach are graded; everything gated on a click the safety rails forbid (persona-badge drills, swatch edits, the calibration game, guest walk, legacy-scope account) stays out of scope, per the plan's own declared exclusions.
| Frame | Width | Verdict | Evidence |
|---|---|---|---|
| f9 — empty-account row grammar (checked against THIS populated account's shared rows) | 375/1440 | MATCH | One row grammar throughout: title + quiet line + trailing door; “Product listing copy” carries the honest “Specified, not built yet” placeholder (R4-05). |
| f10 — jump-nav, 375 | 375 | MISMATCH-KNOWN | Full desktop-length chip text renders unshortened (“FAQs & policies”, “Branding”) — matches the doc's own pre-flagged drift, not new. |
| f10 — jump-nav, 1440 | 1440 | MISMATCH-NEW (tempered) | Part B specifies both groups inline in ONE row at ≥lg. Shipped wraps to two rows (“Customers hear” row, then “Only you see” row) at 1440px — 11 chips don't fit one row at this width. BrainJumpNav.tsx's own comment documents this as INTENTIONAL (“RB2 redesign: groups flow inline and WRAP onto extra rows…no horizontal scroll lane”) — a real doc-vs-code disagreement, not obviously a bug; flagging rather than asserting either side is wrong. |
| f13 — detail sheet, EDIT mode (What you sell) | 1440 | MATCH (corrects a prior MISMATCH-KNOWN) | Part B's known-mismatch says the 40/60 split “never engages” at desktop. The B13 co-pane digest (BrainCoPaneDigest, #2938) DOES render alongside the sheet at 1440px in this capture — left pane lists every section with a status + an is-target highlight on the active one. This looks like a newer feature that superseded the doc's known-mismatch note; flagging the contradiction rather than silently logging it as the stale known item. |
| f13 — detail sheet, 375 | 375 | MATCH | Full-width single-column sheet, no split attempted — matches spec (split isn't expected on mobile). |
| f22 — “How you sound” row anatomy (Branding row, two doors) | 375/1440 | MATCH | PlaybookBrandingRow renders exactly one “Branding” row with two independent (sound)/(look) doors — confirms the Quality-gate correction that this was wrongly logged as NOT-BUILT previously. |
| f22 — “How you sound” sheet content | 375/1440 | MISMATCH-NEW | Spec calls for “You, in one line” + “How you write” (chip “our read”) + voice match score + “Sounds like you…” line. None of that renders — the sheet is in GENERATE mode showing zero relationship to the row's content. See R5-01. |
| f24 — “How you look” sheet | 375/1440 | MATCH (existence, corrects a prior false-absence) | Confirms the Quality-gate correction that this sheet IS built (was previously falsely marked NOT-BUILT). Viewed only, no swatch tapped. |
| f24 — “How you look” content quality | 375/1440 | MISMATCH-NEW | “THE VIBE” block is the same unsynthesised raw dump as the row — no clamp, no summary. See R5-02. |
| Offerings depth sheet (V-12 sheet-holds-detail promise, services) | 1440 | MATCH (mechanism) / data unconfirmed | Description/Details render as editable fields — the mechanism is correct. This account's first offering has both empty; the other 9 unchecked. |
| FAQ depth sheet (V-12 sheet-holds-detail promise, faqs) | 1440 | MATCH | Full Q&A renders unclamped, exactly as the row-truncates/sheet-holds pattern specifies. |
| f2a/f2b guest walk, f26 legacy-scope banner, f11 answer-waiting, persona-badge drills | — | UNREACHABLE | Out of this run's scope — no guest session opened, no legacy-Google-scope test account, no pending-proposal state on this account. Not attempted, not graded. |
This account's FAQ list has 1 item, so the TRUE-empty branch that mounts FaqCandidateChips
never renders — every live screenshot this round shows FaqCandidatePicker
instead (a different, always-mounted sibling component, §4 above). The following are
confirmed by direct source read, not by screenshot — labelled as such, not asserted as
visually observed.
| Claim | Source | Verdict |
|---|---|---|
| Touch target below the 44px mobile minimum, and shrinks further at desktop | FaqCandidateChips.tsx:36 — min-h-[36px] sm:min-h-[32px] | CONFIRMED (source) |
text-foreground/85, border-white/15 off the named opacity ladder (--fg-70/-55/-40/-30) | FaqCandidateChips.tsx:36 | CONFIRMED (source) |
| Wrapping pill cloud for option-picking, against the vertical-first layout principle | FaqCandidateChips.tsx:30 — flex flex-wrap gap-2 | CONFIRMED (source) |
white/85, white/45, white/25, white/35 all off-ladder | FaqCoverageDots.tsx:40,43,84,87,93 | CONFIRMED (source) |
| Permanent 3-item legend explaining the dots | FaqCoverageDots.tsx:92-103 | CONFIRMED (source) |
| Live render of either component | — | UNREACHABLE this round — needs an empty-FAQ, persona-set test account. Round 4 flagged the identical gap (§6 “could not answer”) — still open two rounds later. |
PlaybookDepthSheet.tsx:425-431
and exportPlaybook.ts:145. New nuance: for the one offering this round could see,
the textarea itself is empty — the fix's cost/benefit depends on whether the other 9
offerings actually carry stored details, which is unconfirmed (open question, §8).voiceInstructions || profile.tone?.trim() (PlaybookPage.tsx:1371).
HowYouSoundSheet reads profile.brand_voice_v2 — a completely
different column, currently empty for this account. A founder who reads the wall of text on the
row and taps “(sound)” to fix it lands on a GENERATE-mode onboarding flow
(“Pick it by ear”, a blank paste box) with zero visible connection to what they just
read. The fix door and the broken content are wired to two unrelated fields.visual_tone column, same 29-fragment concatenation,
rendered with no line-clamp and no synthesis inside HowYouLookSheet. Confirms V-12's
row/sheet split is violated on BOTH sides for the look facet, not contained to the row as R4-01
implied. The Tier-1 CSS-facts block correctly shows “Add your website first”
— that part IS gated as designed; it's Tier 2 (the vibe) that leaks.BrainJumpNav.tsx's own docstring calls the
wrap an intentional RB2 redesign choice (“no horizontal scroll lane”). Flagging the
doc/code disagreement rather than asserting the shipped behaviour is wrong — it may be the
design doc that's stale.details populated. The harness
opens the sheet at its default scroll position (offering #1, empty). Scrolling through all 10,
or a scoped DB read of business_profiles.services for this QA account, would
settle it — this run's rails forbid the latter, and the harness doesn't yet scroll inside
a sheet.FaqCandidateChips persona-generation path. Same gap Round 4
flagged — this account has FAQ content, so the true-empty branch never mounts. Needs a
fresh persona-set account with zero FAQs.fullPage,
viewport-clipped capture would be needed.#2938 before updating the design doc.