## What this clears
**30 of the 55 failures** in the dashboard `app:backfill 3/4` shard —
all in one file, all reading `expected null to be truthy`.
## The symptom points the wrong way
That message reads as *"the modal never rendered"*, and that is how this
survived. The file's helpers took the `container` returned by `render()`
and asked it for the modal's elements:
```ts
const header = container.querySelector("[data-testid='agent-log-model-header']");
```
`TaskDetailModal` mounts inside `FloatingWindow`, which uses
**`createPortal`** — so the modal subtree is attached to
`document.body`, **not** beneath the container React handed back. Every
`container.querySelector` in the file returns null no matter what
renders.
## Probed, not inferred
I had already spent one wrong hypothesis on this exact file — the shared
`TaskDetailModal.test-helpers.ts` carries a genuinely stale `{
flagEnabled: false, workflows: [] }` fixture of the kind #2833 fixed for
`App.test.tsx`, so it looked like the 30-failure lever. Adopting
`DEFAULT_BOARD_WORKFLOWS` **changed nothing** (still 30 failed).
Reverted.
So I instrumented instead:
```
P1_after_tab_click menu=true items=["Live","Feed","Raw","Interventions"]
P2_after_select viewer=true header=true empty=false
```
The Activity menu opens, `Raw` selects, and the viewer **and** its model
header are both present — via `document`. Only the container-rooted
lookup could not see them.
**Why the file half-worked:** `screen.getByRole(...)` in the same
helpers always succeeded, because `screen` queries the document. That
mix of query roots is what made a query-root bug look like a rendering
fault.
19 `container.querySelector` call sites converted.
## Scope — deliberately narrow
**Only this file.** Eight other `TaskDetailModal` specs use
`container.querySelector` too — 95 of them in `attachments-and-tabs`
alone — and they **all pass today**, because they render
`TaskDetailContent` rather than the portalled modal. Converting green
files would be churn with real risk and no red to justify it.
## Evidence
| | result |
|---|---|
| the file | **48/48** (was 30 failed) |
| shard `3/4` | **55 → 25** failures |
| mutation: rename the `agent-log-model-header` testid in
`AgentLogViewer` | **18 failed** |
The mutation matters here: the fix is "change what we query", so the
risk is assertions that now find *something* and stop being
load-bearing. They still observe the real component.
`pnpm lint` clean. Test-only; `AgentLogViewer.tsx` restored clean.
## Remaining in this shard
`settings-mobile` (17), `NodesView` (2), `MailboxModal` (2),
`agent-modals-mobile` (2), `TaskDetailModal.pr-tab` (1),
`onboarding-flow` (1). Tracked on #2784, which I have been keeping
current with per-lane numbers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>