l-broad-walk-test
Multi-pass exhaustive bug-hunting sweep of the zudo-text app via observation subagents driving `pnpm dev:mock` in a headless browser. Use when (1) the user says "walk around the app, find problems", "...
l-broad-walk-test
When to use vs. when not to use
Use this skill for periodic open-ended sweeps — a milestone, a release-prep check, a "we just fixed 20 issues, walk again and see what's left."
Don't use this skill for:
A specific user-reported bug → use
/instead. That skill seeds with the user's actual settings, writes a regression spec, and locks the fix.l- agent- walk- test Verifying one CSS change → use
/.verify- ui Code review of a PR → use
/ordeep- review /.codex- review
The output of this skill is GitHub issues filed, not code changes. Do not let it slide into "found a bug, let me also fix it" — the value is the breadth of coverage, which collapses if you stop to fix mid-sweep.
The pattern
Parent (you) ──┬─ Pass 1 ─→ subagent walks focus area → markdown report → file issues
├─ Pass 2 ─→ subagent walks different focus area → report → file issues
├─ Pass 3 ─→ ... (4–5 passes total)
└─ End: summary table of all filed issuesEach pass takes roughly 10–15 minutes of subagent wall time. Total session ~1 hour. Expect 15–30 issues filed per full sweep.
Phase 1 — Prep
1.1 Start dev:mock
lsof -ti :1421 >/dev/null || pnpm dev:mock > /tmp/devmock.log 2>&1 &
sleep 6
curl -sI http://localhost:1421/ | head -1 # expect "HTTP/1.1 200 OK"dev:mock occasionally dies under sustained subagent activity (SIGKILL'd by the kernel after long sessions). If a pass reports the server stopped responding, restart it before the next pass.
1.2 Confirm the seed fixture exists
The project's canonical "realistic user state" is e2e/. Subagents will inject it via the same path / uses:
const fs = require("node:fs");
const seed = JSON.parse(fs.readFileSync("/home/takazudo/repos/myoss/zudo-text/e2e/fixtures/prompts-app-user-seed.json", "utf8"));
seed.editor = { ...(seed.editor || {}), vimMode: false }; // important — see Phase 2 gotchas
await context.addInitScript((data) => {
try { window.localStorage.setItem("e2e:mock-settings-seed", JSON.stringify(data)); } catch {}
}, seed);
await page.goto("http://localhost:1421/");The seed mutation vimMode = false matters: with vim mode on, every pressSequentially keystroke is interpreted in vim, producing garbled content. Disable it before every pass unless the pass is specifically testing vim.
1.3 Check existing open issues (avoid duplicates)
gh issue list --repo zudolab/zudo-text --state open --limit 50 --json number,title --jq '.[] | "\(.number) \(.title)"'Read the titles. As you file new issues across passes, mentally append them to this list so the next pass's filing step can dedup. The subagent doesn't see your filed-issues list, so you (the parent) must enforce dedup discipline.
Phase 2 — Pass focus areas
A full sweep is 4–5 sequential passes. Each pass has a curated focus. Don't try to put everything into one pass — the subagent's report degrades after ~10 scenarios.
Suggested pass plan
| Pass | Focus | Example scenarios |
|---|---|---|
| 1. General | Cold load, header pins, settings dialog, frameset switcher, drafts/archives round-trip, empty-frame picker | Discovers obvious surface bugs first |
| 2. Mobile + palette + drafts | 375×812 viewport (overflow, full-bleed dialogs), Quick Actions popover, command palette, drafts CRUD, color theme switch, settings save & reload | Stress narrow widths and stateful UI |
| 3. Boards + frameset + archive | Kanban / Mind Map / TODO Board picker hints, draft archive flow, display-scale and window-opacity, Spotlight picker on non-Mac, markdown directive rendering | Hits parser-vs-UI mismatches |
| 4. Settings dialog sections | Walk each of the ~20 sections in the left tree: Aliases, Move Buttons, AI Provider, Sync, Notifications, Workspace, Frontmatter Schema, Device Override, Menu Bar, Raw Settings, etc. | Highest issue-density pass historically |
| 5. View providers + features | Find-in-page, Search messages, Diff View, EFE embedded file tree, Related Notes, Notify List, External File Editor, drag-and-drop into editor, long-content stress, Authoring help / Assets | Last pass — fills in the gaps |
Pick the passes that fit the session. If you only have time for 3 passes, drop pass 2 (the mobile-specific findings tend to be the most independent).
Optional later passes (when needed)
Vim mode — modes, registers, marks, complex commands,
:ex-commands.Inline AI skills — creating workspace + user skills, hot-reload, autocomplete.
Sync end-to-end — mock backend WebSocket flow, encryption-key derivation, conflict resolution.
Multi-workspace — chooser sidebar, workspace switching,
bridge.workspace.registercontract.
Phase 3 — Subagent brief shape
Each pass dispatches via the Agent tool with subagent_type: "general-purpose". The brief follows a stable template — keep the shape consistent across passes so you can compare reports.
Brief template (parameterised by pass number N + focus)
## Goal
PASS-N bug-hunting walkthrough of zudo-text. Prior passes filed <COUNT> issues
across <prior-focus>. **This pass: <THIS-FOCUS>.**
**Do not diagnose root causes. Do not fix anything.** Observe, screenshot,
factually report.
## Setup
- Mock backend at http://localhost:1421/ (already running).
- Fixture seed: /home/takazudo/repos/myoss/zudo-text/e2e/fixtures/prompts-app-user-seed.json.
- Disable vim mode in the seed before injection (seed.editor.vimMode = false).
## Browser
`/headless-browser` skill (Playwright CLI), Chromium. Close the browser between
scenarios to avoid the dev:mock SIGKILL pattern seen in long sessions.
Save under $HOME/cclogs/zudo-text/walkthroughN-$(date +%Y%m%d-%H%M%S)/.
Driver scripts under __inbox/walkthroughN/. Both gitignored.
## Seeding snippet (verbatim)
<paste the seeding snippet from Phase 1.2>
## Scenarios
<list 6–10 numbered, lettered scenarios with HIGH/MEDIUM/LOW priority tags>
<each scenario: what to do + what to capture>
## Capture per scenario
### Scenario X: name — [pass | fail | partial | couldn't-reach]
- Seed used: <default | fixture | mutated-fixture>
- URL flow:
- aria snapshot (≤60 lines, only the relevant section):
- Console (unexpected lines only — ignore `[backend-bridge] mock` and
`FrontmatterSchemaContext: files.readText not supported in mock mode`):
- Screenshot: <path>
- Observations: <factual>
## Output
End with:
## Likely bugs
1. <one-line symptom> — Evidence: <scenario letter + obs> — Severity: <cosmetic | functional | data-loss | crash>
...
## Defer / file as issue
- <lower-priority notes>
## Constraints
- ≤ 15 min wall time. Skip scenarios that hang > 1 min.
- ≤ 2500 words total report.
- No code fixes. No keyboard shortcuts unless the shortcut engine has been
verified to respond (test once early in the pass; abandon shortcut paths
if it doesn't).
- Don't commit anything. Don't push.
When done, return the full markdown report. Why "observe, don't diagnose"
The subagent is told not to diagnose root causes. That keeps the report factual and forces YOU (the parent) to verify each finding against the codebase before filing — which catches the cases where the subagent's hypothesis is wrong. The skill / calls this out as well:
Don't trust the subagent's hypothesis — it was told not to diagnose. You verify.
For high-impact findings (functional/data-loss severity), spawn an Explore-subagent to trace the finding to a specific file/line before filing the issue. For cosmetic findings (label truncation, duplicate titles), the screenshot + DOM probe in the report is enough.
Phase 4 — File issues (one pass at a time)
After each pass's report lands:
Pick the findings worth filing. Not every observation is an issue — some are mock-only artefacts (the SpotlightPicker on Linux), some are duplicates of prior passes (recurring
FrontmatterSchemaContextwarnings). Cut these aggressively or fold them into existing issues.Verify high-impact findings. Map functional/data-loss findings to a specific file/line via
Exploreor directRead+grepbefore filing.Batch-upload screenshots, then file.
TS=$(date +%Y%m%d_%H%M%S)
upload() {
local kind="$1"
local src="$2"
local unique="${TS}-${kind}.png"
cp "$HOME/cclogs/zudo-text/walkthroughN-<TIMESTAMP>/$src" "/tmp/${unique}"
gh release upload _attachments "/tmp/${unique}" --repo zudolab/zudo-text --clobber 2>&1 | tail -1
rm "/tmp/${unique}"
echo "${kind}: https://github.com/zudolab/zudo-text/releases/download/_attachments/${unique}"
}
upload <kind-1> <src-1.png>
upload <kind-2> <src-2.png>
# ...Then for each issue, call gh issue create --repo zudolab/zudo-text --title "<title>" --body "$(cat <<'EOF' ... EOF)". The gh-issue-with-imgs skill is the canonical flow — its _attachments release tag is reused across the whole sweep.
Issue body structure — copy this shape for every issue:
## Summary
<one-paragraph plain-English description>
## Steps to reproduce
1. ...
2. ...
<screenshot embedded>
## Expected
<what should happen>
## Severity
<cosmetic | functional | data-loss-adjacent | crash>
## Notes
- Discovered during a `/l-broad-walk-test` walkthrough session.
- Repo branch at the time of repro: <branch> @ <short-sha>.
- Likely lives in <file or package guess>.Consistent structure makes the resulting issue stream skimmable when the user comes to triage it.
Group findings that share a root cause into one issue with subsections (e.g. "Related Notes + Search + Notify List all render duplicate titles because the view component duplicates the frame-chrome banner"). One root cause, one issue, three repro variants.
Defer with intent. Some findings are notable but lower-priority than the current sweep is meant to cover (e.g. "subagent saw a typo in a help-text string"). Keep these in the in-conversation notes for a follow-up pass rather than filing tiny issues that bury the high-impact ones.
Phase 5 — End-of-sweep summary
After the last pass:
Stop dev:mock:
kill $(lsof -ti :1421) 2>/dev/null.Print a session-summary table for the user, grouped by severity:
## Session totals: <N> issues filed **Functional / high impact (X):** #1830, #1831, #1835, #1836, #1854, ... **Functional / medium (Y):** #1827, #1842, #1844, ... **Cosmetic / quality (Z):** #1828, #1832, #1840, #1843, ... **Feature gap (W):** #1839, #1849, ...Don't file a "summary issue". The individual issues are the artefact. A summary issue duplicates information and rots.
Don't write a regression spec. That's
/'s job. This skill stops at "issues filed". The user (orl- agent- walk- test /) will pick which issues to address and write regression specs as part of those fixes.big- plan Mention the next sweep date / trigger in the summary so the user has a natural off-ramp: "When the high-impact issues are fixed, re-run
/to confirm no regressions and surface the next layer of findings."l- broad- walk- test
Pitfalls and lessons (from past sweeps)
Subagent reports occasional non-determinism that's actually observation timing. Past sweep #1 reported "Terminal selected on first load, Search on second" — code-read confirmed the picker is deterministic; the subagent's snapshot landed at a different render moment. Treat single-observation non-determinism reports as "needs re-walk to confirm" rather than auto-filing.
dev:mock SIGKILL under heavy load. Long sessions of
pressSequentially+ dialog interactions can trigger an OOM-style kill of the vite process. Restart between passes. If a single pass dies mid-flight, the subagent will report which scenarios completed — keep those, drop the rest, and rerun the partial pass.The "shortcut engine" isn't reliable in headless Chromium.
Ctrl+K,Ctrl+,, etc. often don't reach the shortcut engine. Test once early in a pass (open Settings via the gear button on the toolbar instead ofCtrl+,). If a pass needs shortcuts, accept the reduced coverage.Mock-mode warnings already filed are noise.
[FrontmatterSchemaContext] files.readText not supported in mock modeshows up on every page load and was filed once (#1828 in the first sweep). Don't refile.Console suppression list to apply. Tell the subagent to filter:
[backend-bridge] mocklines (every backend call logs one)[FrontmatterSchemaContext] files.readText not supported in mock modeDownload the React DevToolsdev warnings Anything else is potentially a finding.
Issue title style. Short, specific, end-loaded with the symptom. "Settings → Shortcuts:
Go to Inboxchip renders with danger border, no error text" — not "Shortcut chip styling issue". The next sweep's parent agent reads issue titles to dedup; specificity helps.Don't try to combine
/'s regression-spec writing with this skill. The two are deliberately separate. This skill is broad-and-shallow;l- agent- walk- test /is narrow-and-deep. Conflating them dilutes both.l- agent- walk- test
Reference
Sibling skill:
/for specific user-reported bugs.l- agent- walk- test Issue-filing helper:
/.gh- issue- with- imgs Browser driver:
/.headless- browser Canonical seed fixture:
e2e/.fixtures/ prompts- app- user- seed. json Mock entrypoint:
tauri-(readsapp/ renderer/ main- mock. tsx localStorage["e2e:mock-settings-seed"]at startup).Working example: the 2026-05-18 sweep that filed 26 issues (#1827, #1828, #1830-#1833, #1835-#1840, #1842-#1849, #1854-#1859). Each pass's screenshots live under
$HOME/(gitignored). The pattern, the focus areas, the issue body shape, and the dedup discipline all come from that sweep.cclogs/ zudo- text/ walkthrough{1. . 5}- */