Skip to content

Cover the Brain Explorer panes and fix two routing bugs - #956

Merged
selfcontained merged 2 commits into
mainfrom
agt_f33a9b9eae63/job-test-enforcer-a0a57f77
Aug 14, 2026
Merged

Cover the Brain Explorer panes and fix two routing bugs#956
selfcontained merged 2 commits into
mainfrom
agt_f33a9b9eae63/job-test-enforcer-a0a57f77

Conversation

@selfcontained

Copy link
Copy Markdown
Owner

Recurring Test Enforcer run. Local suite was green on first pass (26th consecutive), so the run went to the next_focus coverage target — the last two zero-coverage surfaces from the #925 brains split. The coverage work turned up two real product bugs, both fixed here.

Product bugs fixed

Dead redirect on a malformed repo root. BrainsDetailPane recovered from an undecodable base64url repo root by calling navigate() during render. React Router v7 refuses imperative navigation during render — it logs You should call navigate() in a React.useEffect() and no-ops (verified with a probe). So the pane rendered the overview while the broken URL stayed in the address bar, came back on reload, and survived in a shared link. Now a declarative <Navigate to="/automations/brains" replace />.

Double-decoded collection param. selectedCollection={collection ? decodeURIComponent(collection) : null} decoded a path param react-router had already decoded. A collection named 50%off threw URIError and took the whole pane down; one named %41 silently selected a collection that does not exist and rendered it empty. Both names are reachable — collection names come from agents, and the sidebar links to whatever exists. Now collection ?? null. There are no other decodeURIComponent call sites in apps/web/src, and every producer of that segment already goes through encodeURIComponent, so encode/decode is symmetric.

Coverage added

brains-detail-pane.test.tsx (19 tests) mounts the pane on the same three routes the real router declares, so useParams behaves exactly as in production. It pins the repo-root decode and its malformed fallback, the collection round trip, pill counts and the active marker, search wiring, and the destructive "Clear project" flow — wire contract, summed toast, failure path, and pending gating. 20/21 mutants killed. The survivor is the collectionsLoading guard, which is unobservable in both branches because the query's data already defaults to []; it is recorded as a dead guard for a future run rather than papered over with a test that cannot fail.

brains-pane.test.tsx (14 tests) pins the encode half of the same URL contract plus list states, per-type count gating, keyboard activation, and the selection highlight. 19/19 mutants killed.

No new E2E test: e2e/brains-page.spec.ts already drives this route in a real browser, and the two fixes are unit-observable.

Review

One general review agent inspected the diff. Its substantive findings were fixed in the follow-up commit: the first battery never mutated the { replace: true } flags, so nothing guarded the back-button-trap half of the redirect fix — a navigation-type probe now pins REPLACE on all three redirects and PUSH on ordinary pill navigation. It also caught a test that could not fail, a duplicated sidebar test, and a keyboard test that reused a DOM node captured before its own route change.

Validation

pnpm run check, pnpm run format (clean on a warm tree), pnpm run finalize:web, pnpm run test (server 2733 passed / 9 skipped, web 875, extension 60, scripts 4), pnpm run test:e2e (180 passed / 12 skipped), pnpm run test:e2e:live (11 passed, 20.8s, zero leaked e2e-* tmux sessions).

CI scan of the last 50 runs: 49 success. The one failure is the Release workflow's own origin/main advanced after smoke tests guard firing during a merge race — not a test failure. No CI-only flakes found; the flakes list stays empty.

🤖 Generated with Claude Code

selfcontained and others added 2 commits August 13, 2026 20:22
Closes the last two zero-coverage surfaces from the #925 brains split, and
fixes two real bugs the coverage work surfaced in brains-detail-pane.tsx.

A malformed base64url repo root recovered by calling navigate() during
render. React Router v7 refuses imperative navigation during render — it
warns and no-ops — so the undecodable root stayed in the address bar and
came straight back on reload or from a shared link. It is now a declarative
<Navigate replace />.

The collection path segment was decoded a second time on the way to the
collection view, but react-router has already decoded it. A collection named
"50%off" threw URIError and took the pane down; one named "%41" silently
selected a collection that does not exist. Both names are reachable — the
sidebar links to whatever collection an agent created.

brains-detail-pane.test.tsx (20 tests) mounts the pane on the same three
routes the real router declares and pins the repo-root decode and its
malformed fallback, the collection round trip, the pill counts and active
marker, the search wiring, and the destructive "Clear project" flow
including its wire contract, summed toast, failure path and pending gating.
16/17 mutants killed; the survivor is the collections loading guard, which
is unobservable because the query's data already defaults to [].

brains-pane.test.tsx (14 tests) pins the encode half of the same URL
contract plus the sidebar's list states, per-type count gating, keyboard
activation and selection highlight. 18/18 mutants killed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The first battery never mutated the { replace: true } flags, so nothing
guarded the half of the malformed-root fix that matters most: pushing
instead of replacing leaves the undecodable URL one Back press away, and
going Back redirects forward again — a trap. A navigation-type probe now
pins REPLACE on all three redirects and PUSH on ordinary pill navigation.

Deleted the loading-pills test. It could not fail: useBrainCollections
already defaults data to [], so both collectionsLoading guards are
unobservable, and the assertion filtered for a collection no fixture
declared. The dead guards are recorded for a future run rather than
covered by a test that certifies nothing.

Renamed the post-delete test to the navigation it actually protects —
leaving the project unmounts the dialog either way, so that test cannot be
what proves the dialog closes.

Also: dropped a sidebar test that duplicated the routing case, split the
Enter/Space test so neither reuses a node captured before its own route
change, tightened the pill count assertions to exact text, relaxed the
skeleton count to presence, and stubbed Toaster alongside toast.

Batteries after the changes: 20/21 on brains-detail-pane.tsx (the survivor
is the proven-unobservable loading guard) and 19/19 on brains-pane.tsx.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@selfcontained
selfcontained merged commit 037f460 into main Aug 14, 2026
1 check passed
@selfcontained
selfcontained deleted the agt_f33a9b9eae63/job-test-enforcer-a0a57f77 branch August 14, 2026 02:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant