# Anti-Pattern Checklist For LLM Agents

Use this checklist after generating UI. If any anti-pattern is present, revise the interface before producing final code.

## AI agent acts without approval (ai-agent-acts-without-approval)

Detect when:
- The agent can call tools, send external messages, spend money, issue refunds, change access, update customer records, deploy code, delete data, submit forms, publish content, or trigger downstream workflows.
- The UI may describe the agent as preparing, researching, drafting, or working while side effects are already committed.
- Users may have approved a broad prompt, plan, or recommendation but not the exact payload, target, timing, or downstream consequence that executed.
- Approval can be required by policy, confidence, source gaps, cost, permissions, customer impact, legal risk, security risk, or separation of duties.
- The agent may need different treatment for safe read-only steps, reversible draft steps, gated side-effect steps, emergency bypass, and post-action recovery.

Why it fails:
- Treating Run agent as permission to execute every hidden side-effect step.
- Sending a customer message or issuing a refund while the UI still says the agent is drafting.
- Showing an approval card after the tool already executed.
- Letting the requester approve their own high-impact automation step.
- Using high confidence, source grounding, or a green progress state as a substitute for authorization.
- Hiding the exact tool input, recipient list, amount, access target, deployment environment, or deletion scope.
- Providing no stop, rollback, cancel, report, or escalation path after unauthorized execution.

Replace with:
- Inventory all agent tools and mark read-only, draft-only, reversible, externally visible, money-moving, access-changing, destructive, deployment, publication, and customer-impact steps.
- Define which steps require approval by policy, risk, confidence, source status, cost, data sensitivity, target environment, recipient scope, or separation-of-duties rule.
- Render proposed side-effect steps with payload preview, diff, target, tool, evidence, risk, approver eligibility, timeout, and downstream consequence before execution.
- Require explicit approve, edit, reject, cancel, stop, or bypass controls for gated steps, and block self-approval where policy requires independent review.
- Revalidate payload hash, target, source freshness, model version, policy version, approver role, and tool permission immediately before resuming the gated step.
- Separate plan preview, progress trace, tool-use visibility, approval gate, dangerous-action review, and audit trail data so users can tell proposed, armed, executing, and completed actions apart.
- Provide post-action recovery for bypassed or unauthorized execution: stop future steps, rollback, revoke, notify affected users, report incident, and inspect audit trail.
- Test hidden side-effect tools, broad prompt consent, stale notification approval, self-approval, edited payload, emergency bypass, failed resume, rollback, mobile approval, keyboard flow, and high-zoom payload wrapping.

Review question:
- Which agent steps are read-only, draft-only, reversible, externally visible, destructive, money-moving, access-changing, or customer-impacting?
- What exact action, target, payload, tool, and version will execute after approval?
- Can the user distinguish proposed work, armed gated work, running work, completed work, and audit history?
- Who is eligible to approve, who is blocked from self-review, and what happens if the approval becomes stale?
- What recovery exists if the agent already acted without approval?
- Would human approval gate, agent plan preview, agent progress trace, tool-use visibility, dangerous-action review, or automation rule builder solve the actual problem?

## AI answer without sources (ai-answer-without-sources)

Detect when:
- The answer may be generated from web search, file search, enterprise knowledge sources, selected documents, uploaded files, chat history, model prior knowledge, tool outputs, or no retrieval at all.
- The answer contains claims users may rely on for policy, compliance, support, operations, money, safety, medicine, law, customer communication, product decisions, or public publication.
- The system may have skipped retrieval, failed retrieval, hidden permission-limited sources, mixed model knowledge with retrieved evidence, or returned a no-source answer after a source-backed request.
- Users need to know whether the answer is sourced, not searched, unsupported, permission-limited, stale, or draft-only before acting on it.

Why it fails:
- Showing a polished answer with no citations or grounding after the user asked for a policy-backed answer.
- Adding a generic disclaimer while still letting users copy or send the unsourced answer as if it were verified.
- Hiding retrieval failure and returning an answer from model memory.
- Showing related links below the answer without saying they were not used as evidence.
- Promising citations in the prompt or product copy and then returning an answer with no source state.
- Letting regenerated or edited output drop citations without changing the answer status.
- Treating high confidence as a substitute for source evidence.

Replace with:
- Track answer provenance as structured state: source mode, source scope, retrieval status, used evidence, unsupported claims, permissions, freshness, and no-source reason.
- Render no-source and not-searched labels beside the answer summary, not only in hidden metadata or logs.
- Provide search, retry, source selection, upload, request access, ask human, and draft-only actions when those routes can change the source state.
- Block or warn before copy, publish, apply, send, or automate when evidence-dependent claims remain unsourced.
- Preserve source state in copied text, exports, audit logs, handoffs, and regenerated answer versions.
- Do not replace missing sources with confidence percentages, related links, generic disclaimers, or decorative citation numbers.
- Test no retrieval, retrieval failure, zero results, permission-limited sources, stale sources, streaming pending, mobile layout, high zoom, keyboard flow, and screen reader status.

Review question:
- Which claims in this answer require evidence before users act?
- Were sources searched, retrieved, used, unavailable, permission-limited, or not searched?
- Can users tell whether the answer came from retrieved evidence or model prior knowledge?
- What happens when retrieval fails or finds no supporting source?
- Does copy, publish, apply, or send preserve the no-source warning?
- Would source grounding display, citation display, confidence / uncertainty display, streaming response, or correction feedback be the precise pattern?

## AI confidence shown as fake precision (ai-confidence-shown-as-fake-precision)

Detect when:
- The UI displays model output, retrieval ranking, classifier score, extractor score, recommendation rank, generated-answer score, or risk estimate as if it were a calibrated probability.
- The number may come from a raw model logit, internal rank, heuristic score, embedding similarity, confidence token, stale assessment, or population-level metric that does not map to user-facing correctness.
- Users may act on the number by approving, denying, sending, publishing, escalating, triaging, applying an extraction, or trusting a generated answer.
- The product may need uncertainty, threshold, source grounding, warning text, or review controls, but the exact-looking number is doing that work instead.

Why it fails:
- Formatting an uncalibrated model score as 97.42 percent sure.
- Showing 0.873 certainty without saying it is a raw rank, similarity, or heuristic score.
- Using a confidence meter or color band to imply correctness without threshold, calibration, or explanation.
- Keeping old confidence after the user edits input, changes source scope, or the model updates.
- Treating confidence as source evidence, policy approval, legal correctness, or permission.
- Copying the exact-looking score into an audit note without the caveat that made it interpretable.

Replace with:
- Trace each displayed confidence number to its source: calibrated probability, raw score, rank, similarity, heuristic, model confidence, or stale stored value.
- Define whether the number is valid for the current task, population, model version, input quality, source scope, threshold, and consequence.
- Hide or relabel raw scores that cannot be interpreted as user-facing probability.
- Model calibration unavailable, insufficient evidence, out-of-distribution, stale model, threshold changed, ranking-only, copied-score, and review-required states.
- Place uncertainty reason, threshold, freshness, and gated action near the AI output before any commit control.
- Prevent copy, apply, approve, deny, send, publish, or automation from stripping calibration caveats.
- Test exact percent, decimal score, color-only score, gauge score, stale score, source-proof misuse, mobile layout, keyboard flow, high zoom, and status messaging.

Review question:
- What exactly does this number measure, and can users interpret it as probability of correctness?
- Is the score calibrated for this task, population, model version, data source, threshold, and current input?
- Would a qualitative uncertainty state be more honest than a precise percentage or decimal?
- What changes invalidate the displayed score before the user acts?
- Does the UI separate confidence from source grounding, citations, warning text, policy permission, and severe consequence copy?
- Can the user review, verify sources, collect missing input, escalate, or fallback when confidence is unavailable or below threshold?

## Ambiguous destructive action copy (ambiguous-destructive-action-copy)

Detect when:
- A dialog, sheet, action menu, toast, command palette, mobile action sheet, or review page includes a destructive command.
- The interface uses vague labels such as OK, Yes, No, Continue, Confirm, Submit, Remove, Done, or Cancel near a destructive or externally visible action.
- The same word can mean different outcomes, such as cancel the dialog versus cancel the subscription, remove from view versus delete permanently, or continue review versus execute the dangerous action.
- Users need to distinguish the destructive commit, the safe preserve path, reversible cleanup, typed target verification, and high-impact action review.

Why it fails:
- A delete prompt uses OK and Cancel without naming what OK will delete.
- A subscription flow has a Cancel button that could mean close the dialog or cancel the subscription.
- A permission dialog uses Remove without saying whether access is revoked or the person is deleted from the workspace.
- A dangerous agent tool review uses Continue for both the next review step and actual execution.
- A mobile action sheet shortens Delete account to Delete when the account name and scope are offscreen.
- A red button relies on color to signal destruction while its text says Confirm.

Replace with:
- Inventory every destructive prompt and record the trigger label, title, final action, safe action, status message, object, count, and consequence.
- Replace OK, Yes, No, Continue, Confirm, Submit, and Done with outcome-specific labels.
- Replace ambiguous Cancel with Keep plan, Close dialog, Cancel subscription, Stop deletion, or Do not delete according to intent.
- Disambiguate Remove by naming whether the object is deleted, detached, hidden, unshared, revoked, or moved to trash.
- Include counts for bulk destructive actions and rerender labels when selection changes.
- Keep copy synchronized with disabled states, dependency blockers, typed confirmation, and post-action receipts.
- Test localization, truncation, keyboard focus, screen reader names, compact width, and action-sheet layouts so labels remain specific.

Review question:
- Would the final action label still be clear if read without color or icon?
- Does the label name the destructive verb and affected target?
- Could Cancel, Remove, Continue, or Done mean more than one outcome in this context?
- Does the safe action say what remains unchanged?
- Does bulk copy update when selected count or object type changes?
- Does assistive technology receive the same outcome-specific label as sighted users?

## Carousel auto-advance without pause (carousel-auto-advance-without-pause)

Detect when:
- A carousel, hero, promotion rail, onboarding slider, or recommendation strip changes visible content on a timer.
- The slide can contain text, calls to action, form fields, recommendation reasons, feedback controls, warnings, or decision-support information.
- Users may read slowly, use keyboard or assistive technology, hover for detail, switch tabs, use mobile gestures, or prefer reduced motion.
- The product wants motion for attention, but users need control over timing, focus, announcements, and recovery.

Why it fails:
- Hiding Pause behind carousel dots, hover-only controls, or an overflow menu.
- Starting rotation automatically because marketing wants movement without testing reading time or assistive technology impact.
- Continuing to rotate while focus is inside a slide, a form field has text, or the pointer is hovering over details.
- Treating a recommendation rail as a decorative carousel and rotating away reasons, dismiss buttons, sponsored labels, or feedback.
- Announcing every timer-driven slide change to screen readers.
- Ignoring reduced-motion preferences because the slide transition seems slow.
- Fast-forwarding through several slides when the tab regains visibility.
- Using auto-advance to hide stakeholder prioritization problems instead of choosing a static hierarchy.

Replace with:
- Decide whether auto-advance is needed at all; default to paused or static content unless the user starts motion.
- Place Pause or Stop rotation first in the carousel DOM and visible control order when rotation can occur.
- Bind focusin, pointer hover, touch interaction, form input, popover open, and recommendation feedback states to stop or suspend rotation.
- Check prefers-reduced-motion and product-level motion settings before enabling timers or animated transitions.
- Preserve current slide, focused element, typed values, open disclosures, selected recommendation feedback, and live-region behavior while pausing and resuming.
- Use named slide controls and a visible slide count so users can recover the slide that moved.
- Throttle or suppress automatic live-region announcements and announce only user-commanded changes.
- Test keyboard, screen reader, hover, touch, mobile viewport, reduced motion, background tab return, slow reading, form entry, recommendation feedback, and failure recovery.

Review question:
- Can users stop the carousel before any automatic change happens?
- What exactly happens when keyboard focus enters the carousel?
- Does hover, touch exploration, or reading a long caption suspend motion?
- Does reduced motion fully disable auto-advance or only shorten the animation?
- Can a user recover a slide that moved while they were reading or typing?
- Are recommendation reasons, feedback, sponsored labels, warnings, or form fields rotating away?
- Would tabs, a static section, a recommendation list, a grid, or pagination better match the content job?

## Confirmation fatigue (confirmation-fatigue)

Detect when:
- A product uses modal confirmations, alert dialogs, browser confirms, action sheets, or extra OK prompts for many commands in the same workflow.
- Many confirmed actions are frequent, reversible, local, low-risk, or already clear from the command label.
- The same prompt style is used for harmless actions and severe actions, so users cannot tell which prompt deserves attention.
- Teams may have added confirmations after incidents without checking whether undo, prevention, command placement, warning text, or review would target the real error better.

Why it fails:
- Adding a confirmation after every user mistake without asking whether the mistake was reversible.
- Using one generic confirmation component for every action from closing a panel to deleting a workspace.
- Stacking warning text, confirmation dialog, typed confirmation, and undo for a low-risk action.
- Keeping prompts because they feel safer even though users dismiss them unread.
- Removing prompts without adding the undo, restore, status, or prevention path that made removal safe.
- Treating cancellation rate alone as proof that a prompt is useful without checking task interruption and habituation.

Replace with:
- Inventory all confirmation prompts in the workflow and tag each by action, frequency, reversibility, external effects, consequence severity, and existing recovery.
- Remove modal confirmation from routine save, close, filter, dismiss, archive, hide, reorder, and delete-to-trash actions when undo or status feedback is sufficient.
- Replace low-risk confirmations with object-specific feedback, undo, restore, inline validation, disabled explanation, preview, or better command grouping.
- Keep or add confirmation only where object, count, scope, cost, permission, external recipient, recovery limit, or legal consequence can be shown before commitment.
- Use destructive action confirmation, typed confirmation, dangerous-action review, or human approval gate only when their stronger contract matches the consequence.
- Write remaining prompt copy with the affected object, consequence, safe action, and final action; avoid OK, Yes, No, Continue, and repeated Are you sure wording.
- Measure fast dismissals, prompt chains, repeated confirmations per task, cancellation rate, undo use, support incidents, and whether users can recall what they confirmed.
- Test keyboard and screen-reader flow for both removed prompts and remaining prompts so fewer dialogs do not hide recovery from non-pointer users.

Review question:
- What specific mistake does this confirmation prevent?
- How often will a user see this prompt in one normal task?
- Can the exact prior state be restored with undo instead of blocking the action?
- Does the prompt add new consequence information beyond the trigger label?
- Are severe prompts visually and textually distinguishable from routine prompts?
- Are users clicking through so fast that they probably are not reading?
- Can the risk be reduced by command placement, disabled explanations, previews, or safer defaults instead of confirmation?

## Dark-pattern consent (dark-pattern-consent)

Detect when:
- The surface asks for optional data use, marketing, research contact, AI training, partner sharing, personalization, sensitive-data use, non-essential cookies, local storage, advertising tags, analytics tags, or similar tracking.
- Consent may be presented during onboarding, checkout, account creation, cookie banners, cookie settings, preference centers, privacy settings, app permission explanations, beta enrollment, or legal-acceptance-adjacent flows.
- Users may face misleading hierarchy, disabled-looking refusal, confirmshaming copy, repeated prompts, bundled terms, preselected choices, unavailable service after refusal, or a mismatch between visible choice and runtime processing.
- The organization may later rely on the record as evidence, so the design must prove what the user saw, whether refusal was reachable, and whether optional processing was blocked until consent.

Why it fails:
- Showing Accept all as the only button and hiding Reject all inside Manage settings.
- Preselecting optional marketing, analytics, personalization, or partner-sharing toggles.
- Treating continued browsing, closing, scrolling, swiping, or inactivity as consent.
- Using shame copy such as No, I do not want privacy or I prefer worse service for refusal.
- Bundling optional marketing or partner sharing inside required terms acceptance.
- Starting tracking, sharing, or AI training before consent is captured.
- Making withdrawal harder to find or complete than the original acceptance.
- Repeating a prompt after refusal until the user accepts.

Replace with:
- Inventory every consent surface and record accept path, reject path, manage path, withdrawal path, default state, processing start time, and stored evidence.
- Compare the number of steps, visual prominence, wording, keyboard order, and mobile visibility of accept, reject, customize, and withdraw actions.
- Turn off optional purposes by default and split independent purposes into separate choices.
- Remove consent walls, forced acceptance, repeated nags, confirmshaming, deceptive contrast, hidden reject links, preselected options, and bundled legal or marketing choices.
- Block optional cookies, pixels, tags, SDKs, sharing, marketing, AI training, and personalization until the matching purpose is accepted.
- Record accept, reject, customize, withdrawal, renewal, stale, and failed-write outcomes with purpose and version.
- Test accept, reject, customize, withdrawal, renewal, mobile compact, keyboard order, screen-reader labels, browser privacy signal, no-JavaScript, and runtime proof that optional processing is blocked.

Review question:
- Can users reject or customize with effort comparable to accepting?
- Are any optional purposes preselected or bundled into legal terms or another purpose?
- Does the product process, track, share, market, or train before the matching consent exists?
- Does refusal preserve eligible service access and task progress?
- Can users withdraw later from a stable route using the same purpose labels?
- Does the evidence record prove what prompt version, choices, and runtime behavior existed at the time of the decision?
- Is this a dark-pattern consent issue, or should the corrected surface be consent prompt, cookie consent, cookie banner, legal acceptance, preference center, or privacy settings?

## Dead-end empty state (dead-end-empty-state)

Detect when:
- A list, table, dashboard, workspace, inbox, or panel can render with no visible items.
- The product may not yet know whether the cause is first use, filters, permissions, loading failure, deletion, unavailable data, or a hidden prerequisite.
- Users need enough context to decide whether to create, import, clear criteria, request access, retry, restore, or leave.

Why it fails:
- Blank table body with no heading, count, cause, or action.
- Friendly illustration plus vague text such as Nothing here yet with no task path.
- Create button shown to a read-only user and failing after activation.
- No-results caused by filters but active criteria are hidden above the fold.
- Failed load rendered as empty content to avoid showing an error.
- A removed item leaves keyboard focus on a now-empty region with nowhere to go.

Replace with:
- Track data status separately from rendered item count: loading, empty, no-results, permission, error, and ready.
- Render the surrounding context such as table title, filter chips, workspace, owner, or object type.
- Write a cause-specific heading and short explanation before adding illustration.
- Show one valid primary action or a clear reason no action is available.
- Do not offer create/import/reset/retry controls unless they are permitted and wired to a state change.
- Keep keyboard focus in a useful place after the blank region resolves or changes cause.
- Instrument blank states so repeated dead ends can be found and replaced.

Review question:
- Can users name what is absent after reading this state?
- Can users tell whether the cause is first-use, filters, permission, setup, deletion, loading, or failure?
- Is the visible next action valid for this user and wired to a meaningful state change?
- Would the same blank copy still appear if the cause changed to error or no-results?

## Disabled button with no explanation (disabled-button-no-explanation)

Detect when:
- A form, setup flow, permission model, quota, dependency, or safety gate controls whether an action can run.
- The primary action is greyed out, skipped by keyboard focus, or visually present but functionally unavailable.
- The reason may be a missing field, invalid format, unchecked agreement, insufficient permission, pending system state, or locked account.
- Users need to know what to change, who can grant access, or when the action will become available.

Why it fails:
- Greying out Continue until every field is valid without showing the missing or invalid answers.
- Putting the only explanation in a tooltip attached to a disabled button that keyboard and touch users cannot open.
- Using disabled state to hide permission, quota, account lock, or system dependency problems.
- Changing the button from disabled to enabled silently after a requirement changes elsewhere on the page.
- Disabling a destructive action without explaining the safety prerequisite or alternate route.
- Using low contrast disabled styling as the only signal that an action is unavailable.

Replace with:
- Name the exact condition blocking the action, such as Enter a workspace name, Accept billing terms, or Ask an admin for owner access.
- Place requirement text, checklist, or field errors before the action or directly beside it.
- Use enabled submit plus validation when disabling would hide field requirements or prevent users from learning what remains.
- Use aria-describedby or equivalent relationships for nearby requirement text when an unavailable control remains in the UI.
- Keep recovery links, request-access controls, edit fields, and support routes keyboard reachable.
- Avoid hover-only explanations on disabled controls because disabled elements may not receive focus or pointer events consistently.
- Update the action label or status during short processing states so users know the button is busy, not permanently unavailable.

Review question:
- Can users tell exactly which requirement blocks the action before they try random changes?
- Can keyboard and screen reader users reach the explanation and recovery path?
- Is this a field validation problem, a permission problem, a system state, or a safety lock?
- Would an enabled submit with validation teach the next step better than a disabled button?
- Does the UI distinguish temporary processing from a longer blocked state?

## Disabled controls without recovery (disabled-controls-without-recovery)

Detect when:
- The interface gates an action behind form completion, permission, quota, account status, dependency setup, offline state, session expiry, review approval, or safety policy.
- The unavailable control is visible but inert, skipped by focus, or only explained by color, hover, or hidden text.
- Users may not know whether they need to edit fields, ask an admin, wait for processing, reconnect, upgrade a plan, sign in again, finish another step, or use another route.
- The product has enough state to name at least one recovery path or to state that no recovery is possible from this surface.

Why it fails:
- A Continue button remains disabled until all fields are valid but no field or checklist names the missing work.
- A disabled Invite teammate action hides that billing setup, owner approval, or admin policy is required.
- A disabled menu item has a title tooltip as the only explanation, so touch and keyboard users never see the recovery step.
- A Save button is disabled during processing with no progress, timeout, retry, or draft preservation.
- A role-limited user loses read-only access because the disabled edit control consumes the whole surface.
- A stale disabled state remains after the user fixes the field, reconnects, refreshes permissions, or signs back in.

Replace with:
- Inventory each disabled control and record the exact condition, owner, timeout, retry rule, and recovery path.
- Place prerequisite, permission, offline, dependency, or session recovery text before or next to the disabled control.
- Add visible controls for Edit missing fields, Request access, Open setup step, Retry save, Sign in again, Save draft, Contact admin, or Use alternate route when those actions are valid.
- Use aria-describedby or nearby status regions for unavailable controls that remain visible.
- Avoid hiding the only reason in a disabled element tooltip, disabled menu item title, color, icon, or inaccessible hover card.
- Clear stale disabled state when prerequisites are met, permissions refresh, network returns, session recovery completes, or the dependency unlocks.
- Test keyboard order, screen reader announcement, touch, high zoom, offline, slow save, expired session, role change, admin policy, and reload while blocked.

Review question:
- What exact condition makes the control unavailable?
- Can the current user do anything to change that condition from here?
- If another person or system owns the block, is the request, contact, or status route visible?
- Does the UI distinguish missing input from permission, dependency, session, offline, and processing states?
- Can keyboard, touch, and assistive technology users reach the recovery instructions?
- What proves the disabled state clears when recovery succeeds?

## Drawer with no close or return path (drawer-with-no-close-or-return-path)

Detect when:
- A side drawer, inspector, side sheet, mobile full-screen drawer, or navigation drawer opens over or beside the current page.
- The surface is temporary, contextual, or responsive rather than a permanent workspace pane.
- Users need to return to a specific row, card, filter result, map marker, chart point, or navigation trigger after closing.
- The drawer may include dirty fields, selected-object switching, scrim dismissal, browser back handling, or narrow viewport layout changes.

Why it fails:
- Hiding close in an overflow menu or offscreen toolbar.
- Relying on swipe-only dismissal for mobile drawers.
- Letting Escape do nothing because the drawer was implemented as a plain div.
- Closing the drawer while focus moves to the page header or disappears.
- Clearing filters or selected rows when the drawer closes.
- Treating browser back as page navigation instead of first closing the temporary drawer.
- Blocking close during unsaved work without offering Keep editing, Discard, or Save choices.

Replace with:
- Inventory every drawer, side sheet, inspector, and mobile drawer that can open temporarily.
- Identify the opener, selected object, route state, filter state, scroll position, and focus target to restore.
- Add a labelled close control in a stable header or sticky action area.
- Implement Escape dismissal or a dirty-state discard review.
- Handle browser back, route changes, scrim click, outside click, close button, and object switch through one close routine.
- Return focus to the current selected object or opener after every dismissal path.
- Preserve underlying page state unless the user explicitly changes or discards it.
- Provide mobile Back or Close controls when the drawer becomes full-screen.
- Test keyboard-only, touch, screen reader, high zoom, route/back, dirty edits, object switching, and repeated open-close cycles.

Review question:
- What exact element receives focus after each close route?
- Can pointer, keyboard, touch, screen reader, and route/back users all leave the drawer?
- Does the drawer preserve the row, filter, scroll, and draft state that existed before opening?
- What happens if the selected object changes while the drawer is open?
- What happens when the drawer is full-screen on mobile or at high zoom?
- Is close blocked because of dirty state, or because no dismissal contract was designed?

## Fake undo (fake-undo)

Detect when:
- A product shows Undo in a toast, snackbar, activity row, command bar, keyboard shortcut, history stack, or recovery panel after a completed action.
- The action may affect object identity, list order, filters, permissions, relationships, notifications, background jobs, external recipients, payments, webhooks, or audit state.
- The product may capture only part of the prior state or let the recovery window expire while the control still looks available.
- Users may perform multiple actions quickly, change filters, leave the route, reload, go offline, or lose permission before trying to undo.

Why it fails:
- Showing Undo after an action that has already sent email, money, permissions, or webhooks outside the product.
- Restoring only a visible row while losing comments, labels, sharing, order, or ownership.
- Letting a second action overwrite the first action's undo payload.
- Using a disappearing toast as the only recovery path for an important object.
- Keeping Undo visible after the server has already committed a permanent delete.
- Treating rollback failure as success because the item name reappeared.
- Saying Undo when the real action is open trash, recreate from template, request admin restore, or retry save.

Replace with:
- Define what exact prior state must be restored for each action: ID, parent, order, labels, ownership, permissions, relationships, counts, draft values, and focus target.
- Capture the restore payload before mutating local, server, and external systems.
- Make undo idempotent and scoped to a stable action ID so duplicate clicks or retries do not corrupt recovery.
- Block or re-label undo for actions with irreversible external effects, or delay those effects until the recovery window closes.
- Keep recovery controls visible, keyboard reachable, and stable while focused; do not auto-remove a focused Undo button.
- Handle multiple actions with an undo stack, per-item undo, grouped undo, or explicit commit boundary.
- Report restored, expired, failed, partial, final, and unavailable states in text, not only by removing the toast.
- Test reload, route changes, filters, pagination, selection, offline, duplicate actions, permissions, external notifications, and screen reader status before claiming undo.

Review question:
- What exact state is captured before the action, and what proof shows it can be restored?
- Can any external recipient, payment, webhook, permission change, or audit event still observe the action after Undo?
- Does Undo restore identity, order, relationships, labels, permissions, counts, selection, and focus context?
- What happens if the user performs another action before clicking Undo?
- When does the recovery window expire, and how does the UI show final commitment?
- Is this actually trash restore, autosave recovery, retry, confirmation, or support recovery rather than undo?

## Filter reset that clears unrelated search (filter-reset-that-clears-unrelated-search)

Detect when:
- The result set combines keyword search, filter criteria, sort, scope, saved search, saved filter, pagination, view density, or layout state.
- The UI offers Clear filters, Reset, Clear all, Start over, chip removal, mobile drawer reset, no-results recovery, or saved-filter apply actions.
- Users expect a filter reset to widen results by removing constraints, not to destroy the query or saved context that defines the result universe.
- The page may use batch filter drafts, applied filter chips, saved presets, URL parameters, search history, or mobile drawers that make state ownership hard to see.

Why it fails:
- Implementing Clear filters by reinitializing the whole search page state object.
- Using one Reset button for draft filters, applied filters, query, sort, and saved search.
- Treating query text as just another filter chip without showing the difference.
- Clearing search history or saved search identity when only visible filters were reset.
- Resetting sort and pagination without explaining that the result set was re-ranked or repaged.
- Using Start over in no-results recovery when a scoped Remove date filter action would preserve useful context.
- Applying saved filters as if they were saved searches, clearing query and sort accidentally.

Replace with:
- Model query, filters, sort, scope, saved identity, pagination, and view mode as separate state owners.
- Name reset functions after the state they affect, such as clearFilters, clearQuery, clearSort, or resetAllResultState.
- Render query tokens separately from filter chips.
- Place Clear filters near applied filter chips and Clear search near the search field or query token.
- Keep one-chip removal, clear-all-filters, reset-draft, clear-query, and reset-all code paths separate.
- Preserve URL parameters and history entries for unrelated state when clearing filters.
- Add no-results recovery actions that loosen filters without erasing query text.
- Test saved filter application and saved search reruns to confirm only the intended state bundle changes.
- Test keyboard focus, mobile filter drawer reset, browser back, pagination, sort, and reload after every reset path.

Review question:
- What state does this reset control actually own?
- If the label says Clear filters, does the search query survive?
- Can users see query, filters, sort, scope, saved identity, and page state as separate tokens or controls?
- Does one-chip removal affect only one criterion?
- Does no-results recovery preserve the query that produced the empty set?
- What happens to saved search identity, search history, sort, pagination, URL parameters, and focus after reset?

## Hidden destructive account deletion (hidden-destructive-account-deletion)

Detect when:
- The product lets users create or authenticate an account that owns personal data, app data, profile data, messages, files, subscriptions, linked apps, child-account data, enterprise memberships, or authentication tokens.
- The deletion route may be hidden in support, legal copy, app-store disclosures, search, account deactivation, data export, privacy settings, or a disabled control.
- Users may attempt deletion after uninstall, while signed into the wrong account, while managing a child or enterprise account, or while a subscription, legal hold, fraud review, or billing dependency is active.
- The organization may be required to provide direct deletion initiation or a trackable erasure request, so the interface must prove that account deletion was reachable and not disguised as another task.

Why it fails:
- Hiding account deletion in a privacy policy, FAQ, support article, or exact-match help search.
- Offering only deactivation and keeping account data active.
- Presenting data export as the end of the account deletion process.
- Requiring users to email support with no identity check, expected response time, request ID, or status.
- Removing Delete account from the app after users uninstall or sign out.
- Using a small settings-row toggle or vague Delete button for account-level destruction.
- Omitting retained-data, subscription, linked-app, child-account, enterprise-policy, or wrong-account consequences.

Replace with:
- Inventory account creation routes, account settings, app settings, uninstall support paths, public web resources, support queues, data export pages, deactivation controls, and privacy settings.
- Trace whether a user can request deletion from each supported platform and after uninstall without contacting an unrelated support channel.
- Replace hidden, deactivation-only, export-only, or support-only routes with a direct deletion path or a trackable support-required deletion request.
- Show account identity, affected services, associated data, retained data, subscriptions, linked apps, export-first option, verification, typed confirmation, request status, and recovery window before final submission.
- Separate Delete account from Sign out, Remove from device, Delete one service, Unsubscribe, Download data, Disable profile, and Privacy settings.
- Block wrong-account deletion when the signed-in account, provider, workspace, or child-account context changes.
- Test search, mobile navigation, app uninstall, web deletion URL, multiple accounts, child account, enterprise-managed account, billing owner, legal hold, pending request, failed support case, and compact layouts.

Review question:
- Can users find account deletion from account settings without searching help?
- Can users request deletion after uninstall or outside the native app when needed?
- Is the visible route truly account deletion, or only deactivation, export, unsubscribe, sign out, or support contact?
- What exact account, provider, workspace, or child account would be closed?
- Which associated data is deleted, retained, transferred, public, backed up, or outside the product's control?
- Does the flow produce a request ID, status, receipt, or completion proof?
- Is this the hidden account-deletion anti-pattern, or should the corrected route be delete account, destructive action confirmation, typed confirmation, data export, privacy settings, or settings management?

## Icon-only ambiguous action (icon-only-ambiguous-action)

Detect when:
- A toolbar, table row, card, or compact navigation surface contains icon-only controls.
- The icon is not conventional in the product domain, resembles multiple actions, or changes meaning by context.
- The action can archive, delete, share, expose data, change permissions, spend money, or otherwise create user risk.
- Mouse users may see a tooltip, but touch, keyboard, voice, and screen reader users need the action name before activation.

Why it fails:
- Using a trash, tray, box, arrow, or exclamation icon for archive, delete, download, export, and warning actions without visible words.
- Providing an accessible name such as icon, more, or button instead of the action and object.
- Putting the only explanation in a tooltip that appears on hover but not focus or touch.
- Using the same icon for Archive on one page and Delete on another.
- Hiding destructive row actions until hover, then presenting only symbols.
- Relying on color or placement to distinguish icon actions with different consequences.

Replace with:
- Audit every icon-only button for visible action text, accessible name, affected object, and consequence.
- Prefer text labels for primary and high-risk actions; use icon plus text when space allows.
- If icon-only is justified, set a specific accessible name that describes the action, not the icon shape.
- Keep tooltip text supplemental and make sure keyboard and touch users receive equivalent information.
- Avoid reusing the same symbol for different verbs in the same product area.
- Pair destructive icon actions with confirmation, undo, or restore according to consequence and reversibility.
- Test with keyboard navigation, screen reader announcement, touch input, zoom, localization, and first-time users.

Review question:
- Can a first-time user name the action and consequence before pressing the control?
- Will the screen reader announcement match the visible label or tooltip text?
- Does the icon mean the same thing across this workflow and product area?
- Would a touch or keyboard user receive the same explanation as a mouse user?
- If the action is destructive or exposes data, is there confirmation, preview, undo, or restore?

## Inaccessible custom select (inaccessible-custom-select)

Detect when:
- A team replaces native select styling with divs, popovers, portals, or JavaScript-only menus.
- The control works for pointer users but fails keyboard, screen reader, voice, form submission, or zoom scenarios.
- The popup may lose focus, clip options, close unexpectedly, or update only visual text instead of the actual form value.
- The product needs a single known value, searchable known value, or multiple values but uses one generic custom dropdown for all cases.

Why it fails:
- Using divs with click handlers and no role, label, expanded state, or option semantics.
- Updating the visual label but not the form value that submits to the server.
- Closing the menu before keyboard or assistive technology users can inspect options.
- Losing focus when the popup is rendered in a portal or dismissed with Escape.
- Using a custom select for a long list that needs search or autocomplete.
- Using a single-select-style dropdown for multiple values without chips, removal, or clear selected count.
- Clipping options inside overflow containers or hiding them from screen readers.

Replace with:
- Start with native select and document why custom behavior is necessary before replacing it.
- If custom, choose the correct pattern: listbox for browseable single choice, combobox for typed filtering, or multi-select for multiple values.
- Expose stable label, popup relationship, expanded state, active option, selected option, and current value.
- Implement keyboard opening, arrow navigation, Home and End where appropriate, Enter or Space selection, Escape dismissal, and focus return.
- Keep options readable and reachable when rendered in portals, scroll containers, small screens, and zoomed layouts.
- Synchronize the selected value with form submission, validation, reset, and server-rendered defaults.
- Test with keyboard only and at least one screen reader before claiming custom select parity.

Review question:
- Can a keyboard-only user open it, inspect options, choose one, dismiss without change, and continue from the trigger?
- Does the screen reader announcement include label, current value, expanded state, option count or option names, active option, and selected state?
- Does the selected value submit, validate, reset, and hydrate like a real form control?
- Is this actually a select, or does the task need autocomplete, combo box, radio group, or multi-select behavior?
- What happens when the popup is clipped, the page zooms, or the user presses Escape?

## Infinite scroll with no footer access (infinite-scroll-with-no-footer-access)

Detect when:
- The page uses infinite scroll, auto-load-on-near-bottom, virtualized lists, dynamic feeds, product grids, search results, activity streams, or media streams.
- The page footer contains required or useful destinations such as privacy, terms, accessibility, cookies, contact, language, feedback, account, app download, sitemap, or support.
- Users may be trying to finish a task, compare loaded items, reach help, satisfy a legal requirement, unsubscribe, change privacy settings, or leave the stream.
- The product may also need reading position restoration, loaded-count disclosure, item identity, loading failures, offline retry, and mobile browser chrome behavior.

Why it fails:
- Putting Privacy, Terms, Accessibility, Contact, Cookies, or language links only in a footer that infinite scroll prevents users from reaching.
- Appending items every time the footer comes into view.
- Using a spinner at the bottom as the only end-of-feed indicator.
- Adding a Back to top control while still making the footer unreachable.
- Telling users to use search to find footer links.
- Letting keyboard users tab through newly inserted cards forever before footer links.
- Virtualizing items without preserving focused item or return position.
- Treating infinite scroll as harmless because analytics show high engagement, while users cannot complete support or legal tasks.

Replace with:
- Identify all footer-only links and decide whether each must also appear near the stream boundary, header, account menu, or help menu.
- Limit automatic batches before requiring an explicit Load more action.
- Render a stable loaded boundary with item count, loading status, end state, failure, and retry.
- Add Jump to footer or skip-to-footer behavior when long feeds precede required footer links.
- Keep footer links in the normal document flow and test them with keyboard and screen reader navigation.
- Preserve scroll and focus position after opening items, applying filters, sorting, navigating back, refreshing, or retrying.
- Avoid auto-loading while a user is keyboard-tabbing near the footer or focused on footer-access controls.
- Test mobile viewport height, virtualized list unmounting, browser back, reduced motion, offline failure, and slow network loading.
- Prefer pagination or load-more controls when the stream supports search, filters, exact review, task completion, or legal footer access.

Review question:
- Can a mouse, touch, keyboard, and screen reader user reliably reach the footer?
- Which required links are footer-only, and what happens if the footer is pushed away?
- How many batches auto-load before the user must choose Load more?
- Is there a visible loaded count, end state, loading failure, and retry?
- Can users jump to footer, back to top, and return to the same item after opening detail?
- Would pagination, Load more, card list, list view, or a bounded feed better match this task?

## Infinite spinner (infinite-spinner)

Detect when:
- A request can hang, fail silently, be queued for a long time, or lose its completion event.
- The screen or control remains disabled while an indeterminate spinner continues animating.
- Users need to decide whether to wait, retry, cancel, use stale data, leave the flow, or contact support.
- The system can detect elapsed time, retry count, request state, cached data age, or a support reference but does not surface it.

Why it fails:
- Animating a full-page spinner forever after a request times out.
- Replacing a failed API response with a loading state because error handling is missing.
- Disabling the only button with a spinner and no explanation, timeout, or alternate action.
- Showing a skeleton and spinner together while neither resolves to content or error.
- Making users refresh the browser to find out whether a payment, upload, report, or save completed.
- Keeping aria-busy set after the operation has failed or moved to the background.

Replace with:
- Define timeout thresholds per operation type, such as short inline saves, medium data loads, long imports, and background jobs.
- Pair every spinner with text that names what is loading or processing.
- After the threshold, replace or augment the spinner with elapsed status and actions such as Retry, Cancel, Use cached values, Keep working, or Contact support.
- Switch to determinate progress when the backend can expose stages, percent, item counts, or queue position.
- Preserve the affected task context so users can continue, retry, or report the problem without reconstructing their work.
- Instrument stalled requests and retry outcomes so the UI timeout is connected to real system state.
- Remove busy or disabled state when loading resolves, fails, is cancelled, or moves to background processing.

Review question:
- What exact UI state appears after the first wait threshold is crossed?
- Can the user safely leave, cancel, retry, or use cached data without losing context?
- Does the spinner name the operation and affected object, or only imply that something somewhere is happening?
- What prevents a failed request from being represented as loading forever?
- Can keyboard and screen reader users discover the timeout and recovery actions?

## Modal for nonblocking content (modal-for-nonblocking-content)

Detect when:
- The layer contains read-only help, status, preview, metadata, release notes, success feedback, onboarding tips, marketing, or supplemental explanation.
- The page behind the layer is the context users need for comparison, typing, scanning, filtering, or deciding.
- The modal has only OK, Close, Got it, or Dismiss and no necessary task outcome.
- Users encounter the interruption repeatedly, on mobile, during checkout, while editing, or inside a high-volume review workflow.

Why it fails:
- Showing success confirmation as a modal when an inline message, toast, or confirmation page would fit better.
- Opening help text in a modal that hides the field or table it explains.
- Putting a read-only preview in a modal when users need side-by-side comparison.
- Blocking the page for background sync, autosave, routine update, or informational release note.
- Using a modal for newsletter signup, promotion, or survey before the primary workflow is complete.
- Adding OK-only modals for generated status messages because the component library makes dialogs easy.

Replace with:
- Inventory every modal that contains only information, status, help, preview, release notes, promotion, or success feedback.
- Ask what background interaction must be prevented; if the answer is none, move the content out of a modal.
- Map each nonblocking modal to inline message, banner, toast, popover, drawer, disclosure, side panel, sheet, or full page based on scope and task size.
- Keep field help beside the field, record detail beside the record list, and page status near the affected workspace.
- Provide explicit close controls and Escape behavior for temporary nonblocking layers.
- Restore focus locally after popover, drawer, toast action, or disclosure dismissal.
- Make mobile layouts preserve the affected control or object instead of hiding it behind a full-screen informational modal.
- Track repeated announcements through notification history or release-note surfaces rather than redisplaying modal interruptions.

Review question:
- What action or risk requires background interaction to be blocked?
- Could users keep working safely if this information were inline, in a banner, in a popover, or in a drawer?
- Is the background page the context users need to understand the message?
- Does the layer have a real task outcome, or only OK, Got it, Close, or Dismiss?
- Can users recover the information after dismissing it?
- What happens on mobile, high zoom, keyboard Escape, and repeated visits?

## Pagination without current page (pagination-without-current-page)

Detect when:
- The interface splits a table, result list, collection, audit log, inbox, resource list, catalog, or search result into multiple pages.
- Users rely on page position to resume work, compare ranges, share URLs, move with previous/next, or confirm that filters and sort persisted.
- The UI may have identical page chips, previous/next-only controls, ellipses, cursor pagination, async loading, page-size changes, filters, sort, or browser back/forward.
- Current-page state may be missing visually, missing from accessibility semantics, out of sync with the result range, or lost after loading.

Why it fails:
- Showing page numbers as identical chips with no selected state.
- Relying on the browser URL as the only current-page indicator.
- Marking both a page number and Next as current.
- Leaving aria-current on a stale page after async navigation.
- Using disabled styling on the current page without accessible current-page text.
- Showing result range 41-50 while page 2 is highlighted.
- Hiding page numbers on mobile without replacing them with Page x of y or a current range.
- Treating cursor pagination as exempt from current-position feedback.

Replace with:
- Render pagination inside a labelled nav or equivalent region near the controlled results.
- Apply aria-current="page" to exactly one current page link or button when numbered pages are rendered.
- Include visible current-page wording or an accessible label such as Page 3, current page.
- Show the result range and total count near the pagination or collection summary.
- Disable, hide, or relabel Previous and Next at the first and last page without making unavailable actions look active.
- Keep page state, URL parameters, server cursor, result range, and visible records from drifting apart.
- Handle filter, sort, search, and page-size changes by moving to a valid current page and announcing the change.
- Test async loading, browser back/forward, reload, narrow layouts, ellipses, page-size selectors, and cursor-only pagination.
- Ensure current state is not indicated only by color, hover, focus ring, or disabled styling.

Review question:
- Which page or result range is current right now?
- Can users identify the current page visually, by keyboard, and through assistive technology?
- Do result range, URL, visible records, and page controls agree?
- What happens to current-page state after loading, filtering, sorting, page-size changes, browser back, and reload?
- Are previous and next clearly relative to the current page and unavailable at the edges?
- Is this actually task progress, hierarchy navigation, or a feed rather than pagination?

## Permission prompt with no context (permission-prompt-with-no-context)

Detect when:
- The prompt requests an operating-system, browser, or app-level permission for a device resource or powerful feature such as location, camera, microphone, photos, contacts, notifications, Bluetooth, clipboard, motion sensors, or storage access.
- The user has not yet chosen the feature that needs the resource, or the UI does not name the task and benefit before the system prompt appears.
- The product may use first-run onboarding, account creation, a splash screen, a fake setup checklist, or a broad modal to collect permission for speculative future use.
- Denial may be mishandled through repeat nags, blocked flows, settings dead ends, broad consent assumptions, resource mismatch, or loss of unrelated product access.

Why it fails:
- Requesting permissions on first launch because analytics show users may need the feature later.
- Asking for location, notifications, contacts, and photos as one setup checklist before explaining any task.
- Using vague benefit copy instead of naming the resource and feature.
- Triggering a system prompt from a custom modal close, page load, hover, timeout, or background script.
- Treating denial as a reason to block the whole product.
- Looping a custom prompt or browser prompt after denial.
- Requesting a more invasive permission than the feature needs.

Replace with:
- Inventory every system permission and map it to the exact feature action that first needs the resource.
- Remove first-run, splash-screen, onboarding, sign-in, page-load, and unrelated-navigation permission triggers unless the feature itself is being started.
- Write resource-specific rationale copy that names the task, resource, benefit, choice, fallback, and settings path.
- Split bundled resource asks into separate feature-triggered requests or lower-access alternatives.
- Add denial, dismissal, previously denied, permanently denied, limited, revoked, unavailable, and settings-required branches.
- Provide fallback routes such as manual address, upload file, paste code, type contact, chat-only mode, continue without notifications, or open settings.
- Test cold start, feature-triggered ask, grant, deny, dismiss, repeat visit, permanent denial, resource mismatch, bundled permissions, compact layout, keyboard order, and status messaging.

Review question:
- What exact user action made this permission necessary now?
- Can the user understand the resource, task, benefit, fallback, and denial outcome before the system prompt appears?
- Is the requested resource the least powerful option that works for this task?
- What does the product do after deny, dismiss, limited access, revoked permission, or permanent denial?
- Can users complete the core task through a manual or lower-access route?
- Is this a device permission, optional data-use consent, account authorization, notification preference, privacy setting, or human approval decision?

## Required field hidden by conditional logic (required-field-hidden-by-conditional-logic)

Detect when:
- A form has radio, checkbox, select, eligibility, account type, permission, or saved-draft answers that control which later answers are required.
- The required field may be visually hidden, collapsed, disabled, moved to another page, filtered out, or missing from the current route.
- Validation may run on the client, server, saved draft, review step, imported payload, or resumed session.
- Users need recovery after submit, browser Back, review edits, mobile accordions, assistive technology changes, and stale conditional answers.

Why it fails:
- Keeping a visually hidden input required because the backend schema says the field is required in some cases.
- Showing an error summary that links to an element hidden by CSS, collapsed accordion state, or conditional route logic.
- Using disabled required controls to represent unavailable answers.
- Clearing the trigger visually but leaving the old branch active in saved draft or server payload.
- Only marking required fields after failed submit, forcing users to discover branch rules by trial and error.
- Putting a required conditional field at the bottom of the form far away from its trigger.
- Nesting several required conditional fields inside one local reveal instead of splitting the flow.
- Relying on visual reveal animation without making new required fields discoverable to assistive technology.

Replace with:
- Create a requirement map that ties every conditional required field to its owning trigger, active condition, visibility state, payload key, and error target.
- Keep client validation, server validation, saved draft restoration, and review pages using the same condition rules.
- Reveal short required follow-ups beside the trigger; route larger branches to pages or steps with their own required indicators.
- Before submit, validate only fields whose triggers make them active and visible or routeable.
- When hiding a branch, clear or mark inactive its values, errors, dirty state, and review rows.
- When an error is produced for a hidden field, first restore the branch or route to the owning question, then focus the summary or field.
- Test with browser Back, saved drafts, server errors, review edits, mobile collapsed sections, screen readers, keyboard-only navigation, and stale branch values.
- Log or assert when validation references a hidden or missing DOM target so hidden blockers are caught before release.

Review question:
- Which trigger makes this field required, and is that trigger visible when the error appears?
- Can a hidden, disabled, collapsed, or off-route field ever block submit?
- What happens to values and errors when the trigger changes?
- Does the error summary link to a visible recoverable field?
- Does server validation return enough branch context to reveal or route to the missing answer?
- Can review edits or browser Back create newly required questions before final submit?
- Would this branch be clearer as a separate page, step, or review-gated question?

## Toast-only critical error (toast-only-critical-error)

Detect when:
- A payment, save, permission, destructive action, security, or data-integrity operation fails.
- The failed task still needs user action after the message appears.
- The only visible feedback is a toast, snackbar, banner flash, or notification that may auto-dismiss or sit away from the affected control.
- The product cannot guarantee the user saw, read, understood, and acted on the transient message before it disappeared.

Why it fails:
- Showing Payment failed as a small toast while the invoice page returns to its normal paid-or-unpaid layout with no retry path.
- Using a disappearing snackbar as the only feedback for failed save, failed delete, failed permission change, failed upload, or failed authentication.
- Placing the toast far from the failed form or table row so users cannot connect the message to the affected task.
- Auto-dismissing a technical error code that support needs the user to copy or reference.
- Replacing a contextual error state with a notification because it is easier to trigger from a global event handler.

Replace with:
- Classify errors by consequence before choosing the feedback surface: low-risk status can be transient, but blocking, financial, destructive, permission, and data-loss failures need persistence.
- Render the persistent error near the affected button, form, record, or page section and include the exact failed action in the heading.
- Keep retry, correction, undo, support, or alternate-path actions visible and keyboard reachable after any toast closes.
- Use a toast only as a duplicate announcement for urgent awareness, and link it to the persistent place where the user can recover.
- Preserve entered data, selected items, payment context, and reference IDs so users can retry or ask for help without reconstructing the task.
- Test the flow after the toast expires, with screen reader timing, reduced-motion settings, zoom, keyboard navigation, and delayed attention.

Review question:
- If the user looks away for five seconds, can they still tell what failed and what to do next?
- Does the recovery action remain attached to the invoice, form, file, or account setting that failed?
- Would a screen reader or keyboard user be able to act after the transient announcement has finished?
- Is the toast communicating low-risk status, or is it carrying the only explanation for a high-consequence failure?

## Toast-only success for completed transaction (toast-only-success-for-completed-transaction)

Detect when:
- The user has completed or appears to have completed an application, booking, order, payment, account change, survey response, publication, approval, or service request.
- The transaction may need a reference number, receipt, submitted detail summary, next-step timing, tracking, contact, cancellation, amend, save, print, email, or support path.
- The implementation uses a toast, snackbar, flash, or temporary notification as the only completion proof or redirects users to a dashboard without durable confirmation.
- Users may look away, use assistive technology, close the page, refresh, return from browser history, contact support, or need proof later.

Why it fails:
- Redirecting to a dashboard and showing a five-second Application submitted toast with no receipt page.
- Using a generic Done toast for payment, booking, order, application, and profile-change outcomes.
- Clearing the form immediately after submit without rendering a durable success state.
- Showing a toast before the server commit finishes.
- Putting the reference number only inside the toast.
- Hiding next steps, timing, or support path behind notification history.
- Letting users refresh or tap Submit again because no persistent completed state exists.
- Treating a queued offline or pending async action as completed transaction success.

Replace with:
- Identify which actions are completed transactions rather than disposable status events.
- Define the authoritative commit event, reference, receipt, timestamp, object identity, submitted summary, and next-step content before rendering success.
- Choose confirmation page for journey endpoints and success confirmation for in-context proof.
- Use toast only as secondary notification and provide a route to the persistent confirmation.
- Keep proof visible through toast expiry, refresh, Back, bookmarked return, dashboard redirect, and session recovery where permitted.
- Remove or guard duplicate submit controls after commit and ensure refresh cannot replay the transaction.
- Write success copy with the transaction name and proof, not vague Done or Success.
- Test with screen reader timing, keyboard navigation, slow readers, mobile viewport, support-reference copying, print/save behavior, and interrupted attention.

Review question:
- If the toast disappears, can users still prove the transaction completed?
- What reference, receipt, timestamp, or submitted details might users need later?
- Does the UI explain what happens next and when?
- What authoritative event proves the transaction completed before success is shown?
- What happens on refresh, Back, duplicate submit, bookmark return, or expired session?
- Should this be a confirmation page, in-context success confirmation, or only a disposable toast?

## Tooltip-only required information (tooltip-only-required-information)

Detect when:
- The hidden content is needed to complete a field, understand eligibility, choose an option, avoid a fee, meet a deadline, satisfy a document rule, or recover from a blocked control.
- The implementation uses a question-mark icon, native title attribute, aria-describedby tooltip, hover bubble, focus bubble, disabled-control tooltip, chart cell tooltip, or compact label tooltip as the only explanation.
- Users may be on touch devices, keyboard-only navigation, screen readers, high zoom, slow reading, switch control, or reduced pointer precision.
- The tooltip closes on blur, pointer out, Escape, scroll, validation rerender, viewport collision, route change, or mobile tap.

Why it fails:
- Putting accepted document types only in a help-icon tooltip.
- Putting password rules only in a field-focus tooltip.
- Putting eligibility thresholds only in a hover card or tooltip beside a question.
- Using a disabled button tooltip as the only explanation for why users cannot continue.
- Relying on native title attributes for required field format.
- Putting legal terms, fees, deadline consequences, or consent scope only in a tooltip.
- Hiding chart values, table definitions, or required column meaning only behind pointer hover.
- Using aria-describedby to hide instructions that disappear before the user can apply them.

Replace with:
- Inventory every tooltip, title attribute, help icon, and aria-describedby bubble in the flow.
- Classify each item as supplemental or required for task success, safe choice, validation, eligibility, legal consequence, or recovery.
- Move required text into visible helper text, inline message, validation copy, details disclosure, or popover content.
- Leave tooltips only for short supplemental descriptions tied to triggers that already have names.
- Provide explicit touch and keyboard routes for any help that users must intentionally open.
- Show blocked-action requirements beside the disabled or unavailable action, not only on hover.
- Test blur, Escape, pointer out, scroll, zoom, validation rerender, mobile tap, screen reader reading order, and slow-reader timing.
- Confirm the task can be completed correctly after all tooltips are dismissed.

Review question:
- Could users complete the task correctly if every tooltip disappeared?
- Is any tooltip text required to answer, choose, pay, upload, consent, or recover?
- Can touch users and keyboard users reach the same information before acting?
- Does validation repeat the exact hidden requirement when users miss it?
- Should this content be visible helper text, inline message, disclosure details, popover, warning text, or validation copy?
- What happens when focus leaves the trigger, Escape closes the tooltip, the page scrolls, or the viewport is narrow?

## Validation that clears user input (validation-that-clears-user-input)

Detect when:
- A form, editor, checkout, upload, import, authentication, or configuration screen validates user-entered values on blur, submit, save, retry, or server response.
- Validation can fail locally, through server-side rules, from normalization or masking, after session expiry, during autosave, or after a network error.
- The user may have entered multiple related fields, long text, uploads, selected options, pasted values, or formatted values that are expensive to recreate.
- Some sensitive values such as passwords, card verification codes, or one-time codes may need special clearing rules, but that exception must not be generalized to ordinary fields.

Why it fails:
- Calling form reset after submit regardless of success or failure.
- Replacing the user's raw value with an empty string when parsing fails.
- Re-rendering the form from default values after a server validation response.
- Clearing every field because one field was invalid.
- Clearing uploaded files without preserving valid file names or explaining the failed file.
- Using password-clearing rules as an excuse to clear ordinary text fields.
- Showing only a toast after data loss instead of restoring the user's work.
- Combining Reset and Submit controls so users accidentally erase work while fixing validation.

Replace with:
- Keep form state separate from validation state so adding an error cannot reset field values.
- On failed submit, render the previous submitted values back into every safe control before showing errors.
- Return server validation errors with field keys and the submitted values or preserve the client-side payload until response handling completes.
- Preserve raw and formatted values separately for masks, currency, dates, phone numbers, addresses, and IDs.
- Protect long text and uploads with local draft or temporary object state while validation runs.
- Handle network failure, retry, session expiry, route reload, browser Back, and reauthentication without falling back to blank defaults.
- Define explicit exceptions for passwords, card verification codes, one-time codes, and prohibited file contents; clear only those values and explain the reason.
- Test failed client validation, failed server validation, slow network, reload, reauth, mobile keyboard, pasted input, autofill, uploads, long textarea text, and screen reader recovery.

Review question:
- Which values survive client validation, server validation, retry, reload, and session return?
- Can the user edit the failing value directly, or must they retype it?
- Are valid sibling fields preserved when one field fails?
- Does formatting preserve raw input or explain how it was interpreted?
- What sensitive fields are deliberately cleared, and is the reason visible?
- Can long text, uploads, and selected options be recovered after an error?
- Does the error summary link to fields without rebuilding the form from defaults?

