Validating Changes in the Browser
This skill is the last station before a ticket is shipped. It is invoked only after the implementation is complete and the relevant review step has succeeded — not as a substitute for either, but as the final user-eye check that catches the things a unit test, an API test, or a static review cannot see: broken empty states, missing toasts, focus traps, regressed flows on roles the developer didn't think to test, console errors, layout glitches, latent bugs in sibling pages that the change accidentally exposed.
The orchestrator runs the test list itself via Chrome DevTools MCP. Whatever it finds — including issues that pre-date the current branch — is fixed in the same loop. The user only sees the final list, fully ticked, with a question: ship or optimize further.
Language convention for this skill:
- The instructions you read here (English) tell you HOW to run the workflow.
- The artefacts the developer sees at the end (test plan headings, walked list, status labels, ship-or-optimize question and options) are rendered in the language the user has been speaking in this session — German if the conversation has been in German, English if in English, the user's language otherwise. The English examples below are illustrative templates; translate the headings, columns, action prose, status labels, and the AskUserQuestion text+options to match the user's language before showing them.
When to Use This Skill
Activates at the end of these workflows (invoked from each):
/lt-dev:resolve-ticket — after the review-pipeline guidance, before /lt-dev:dev-submit
/lt-dev:take-ticket — inside STEP 10 (Review-Ready Summary), before handoff
/lt-dev:ticket-cycle — between Phase B (review) and Phase C (ship)
/lt-dev:review — as the final Phase 7, after Phase 6 decision & fix-execution
/lt-dev:debug — after Step 7 (fix implementation) succeeded
/lt-dev:production-ready — as the final phase, after CI validation
building-stories-with-tdd skill — at the end of Step 5b (Final Validation)
branch-rebaser agent — after Phase 10 (Code Review) succeeded
NOT for
- Skipping the implementation step (use the relevant dev workflow first)
- Skipping the code review (use
/lt-dev:review first)
- Running automated E2E tests — Playwright lives in
lt dev test / CI and runs separately; this skill is for the human-shaped flows that automated tests miss
- Smoke testing a fresh
git pull you didn't touch — only relevant when there is a diff to validate
Hard Rules
- Run the list yourself first. The list shown to the user is the walked list, not a draft. Every check must have been executed via Chrome DevTools MCP (or, for non-UI tickets, the documented manual equivalent) before the user sees it.
- Fix everything you find, including pre-existing issues. A console error that was already on
main is still a console error on this branch — patch it as part of the validation loop and surface it in the summary as "also fixed" (translated to the user's session language).
- No silent skips. If a step cannot be tested (e.g. the project has no app, the change is backend-only and no UI consumes it yet), declare that explicitly in the list — don't omit the step.
- Never reuse production data. Seeds use
@test.com emails and clearly fake names so they're filterable / wipeable.
- Never leave dev servers orphaned. Follow managing-dev-servers for start + stop semantics. If you used
lt dev up, leave it up only if the user wants to continue testing manually.
- Account visibility is mandatory. Every step that requires a login MUST explicitly name the account (email, password, role). The developer reads the list as their own re-walk manual — they must be able to log into the stack without follow-up questions. This applies to both reused seed accounts AND newly-created accounts. For public/unauthenticated steps, mark them explicitly as
Account: no login (public / incognito) (translated to the user's session language) instead of omitting the field.
- Ticket context block is mandatory. Every walked list begins with a short context block stating (a) what the task / bug was in 1–3 sentences ("task summary"), (b) how it was implemented or fixed in 1–3 sentences plus the most-relevant
file:line references ("implementation summary"), and (c) the ticket link when the originating workflow knows one (Linear URL, GitHub issue URL, file path of a *.md story). The user uses this block to orient themselves before re-walking — they should not need to switch context to remember what the branch is about.
- URL-per-step is mandatory for UI steps — as a clickable markdown link. Every step that touches a browser route MUST carry the fully-qualified URL the user navigates to, rendered as a clickable markdown link so the user clicks straight from the list (e.g.
URL: [users/new](https://<slug>.localhost/users/new)). The session renders GitHub-flavored markdown, so [label](url) is clickable in the terminal / VS Code. Deep links (with query params, route params, or hash fragments) keep the exact form you used during the walk inside the link target. For non-UI steps (backend smoke pass, CLI flow), record the equivalent locator (curl URL + method, command line). Omit only when the step is genuinely location-less.
- The user's final answer is binary in spirit: ship or optimize further. The
AskUserQuestion at the end always offers both — never end the workflow without that gate.
- Keep the browser lean and close it when the walk ends. Reuse a single Chrome DevTools MCP page across steps (
navigate_page, not a fresh new_page per step); open a second tab only when a step truly needs two contexts at once, and close_page it immediately after. When the walk concludes — on every AskUserQuestion outcome — close every page you opened via close_page so the MCP releases the Chrome instance, even when you leave lt dev up running for the user's own re-test (they use their own browser). Browser-close is independent of the dev-server keep/stop decision. See managing-dev-servers.
Workflow
Step 1 — Decide whether this step applies at all
Skim the diff (git diff <base>...HEAD --name-only):
- At least one file under
projects/app/, packages/app/, app/, **/*.vue, **/*.svelte, **/*.tsx, or any frontend route directory → full browser pass mandatory.
- Backend-only diff (
projects/api/, src/server/, etc.) that exposes a new/changed endpoint:
- If a frontend consumer exists in the same repo → still do a browser pass (the new endpoint will manifest in the UI somewhere).
- If no consumer exists yet → reduce to an API smoke pass: hit each new/changed endpoint with
curl against https://api.<slug>.localhost (or the active API URL from lt dev status) at three role levels (Admin, regular User, unauthenticated) and assert the response matches the documented contract. Skip the UI portion explicitly in the list.
- Pure tooling / config / CI diff (no runtime impact): log "No browser test required — diff has no runtime impact" (translated to the user's session language) and exit cleanly. Do NOT skip the user gate, even here — they still get the closing question to confirm "ship".
Step 2 — Boot the application
Follow the managing-dev-servers decision tree. Short version:
- If the prompt contains an "Active lt-dev project" block with
session: yes → already running, use the URLs from the block.
- If the block says
session: no → run lt dev up and wait until https://<slug>.localhost answers 200 OK.
- If the block says "lt-Stack project detected — not yet migrated" → run
lt dev init first (idempotent — also chains lt dev install if needed), then lt dev up.
- If no block is injected → non-lt project. Start the project's documented dev server via
run_in_background: true (e.g. pnpm dev) and pkill it at the end. Use the documented localhost ports.
Never start pnpm dev / pnpm start directly when an lt-dev context block is present — that bypasses Caddy and re-introduces cross-wiring risk.
If the boot fails (port collision, missing CA trust, DB not running): run lt dev doctor and resolve before continuing. Do NOT walk the list against a half-broken stack.
The stack is scoped to the project, not to your session. lt dev up serves one <slug> with one dev database (<slug>-local), so a parallel Claude Code session in the same project shares both. Three consequences:
session: yes may mean a peer started it. That is fine, use it. But it means lt dev down at the end of your walk stops a stack somebody else is mid-walk in. When a peer is live in this project (ListAgents), leave the stack up and say so instead.
- A reseed is destructive for the peer too. Step 3 writes into the shared dev database. Wiping and reseeding pulls the ground out from under a peer's logged-in session. Add your data alongside theirs, or send one
CONFLICT and agree who owns the database for the next few minutes.
- The isolated
lt dev test stack has none of this problem. It runs its own <slug>-test database and its own URLs, so an E2E suite never disturbs a peer's walk. Prefer it whenever the walk does not have to happen against the dev data.
The Chrome DevTools MCP itself needs no coordination: each session spawns its own chain and its own Chrome, so tabs never cross. What does cross is pkill on chrome or node, and the cleanup-stale-chrome-mcp hook, which reaps any chain older than CHROME_MCP_MAX_AGE_HOURS (72 by default) that is not its own session's — including a peer's, mid-walk. See coordinating-peer-sessions.
Step 3 — Seed realistic test data + cover every role
The seed data is for you — Chrome DevTools MCP will log in as it, navigate as it, click as it. Make it realistic enough that the flows the user cares about actually fire (a list view needs items, a role-gated action needs the right role, a dashboard needs numbers).
Choose the cheapest seed path that produces the required data:
- Project provides a seed script (
pnpm run seed, pnpm db:seed, scripts/seed.ts, etc.) → run it. Read it first to know which accounts it produces and what their credentials are — you MUST surface those credentials to the user later.
tests/fixtures/ contains a seed fixture → adapt it inline or pipe it via the API. Same rule: read the fixture to know the credentials.
- No seed infrastructure exists → create accounts + entities yourself via Chrome DevTools MCP (sign-up flow) OR via direct API calls (
testHelper-style, but ad-hoc — curl https://api.<slug>.localhost/auth/signin -d '{...}'). You pick the passwords; record them.
Seed rules:
- Emails end in
@test.com so the cleanup regex picks them up later (consistent with building-stories-with-tdd).
- Names are obviously fake (
Test Admin, Test User One) — never realistic personally-identifying strings.
- Cover every role you will test against. For a permission-matrix ticket, that means one account per role mentioned in the matrix from the implementation step. If the matrix lists
Admin, User, Guest, and a custom Reviewer role, you create or reuse four accounts.
- Cover the entity states the diff touches. A list-view change needs ≥3 items including edge cases (long string, missing optional field, special characters). A status-driven flow needs items in each status (draft / sent / archived / etc.).
- Use a single, memorable password scheme across all accounts (e.g.
TestPass123!) — so the user can re-walk fast without juggling passwords. Never write "see seed" or "default password" — always write the literal value.
Maintain an account registry in your working notes from this step onwards. For every account you reuse or create, record: email, literal password, role, and provenance (existing seed vs NEW for this walk). The registry feeds the test-list header AND the closing summary — the user needs every credential visible to reproduce the walk. Translate the provenance labels to the user's session language when rendering.
Step 4 — Derive the step-by-step test list from the diff
Build the list from the actual diff, not from a generic template. For every changed or newly-added surface, generate one or more concrete check steps.
Account-per-step is mandatory. Every step in the list explicitly names which account is used:
- For login-required steps →
Account: <email> (the account from the registry built in Step 3).
- For public / unauthenticated routes →
Account: no login (public / incognito) (translated to the user's session language).
- For multi-role flows (e.g. "Admin approves, User sees result") → split into separate steps, one per role, each naming its account.
Never leave the account implicit — the user reads the list as their own re-walk manual.
Render the test plan in the language the user has been speaking in this session. The English template below is illustrative — translate the headings, account-list labels, and step prose when you produce the actual output. Always include the ticket-context block (task summary + implementation summary + ticket link) and a URL: field per UI step, rendered as a clickable markdown link [<route>](https://…):
Test Plan: <Ticket-ID / Feature Name>
Ticket
- Link : <Linear URL / GitHub issue URL / file:path-to-story.md, or "no ticket — ad-hoc fix">
- Task : <1–3 sentence summary of what needed to happen — copied / paraphrased from ticket>
- Done by : <1–3 sentence summary of how it was implemented or fixed, with the most-relevant file:line refs>
Server : https://<slug>.localhost (App) / https://api.<slug>.localhost (API)
Accounts for this walk
- admin@test.com / TestPass123! / Admin / existing seed
- user1@test.com / TestPass123! / User / NEW for this walk
- guest@test.com / TestPass123! / Guest / NEW for this walk
- (no login) / — / — / public routes
Steps
[ ] 1. <Page / Flow / Component> — Account: <email> — URL: [<route>](https://<slug>.localhost/<route>) — <concrete action> — <expected result>
[ ] 2. <Page / Flow> — Account: no login (public) — URL: [<public-route>](https://<slug>.localhost/<public-route>) — <action> — <expectation>
[ ] 3. <Backend smoke> — Account: <email or "anonymous"> — URL: POST https://api.<slug>.localhost/<endpoint> (curl) — <action> — <expectation>
[ ] 4. ...
Coverage rules (apply each that fits the diff):
- Every changed page / route → at least one check that navigates to it and confirms it renders without console errors, hydration mismatches, or 4xx/5xx network calls.
- Every changed component used in multiple places → check each callsite, not just one. Use
git grep against the component name to find them.
- Every new / changed form → check (a) happy path submit, (b) at least one validation error, (c) the loading state, (d) the success feedback (Toast / redirect / inline confirmation).
- Every new / changed list view → check (a) populated state, (b) empty state, (c) error state (force by killing the API or injecting a 500 via
evaluate_script), (d) pagination edge if applicable.
- Every role / permission matrix row from the implementation step → log in as that role using the account from the registry, attempt the action, assert allow / deny / partial as documented.
- Every destructive action → confirm the confirm-dialog is present, the button is red / clearly destructive, and the action is reversible (or explicitly not).
- Every navigation change (new route, redirect, breadcrumb update) → walk it from the entry point the user would actually use, not just direct URL.
- Mobile viewport pass at the end:
resize_page to 390×844, walk the top 3–5 most-affected pages again, confirm no overflow / unreachable buttons / collapsed-menu regressions.
- Console + network pass at the end: take a final
take_snapshot, list_console_messages, and list_network_requests on the most-changed page. Any error / warning level console message or failed network request → finding.
For non-UI tickets (backend-only, no consumer): the list is shorter — endpoint, role, expected status code, expected schema. Same rigor on account visibility (which role is used per request).
Step 5 — Walk the list yourself
For each step, drive Chrome DevTools MCP using the mcp__plugin_lt-dev_chrome-devtools__* tools (NOT the Playwright-based browser MCP — see managing-dev-servers).
Tab economy: open the app once with new_page, then drive every subsequent step by navigate_page on that same page — do not open a fresh tab per step. Spawn a second tab only when a step genuinely needs two contexts at once (two roles side-by-side, an OAuth / popup window), and close_page it the moment that step is done. list_pages shows what is open. See managing-dev-servers → Chrome DevTools MCP — Browser-Tabs & Cleanup.
Typical tool calls per step intent:
- Open the app →
new_page with the URL from Step 2 (once — reuse it via navigate_page afterwards).
- Sign in as a role →
fill_form on the login form using the credentials from the registry built in Step 3.
- Navigate →
navigate_page (prefer over a new tab).
- Click / interact →
click (with take_snapshot first to get stable selectors), fill, press_key, hover, drag.
- Verify state →
take_snapshot (DOM tree) + take_screenshot (visual confirmation).
- Inspect console →
list_console_messages after the action.
- Inspect network →
list_network_requests after the action.
- Force an error →
evaluate_script to throw / mutate a request / mock a 500.
- Mobile pass →
resize_page to 390×844, repeat the relevant steps.
- Run a Lighthouse a11y / perf snapshot →
lighthouse_audit on the most-changed page.
After each step, mark the checkbox only if the step actually passed. If it failed → Step 6.
Step 6 — Fix everything you find, then re-walk
Findings during the walk include:
- A new or pre-existing bug (broken button, wrong text, 500 on a side-effect endpoint, layout overflow, ...).
- A console error or warning. Treat warnings as findings unless they are documented third-party noise.
- A network failure (4xx other than expected 401/403, 5xx, CORS error, slow request > 2s for a non-load-heavy endpoint).
- A regressed empty / loading / error state.
- An a11y violation surfaced by Lighthouse (focus order, missing label, contrast).
- A mobile regression (overflow, unreachable button, broken menu).
For each finding:
- Diagnose root cause by reading the relevant code (the component, the page, the composable, the controller / service if backend).
- Fix it — including if it pre-dates the branch. Use the same editing rules the originating workflow has been using (TypeScript strictness, no
--no-verify, no @ts-ignore).
- Note it in working memory as "also fixed" (translated to the user's session language) — these will surface in the final summary so the user knows the branch did more than just the ticket.
- Re-walk the affected step to confirm green.
- Re-walk dependent steps too — a fix to a shared composable might affect other pages.
Stall guard: if the same finding fails to converge after 3 fix attempts, stop the loop, write a structured diagnosis (file, observation, attempted fixes, current hypothesis), and surface it as a blocker in the final summary. Don't ship a known-broken state silently.
If a finding is truly out-of-scope and high-risk to fix in this branch (e.g. a multi-day refactor of a shared module), name it in the final summary in one line, translated to the user's session language, and leave it there. Do not open a ticket for it as a matter of course — a walk that leaves a trail of follow-up tickets behind every ticket is how one day's work becomes a backlog. A ticket is filed only where the finding clears Part 0 of filing-ai-proposed-tickets: demonstrated, standalone, and genuinely worse left undone. Then it goes through that skill in full — duplicate search first, Triage state, AI label. Everything else is a line in the summary, and the user decides.
Step 7 — Show the user the walked list
Render the final list (every step ticked) in a structured block. Repeat the ticket-context block AND the account registry verbatim so the user can re-walk from a single screen without scrolling back. Each executed check carries its URL: field again so the user can click straight to the page. Render in the language the user has been speaking; the English template below is illustrative:
╔══════════════════════════════════════════════════════════╗
║ Manual Browser Walk: <Ticket-ID / Feature> ║
╚══════════════════════════════════════════════════════════╝
Ticket
- Link : <Linear URL / GitHub issue URL / file:path-to-story.md, or "no ticket — ad-hoc fix">
- Task : <1–3 sentence summary of what needed to happen>
- Done by : <1–3 sentence summary of how it was implemented or fixed, with the most-relevant file:line refs>
Stack
- App: <URL>
- API: <URL>
- DB: <slug>-local (seed data: @test.com)
Accounts (re-walk credentials — log in with these)
- admin@test.com / TestPass123! / Admin / existing seed
- user1@test.com / TestPass123! / User / NEW for this walk
- guest@test.com / TestPass123! / Guest / NEW for this walk
- (no login) / — / — / public routes
Executed checks
[x] 1. <Step> — Account: <email> — URL: [<route>](https://<slug>.localhost/<route>) — Observation: <short note on what actually happened>
[x] 2. <Step> — Account: no login — URL: [<public-route>](https://<slug>.localhost/<public-route>) — Observation: ...
[x] 3. <Step> — Account: <email> — URL: POST https://api.<slug>.localhost/<endpoint> (curl) — Observation: ...
Also fixed during the walk
- <file:line> — <short reason — what was broken>
- ...
- (Mark pre-existing issues clearly as "pre-existing" vs. "from current implementation")
Deliberately not fixed (out of scope)
- <file:line> — <reason, recommendation: separate ticket>
- (Empty if everything was covered)
Screenshots / Lighthouse
- <path or inline reference to relevant take_screenshot / lighthouse_audit results>
The list must be scannable — the user reads it as their own re-walk plan, the account registry makes the re-walk reproducible.
If lt dev up was started by this skill, leave it running for the user's re-walk unless they declare they don't need it in Step 8.
Step 8 — Ship-or-Optimize gate
Always close with AskUserQuestion. Translate the question text and the four option labels to the language the user has been speaking — the English version below is illustrative:
- Question: "Browser walk complete. Ready to ship, or should we optimize further?"
- Options:
- "Ship — everything looks good" (Recommended)
- "Optimize further — I'll describe what" — free-text follow-up; the originating workflow re-enters its implementation loop with the user's notes.
- "I'll re-test myself first — wait" — pause; leave
lt dev up running; the user will return with a verdict.
- "Cancel — leave branch as-is" — stop, no shipping; leave the branch as-is for the user.
On every outcome, close the automation browser first. The walk is over, so close_page every Chrome DevTools MCP page you opened — list_pages should show no leftover tab. This is independent of the stack decision below: even when the dev server stays up, the browser is released (the user re-tests in their own browser).
On option 1: close the browser (above), then clean up dev servers (lt dev down if you started it, pkill non-lt processes) after asking the user one last time if they want to keep the stack running for a final sanity check. Then return control to the originating workflow with verdict READY-TO-SHIP.
On option 2: close the browser (above), collect the user's notes, return to the originating workflow's implementation step with that scope. After the fixes, this skill runs again from Step 4 (new list from the new diff) — a fresh new_page reopens the browser then.
On option 3: close the browser (above) but don't tear down the stack. Print the account registry + URLs prominently again. Stop, wait for the user's next message — they re-test in their own browser against the still-running stack.
On option 4: close the browser (above), then tear down the stack the same way as option 1. Surface a closing block stating the branch is intact and unpushed (if the originating workflow normally pushes).
Working with the originating workflow
This skill is invoked from another workflow — never the entry point on its own. The contract:
Inputs the originating workflow MUST pass:
diff_base (e.g. origin/dev) so the skill can compute the diff.
ticket_id (if any) for the list header.
ticket_url (if any) — full URL to the originating ticket (e.g. https://linear.app/<workspace>/issue/DEV-123, GitHub issue URL, or the absolute repo-relative path to the story file). The skill renders this verbatim in the ticket-context block; if the originating workflow only knows the identifier, it should derive the URL from the workspace conventions before invoking the skill.
task_summary — 1–3 sentences describing what the task / bug was, in the user's session language. Used in the ticket-context block. Source: ticket description for ticket-driven workflows, the bug description for /lt-dev:debug, the diff intent for ad-hoc rebases.
implementation_summary — 1–3 sentences describing how it was implemented or fixed, plus the most-relevant file:line references. Used in the ticket-context block.
permission_matrix (if Step 5 of the originating workflow produced one) — the skill uses it directly for role coverage.
also_fixed_carryover (any pre-existing issues already noted by earlier steps) — the skill will avoid double-fixing them.
Outputs the skill returns to the originating workflow:
verdict: READY-TO-SHIP | OPTIMIZE | WAITING-FOR-USER | CANCELLED
also_fixed: list of files fixed inside this skill's loop (so they can be folded into the originating workflow's summary)
out_of_scope_findings: list of issues deliberately deferred (for the originating workflow to convert into follow-up tickets)
accounts_registry: list of all accounts used (existing + newly-created) with credentials — the originating workflow includes this in its own summary block so the user has the credentials in one place.
final_list: the rendered list (so the originating workflow can include it in its own summary block)
Failure modes the originating workflow must handle:
stall_guard_triggered — a finding failed to converge; the originating workflow should NOT mark the ticket complete.
boot_failed — the stack couldn't start; the originating workflow should surface lt dev doctor's output and stop.
Related Skills & Tools
- managing-dev-servers — decision tree for booting servers (
lt dev vs fallback)
- using-lt-cli —
lt dev command reference
- developing-lt-frontend — frontend patterns the fixes may need to follow
- generating-nest-servers — backend patterns for API-side fixes during the walk
- filing-ai-proposed-tickets — the only route by which an out-of-scope finding may become a ticket, and the bar it has to clear first
- Chrome DevTools MCP —
mcp__plugin_lt-dev_chrome-devtools__* tool family. Do NOT use the Playwright-based browser MCP for this skill.
Final Reminders
- The user only sees the walked list, never a draft. If you couldn't walk a step, that step's status is documented and the user is told.
- Fixing pre-existing issues during the walk is the default behavior, not an exception.
- Every step in the list names the account it uses — no implicit logins. New accounts created during this walk are listed with their literal credentials.
- Every UI step in the list carries the fully-qualified URL the user navigates to as a clickable markdown link
[route](url) (deep links included), so the user can click straight to the page.
- The walked list opens with a ticket-context block (link + task summary + implementation summary) so the user knows what the branch is about without leaving the list.
- The
AskUserQuestion at the end is mandatory — there is no path that returns to the originating workflow without it.
- Keep tabs to a minimum during the walk (one page,
navigate_page) and close_page every automation tab once the walk ends — the browser is never left idle, regardless of whether the dev server stays up.
- All user-facing artefacts (test plan, walked list, status labels, AskUserQuestion text + options) are translated to the language the user has been speaking in this session — never hardcode the output language.
1---2name: validating-changes-in-browser3description: Final browser validation after implementation AND review have succeeded. Boots the app via `lt dev up`, seeds realistic `@test.com` data, derives a step-by-step test list from the diff (every affected page, role, flow, empty/error state, mobile pass, console + network sweep), then walks it autonomously via Chrome DevTools MCP. Fixes everything it finds, including pre-existing issues, in the same loop. Activates as the last step of any ship-oriented workflow, and on "im Browser prüfen", "durchklicken". NOT a substitute for implementation, code review, or automated E2E tests, which run before.4---56# Validating Changes in the Browser78This skill is the **last station** before a ticket is shipped. It is invoked **only after** the implementation is complete and the relevant review step has succeeded — not as a substitute for either, but as the final user-eye check that catches the things a unit test, an API test, or a static review cannot see: broken empty states, missing toasts, focus traps, regressed flows on roles the developer didn't think to test, console errors, layout glitches, latent bugs in sibling pages that the change accidentally exposed.910The orchestrator runs the test list **itself** via Chrome DevTools MCP. Whatever it finds — including issues that pre-date the current branch — is fixed in the same loop. The user only sees the **final** list, fully ticked, with a question: ship or optimize further.1112**Language convention for this skill:**1314- The instructions you read here (English) tell you HOW to run the workflow.15- The artefacts the **developer sees** at the end (test plan headings, walked list, status labels, ship-or-optimize question and options) are rendered in the **language the user has been speaking in this session** — German if the conversation has been in German, English if in English, the user's language otherwise. The English examples below are illustrative templates; translate the headings, columns, action prose, status labels, and the AskUserQuestion text+options to match the user's language before showing them.1617## When to Use This Skill1819Activates at the end of these workflows (invoked from each):2021- `/lt-dev:resolve-ticket` — after the review-pipeline guidance, before `/lt-dev:dev-submit`22- `/lt-dev:take-ticket` — inside STEP 10 (Review-Ready Summary), before handoff23- `/lt-dev:ticket-cycle` — between Phase B (review) and Phase C (ship)24- `/lt-dev:review` — as the final Phase 7, after Phase 6 decision & fix-execution25- `/lt-dev:debug` — after Step 7 (fix implementation) succeeded26- `/lt-dev:production-ready` — as the final phase, after CI validation27- `building-stories-with-tdd` skill — at the end of Step 5b (Final Validation)28- `branch-rebaser` agent — after Phase 10 (Code Review) succeeded2930## NOT for3132- Skipping the implementation step (use the relevant dev workflow first)33- Skipping the code review (use `/lt-dev:review` first)34- Running automated E2E tests — Playwright lives in `lt dev test` / CI and runs separately; this skill is for the human-shaped flows that automated tests miss35- Smoke testing a fresh `git pull` you didn't touch — only relevant when there is a diff to validate3637## Hard Rules38391. **Run the list yourself first.** The list shown to the user is the **walked** list, not a draft. Every check must have been executed via Chrome DevTools MCP (or, for non-UI tickets, the documented manual equivalent) before the user sees it.402. **Fix everything you find, including pre-existing issues.** A console error that was already on `main` is still a console error on this branch — patch it as part of the validation loop and surface it in the summary as "also fixed" (translated to the user's session language).413. **No silent skips.** If a step cannot be tested (e.g. the project has no app, the change is backend-only and no UI consumes it yet), declare that explicitly in the list — don't omit the step.424. **Never reuse production data.** Seeds use `@test.com` emails and clearly fake names so they're filterable / wipeable.435. **Never leave dev servers orphaned.** Follow [managing-dev-servers](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md) for start + stop semantics. If you used `lt dev up`, leave it up only if the user wants to continue testing manually.446. **Account visibility is mandatory.** Every step that requires a login MUST explicitly name the account (email, password, role). The developer reads the list as their own re-walk manual — they must be able to log into the stack without follow-up questions. This applies to both reused seed accounts AND newly-created accounts. For public/unauthenticated steps, mark them explicitly as `Account: no login (public / incognito)` (translated to the user's session language) instead of omitting the field.457. **Ticket context block is mandatory.** Every walked list begins with a short context block stating (a) what the task / bug was in 1–3 sentences ("task summary"), (b) how it was implemented or fixed in 1–3 sentences plus the most-relevant `file:line` references ("implementation summary"), and (c) the ticket link when the originating workflow knows one (Linear URL, GitHub issue URL, file path of a `*.md` story). The user uses this block to orient themselves before re-walking — they should not need to switch context to remember what the branch is about.468. **URL-per-step is mandatory for UI steps — as a clickable markdown link.** Every step that touches a browser route MUST carry the fully-qualified URL the user navigates to, **rendered as a clickable markdown link** so the user clicks straight from the list (e.g. `URL: [users/new](https://<slug>.localhost/users/new)`). The session renders GitHub-flavored markdown, so `[label](url)` is clickable in the terminal / VS Code. Deep links (with query params, route params, or hash fragments) keep the exact form you used during the walk inside the link target. For non-UI steps (backend smoke pass, CLI flow), record the equivalent locator (`curl` URL + method, command line). Omit only when the step is genuinely location-less.479. **The user's final answer is binary in spirit:** ship or optimize further. The `AskUserQuestion` at the end always offers both — never end the workflow without that gate.4810. **Keep the browser lean and close it when the walk ends.** Reuse a single Chrome DevTools MCP page across steps (`navigate_page`, not a fresh `new_page` per step); open a second tab only when a step truly needs two contexts at once, and `close_page` it immediately after. When the walk concludes — on **every** `AskUserQuestion` outcome — close every page you opened via `close_page` so the MCP releases the Chrome instance, even when you leave `lt dev up` running for the user's own re-test (they use their own browser). Browser-close is independent of the dev-server keep/stop decision. See [managing-dev-servers](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md).4950## Workflow5152### Step 1 — Decide whether this step applies at all5354Skim the diff (`git diff <base>...HEAD --name-only`):5556- **At least one file under `projects/app/`, `packages/app/`, `app/`, `**/*.vue`, `**/*.svelte`, `**/*.tsx`, or any frontend route directory** → full browser pass mandatory.57- **Backend-only diff (`projects/api/`, `src/server/`, etc.)** that exposes a new/changed endpoint:58 - If a frontend consumer exists in the same repo → still do a browser pass (the new endpoint will manifest in the UI somewhere).59 - If no consumer exists yet → reduce to an API smoke pass: hit each new/changed endpoint with `curl` against `https://api.<slug>.localhost` (or the active API URL from `lt dev status`) at three role levels (Admin, regular User, unauthenticated) and assert the response matches the documented contract. Skip the UI portion explicitly in the list.60- **Pure tooling / config / CI diff** (no runtime impact): log "No browser test required — diff has no runtime impact" (translated to the user's session language) and exit cleanly. Do NOT skip the user gate, even here — they still get the closing question to confirm "ship".6162### Step 2 — Boot the application6364Follow the [managing-dev-servers](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md) decision tree. Short version:6566- If the prompt contains an "Active lt-dev project" block with `session: yes` → already running, use the URLs from the block.67- If the block says `session: no` → run `lt dev up` and wait until `https://<slug>.localhost` answers 200 OK.68- If the block says "lt-Stack project detected — not yet migrated" → run `lt dev init` first (idempotent — also chains `lt dev install` if needed), then `lt dev up`.69- If no block is injected → non-lt project. Start the project's documented dev server via `run_in_background: true` (e.g. `pnpm dev`) and `pkill` it at the end. Use the documented localhost ports.7071**Never start `pnpm dev` / `pnpm start` directly when an lt-dev context block is present** — that bypasses Caddy and re-introduces cross-wiring risk.7273If the boot fails (port collision, missing CA trust, DB not running): run `lt dev doctor` and resolve before continuing. Do NOT walk the list against a half-broken stack.7475**The stack is scoped to the project, not to your session.** `lt dev up` serves one `<slug>` with one dev database (`<slug>-local`), so a parallel Claude Code session in the same project shares both. Three consequences:7677- **`session: yes` may mean a peer started it.** That is fine, use it. But it means `lt dev down` at the end of your walk stops a stack somebody else is mid-walk in. When a peer is live in this project (`ListAgents`), leave the stack up and say so instead.78- **A reseed is destructive for the peer too.** Step 3 writes into the shared dev database. Wiping and reseeding pulls the ground out from under a peer's logged-in session. Add your data alongside theirs, or send one `CONFLICT` and agree who owns the database for the next few minutes.79- **The isolated `lt dev test` stack has none of this problem.** It runs its own `<slug>-test` database and its own URLs, so an E2E suite never disturbs a peer's walk. Prefer it whenever the walk does not have to happen against the dev data.8081The Chrome DevTools MCP itself needs no coordination: each session spawns its own chain and its own Chrome, so tabs never cross. What does cross is `pkill` on `chrome` or `node`, and the `cleanup-stale-chrome-mcp` hook, which reaps any chain older than `CHROME_MCP_MAX_AGE_HOURS` (72 by default) that is not its own session's — including a peer's, mid-walk. See [coordinating-peer-sessions](${CLAUDE_PLUGIN_ROOT}/skills/coordinating-peer-sessions/SKILL.md).8283### Step 3 — Seed realistic test data + cover every role8485The seed data is for **you** — Chrome DevTools MCP will log in as it, navigate as it, click as it. Make it realistic enough that the flows the user cares about actually fire (a list view needs items, a role-gated action needs the right role, a dashboard needs numbers).8687Choose the cheapest seed path that produces the required data:88891. **Project provides a seed script** (`pnpm run seed`, `pnpm db:seed`, `scripts/seed.ts`, etc.) → run it. Read it first to know which accounts it produces and what their credentials are — you MUST surface those credentials to the user later.902. **`tests/fixtures/` contains a seed fixture** → adapt it inline or pipe it via the API. Same rule: read the fixture to know the credentials.913. **No seed infrastructure exists** → create accounts + entities yourself via Chrome DevTools MCP (sign-up flow) OR via direct API calls (`testHelper`-style, but ad-hoc — `curl https://api.<slug>.localhost/auth/signin -d '{...}'`). You pick the passwords; record them.9293Seed rules:9495- **Emails end in `@test.com`** so the cleanup regex picks them up later (consistent with `building-stories-with-tdd`).96- **Names are obviously fake** (`Test Admin`, `Test User One`) — never realistic personally-identifying strings.97- **Cover every role you will test against.** For a permission-matrix ticket, that means one account per role mentioned in the matrix from the implementation step. If the matrix lists `Admin`, `User`, `Guest`, and a custom `Reviewer` role, you create or reuse four accounts.98- **Cover the entity states the diff touches.** A list-view change needs ≥3 items including edge cases (long string, missing optional field, special characters). A status-driven flow needs items in each status (draft / sent / archived / etc.).99- **Use a single, memorable password scheme** across all accounts (e.g. `TestPass123!`) — so the user can re-walk fast without juggling passwords. Never write "see seed" or "default password" — always write the literal value.100101**Maintain an account registry** in your working notes from this step onwards. For every account you reuse or create, record: email, literal password, role, and provenance (`existing seed` vs `NEW for this walk`). The registry feeds the test-list header AND the closing summary — the user needs every credential visible to reproduce the walk. Translate the provenance labels to the user's session language when rendering.102103### Step 4 — Derive the step-by-step test list from the diff104105Build the list **from the actual diff**, not from a generic template. For every changed or newly-added surface, generate one or more concrete check steps.106107**Account-per-step is mandatory.** Every step in the list explicitly names which account is used:108109- For login-required steps → `Account: <email>` (the account from the registry built in Step 3).110- For public / unauthenticated routes → `Account: no login (public / incognito)` (translated to the user's session language).111- For multi-role flows (e.g. "Admin approves, User sees result") → split into separate steps, one per role, each naming its account.112113Never leave the account implicit — the user reads the list as their own re-walk manual.114115Render the test plan in the **language the user has been speaking in this session**. The English template below is illustrative — translate the headings, account-list labels, and step prose when you produce the actual output. Always include the ticket-context block (task summary + implementation summary + ticket link) and a `URL:` field per UI step, rendered as a clickable markdown link `[<route>](https://…)`:116117```118Test Plan: <Ticket-ID / Feature Name>119120Ticket121- Link : <Linear URL / GitHub issue URL / file:path-to-story.md, or "no ticket — ad-hoc fix">122- Task : <1–3 sentence summary of what needed to happen — copied / paraphrased from ticket>123- Done by : <1–3 sentence summary of how it was implemented or fixed, with the most-relevant file:line refs>124125Server : https://<slug>.localhost (App) / https://api.<slug>.localhost (API)126127Accounts for this walk128- admin@test.com / TestPass123! / Admin / existing seed129- user1@test.com / TestPass123! / User / NEW for this walk130- guest@test.com / TestPass123! / Guest / NEW for this walk131- (no login) / — / — / public routes132133Steps134[ ] 1. <Page / Flow / Component> — Account: <email> — URL: [<route>](https://<slug>.localhost/<route>) — <concrete action> — <expected result>135[ ] 2. <Page / Flow> — Account: no login (public) — URL: [<public-route>](https://<slug>.localhost/<public-route>) — <action> — <expectation>136[ ] 3. <Backend smoke> — Account: <email or "anonymous"> — URL: POST https://api.<slug>.localhost/<endpoint> (curl) — <action> — <expectation>137[ ] 4. ...138```139140Coverage rules (apply each that fits the diff):141142- **Every changed page / route** → at least one check that navigates to it and confirms it renders without console errors, hydration mismatches, or 4xx/5xx network calls.143- **Every changed component used in multiple places** → check each callsite, not just one. Use `git grep` against the component name to find them.144- **Every new / changed form** → check (a) happy path submit, (b) at least one validation error, (c) the loading state, (d) the success feedback (Toast / redirect / inline confirmation).145- **Every new / changed list view** → check (a) populated state, (b) empty state, (c) error state (force by killing the API or injecting a 500 via `evaluate_script`), (d) pagination edge if applicable.146- **Every role / permission matrix row from the implementation step** → log in as that role using the account from the registry, attempt the action, assert allow / deny / partial as documented.147- **Every destructive action** → confirm the confirm-dialog is present, the button is red / clearly destructive, and the action is reversible (or explicitly not).148- **Every navigation change** (new route, redirect, breadcrumb update) → walk it from the entry point the user would actually use, not just direct URL.149- **Mobile viewport pass** at the end: `resize_page` to 390×844, walk the top 3–5 most-affected pages again, confirm no overflow / unreachable buttons / collapsed-menu regressions.150- **Console + network pass** at the end: take a final `take_snapshot`, `list_console_messages`, and `list_network_requests` on the most-changed page. Any `error` / `warning` level console message or failed network request → finding.151152For non-UI tickets (backend-only, no consumer): the list is shorter — endpoint, role, expected status code, expected schema. Same rigor on account visibility (which role is used per request).153154### Step 5 — Walk the list yourself155156For each step, drive Chrome DevTools MCP using the `mcp__plugin_lt-dev_chrome-devtools__*` tools (NOT the Playwright-based browser MCP — see [managing-dev-servers](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md)).157158**Tab economy:** open the app **once** with `new_page`, then drive every subsequent step by `navigate_page` on that same page — do not open a fresh tab per step. Spawn a second tab only when a step genuinely needs two contexts at once (two roles side-by-side, an OAuth / popup window), and `close_page` it the moment that step is done. `list_pages` shows what is open. See [managing-dev-servers → Chrome DevTools MCP — Browser-Tabs & Cleanup](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md).159160Typical tool calls per step intent:161162- **Open the app** → `new_page` with the URL from Step 2 (once — reuse it via `navigate_page` afterwards).163- **Sign in as a role** → `fill_form` on the login form using the credentials from the registry built in Step 3.164- **Navigate** → `navigate_page` (prefer over a new tab).165- **Click / interact** → `click` (with `take_snapshot` first to get stable selectors), `fill`, `press_key`, `hover`, `drag`.166- **Verify state** → `take_snapshot` (DOM tree) + `take_screenshot` (visual confirmation).167- **Inspect console** → `list_console_messages` after the action.168- **Inspect network** → `list_network_requests` after the action.169- **Force an error** → `evaluate_script` to throw / mutate a request / mock a 500.170- **Mobile pass** → `resize_page` to 390×844, repeat the relevant steps.171- **Run a Lighthouse a11y / perf snapshot** → `lighthouse_audit` on the most-changed page.172173After each step, mark the checkbox **only if** the step actually passed. If it failed → Step 6.174175### Step 6 — Fix everything you find, then re-walk176177Findings during the walk include:178179- A new or pre-existing bug (broken button, wrong text, 500 on a side-effect endpoint, layout overflow, ...).180- A console error or warning. Treat warnings as findings unless they are documented third-party noise.181- A network failure (4xx other than expected 401/403, 5xx, CORS error, slow request > 2s for a non-load-heavy endpoint).182- A regressed empty / loading / error state.183- An a11y violation surfaced by Lighthouse (focus order, missing label, contrast).184- A mobile regression (overflow, unreachable button, broken menu).185186For each finding:1871881. **Diagnose root cause** by reading the relevant code (the component, the page, the composable, the controller / service if backend).1892. **Fix it** — including if it pre-dates the branch. Use the same editing rules the originating workflow has been using (TypeScript strictness, no `--no-verify`, no `@ts-ignore`).1903. **Note it in working memory** as "also fixed" (translated to the user's session language) — these will surface in the final summary so the user knows the branch did more than just the ticket.1914. **Re-walk the affected step** to confirm green.1925. **Re-walk dependent steps too** — a fix to a shared composable might affect other pages.193194Stall guard: if the same finding fails to converge after 3 fix attempts, stop the loop, write a structured diagnosis (file, observation, attempted fixes, current hypothesis), and surface it as a blocker in the final summary. Don't ship a known-broken state silently.195196If a finding is truly out-of-scope and high-risk to fix in this branch (e.g. a multi-day refactor of a shared module), name it in the final summary in one line, translated to the user's session language, and leave it there. **Do not open a ticket for it as a matter of course** — a walk that leaves a trail of follow-up tickets behind every ticket is how one day's work becomes a backlog. A ticket is filed only where the finding clears Part 0 of [`filing-ai-proposed-tickets`](../filing-ai-proposed-tickets/SKILL.md): demonstrated, standalone, and genuinely worse left undone. Then it goes through that skill in full — duplicate search first, Triage state, AI label. Everything else is a line in the summary, and the user decides.197198### Step 7 — Show the user the walked list199200Render the **final** list (every step ticked) in a structured block. **Repeat the ticket-context block AND the account registry verbatim** so the user can re-walk from a single screen without scrolling back. Each executed check carries its `URL:` field again so the user can click straight to the page. Render in the language the user has been speaking; the English template below is illustrative:201202```203╔══════════════════════════════════════════════════════════╗204║ Manual Browser Walk: <Ticket-ID / Feature> ║205╚══════════════════════════════════════════════════════════╝206207Ticket208- Link : <Linear URL / GitHub issue URL / file:path-to-story.md, or "no ticket — ad-hoc fix">209- Task : <1–3 sentence summary of what needed to happen>210- Done by : <1–3 sentence summary of how it was implemented or fixed, with the most-relevant file:line refs>211212Stack213- App: <URL>214- API: <URL>215- DB: <slug>-local (seed data: @test.com)216217Accounts (re-walk credentials — log in with these)218- admin@test.com / TestPass123! / Admin / existing seed219- user1@test.com / TestPass123! / User / NEW for this walk220- guest@test.com / TestPass123! / Guest / NEW for this walk221- (no login) / — / — / public routes222223Executed checks224[x] 1. <Step> — Account: <email> — URL: [<route>](https://<slug>.localhost/<route>) — Observation: <short note on what actually happened>225[x] 2. <Step> — Account: no login — URL: [<public-route>](https://<slug>.localhost/<public-route>) — Observation: ...226[x] 3. <Step> — Account: <email> — URL: POST https://api.<slug>.localhost/<endpoint> (curl) — Observation: ...227228Also fixed during the walk229- <file:line> — <short reason — what was broken>230- ...231- (Mark pre-existing issues clearly as "pre-existing" vs. "from current implementation")232233Deliberately not fixed (out of scope)234- <file:line> — <reason, recommendation: separate ticket>235- (Empty if everything was covered)236237Screenshots / Lighthouse238- <path or inline reference to relevant take_screenshot / lighthouse_audit results>239```240241The list must be **scannable** — the user reads it as their own re-walk plan, the account registry makes the re-walk reproducible.242243If `lt dev up` was started by this skill, leave it running for the user's re-walk **unless they declare they don't need it** in Step 8.244245### Step 8 — Ship-or-Optimize gate246247Always close with `AskUserQuestion`. **Translate the question text and the four option labels to the language the user has been speaking** — the English version below is illustrative:248249- **Question:** "Browser walk complete. Ready to ship, or should we optimize further?"250- **Options:**251 1. "Ship — everything looks good" *(Recommended)*252 2. "Optimize further — I'll describe what" — free-text follow-up; the originating workflow re-enters its implementation loop with the user's notes.253 3. "I'll re-test myself first — wait" — pause; leave `lt dev up` running; the user will return with a verdict.254 4. "Cancel — leave branch as-is" — stop, no shipping; leave the branch as-is for the user.255256**On every outcome, close the automation browser first.** The walk is over, so `close_page` every Chrome DevTools MCP page you opened — `list_pages` should show no leftover tab. This is independent of the stack decision below: even when the dev server stays up, the browser is released (the user re-tests in their own browser).257258On option 1: close the browser (above), then clean up dev servers (`lt dev down` if you started it, `pkill` non-lt processes) **after** asking the user one last time if they want to keep the stack running for a final sanity check. Then return control to the originating workflow with verdict `READY-TO-SHIP`.259260On option 2: close the browser (above), collect the user's notes, return to the originating workflow's implementation step with that scope. After the fixes, this skill runs again from Step 4 (new list from the new diff) — a fresh `new_page` reopens the browser then.261262On option 3: close the browser (above) but **don't** tear down the stack. Print the account registry + URLs prominently again. Stop, wait for the user's next message — they re-test in their own browser against the still-running stack.263264On option 4: close the browser (above), then tear down the stack the same way as option 1. Surface a closing block stating the branch is intact and unpushed (if the originating workflow normally pushes).265266## Working with the originating workflow267268This skill is **invoked from** another workflow — never the entry point on its own. The contract:269270- **Inputs** the originating workflow MUST pass:271 - `diff_base` (e.g. `origin/dev`) so the skill can compute the diff.272 - `ticket_id` (if any) for the list header.273 - `ticket_url` (if any) — full URL to the originating ticket (e.g. `https://linear.app/<workspace>/issue/DEV-123`, GitHub issue URL, or the absolute repo-relative path to the story file). The skill renders this verbatim in the ticket-context block; if the originating workflow only knows the identifier, it should derive the URL from the workspace conventions before invoking the skill.274 - `task_summary` — 1–3 sentences describing what the task / bug was, in the user's session language. Used in the ticket-context block. Source: ticket description for ticket-driven workflows, the bug description for `/lt-dev:debug`, the diff intent for ad-hoc rebases.275 - `implementation_summary` — 1–3 sentences describing how it was implemented or fixed, plus the most-relevant `file:line` references. Used in the ticket-context block.276 - `permission_matrix` (if Step 5 of the originating workflow produced one) — the skill uses it directly for role coverage.277 - `also_fixed_carryover` (any pre-existing issues already noted by earlier steps) — the skill will avoid double-fixing them.278279- **Outputs** the skill returns to the originating workflow:280 - `verdict`: `READY-TO-SHIP` | `OPTIMIZE` | `WAITING-FOR-USER` | `CANCELLED`281 - `also_fixed`: list of files fixed inside this skill's loop (so they can be folded into the originating workflow's summary)282 - `out_of_scope_findings`: list of issues deliberately deferred (for the originating workflow to convert into follow-up tickets)283 - `accounts_registry`: list of all accounts used (existing + newly-created) with credentials — the originating workflow includes this in its own summary block so the user has the credentials in one place.284 - `final_list`: the rendered list (so the originating workflow can include it in its own summary block)285286- **Failure modes the originating workflow must handle:**287 - `stall_guard_triggered` — a finding failed to converge; the originating workflow should NOT mark the ticket complete.288 - `boot_failed` — the stack couldn't start; the originating workflow should surface `lt dev doctor`'s output and stop.289290## Related Skills & Tools291292- [managing-dev-servers](${CLAUDE_PLUGIN_ROOT}/skills/managing-dev-servers/SKILL.md) — decision tree for booting servers (`lt dev` vs fallback)293- [using-lt-cli](${CLAUDE_PLUGIN_ROOT}/skills/using-lt-cli/SKILL.md) — `lt dev` command reference294- [developing-lt-frontend](${CLAUDE_PLUGIN_ROOT}/skills/developing-lt-frontend/SKILL.md) — frontend patterns the fixes may need to follow295- [generating-nest-servers](${CLAUDE_PLUGIN_ROOT}/skills/generating-nest-servers/SKILL.md) — backend patterns for API-side fixes during the walk296- [filing-ai-proposed-tickets](${CLAUDE_PLUGIN_ROOT}/skills/filing-ai-proposed-tickets/SKILL.md) — the only route by which an out-of-scope finding may become a ticket, and the bar it has to clear first297- Chrome DevTools MCP — `mcp__plugin_lt-dev_chrome-devtools__*` tool family. **Do NOT** use the Playwright-based browser MCP for this skill.298299## Final Reminders300301- The user only sees the **walked** list, never a draft. If you couldn't walk a step, that step's status is documented and the user is told.302- Fixing pre-existing issues during the walk is the default behavior, not an exception.303- Every step in the list names the account it uses — no implicit logins. New accounts created during this walk are listed with their literal credentials.304- Every UI step in the list carries the fully-qualified URL the user navigates to as a clickable markdown link `[route](url)` (deep links included), so the user can click straight to the page.305- The walked list opens with a ticket-context block (link + task summary + implementation summary) so the user knows what the branch is about without leaving the list.306- The `AskUserQuestion` at the end is mandatory — there is no path that returns to the originating workflow without it.307- Keep tabs to a minimum during the walk (one page, `navigate_page`) and `close_page` every automation tab once the walk ends — the browser is never left idle, regardless of whether the dev server stays up.308- All user-facing artefacts (test plan, walked list, status labels, AskUserQuestion text + options) are translated to the language the user has been speaking in this session — never hardcode the output language.