whisper-money/tests/Feature/Ai
Víctor Falcón d3ec96b845
fix(onboarding): stop the AI rule-suggestion step from hanging forever (#705)
## Problem

A user reported being stuck forever on the onboarding "Looking for
patterns" step (the "Polishing your suggestions…" spinner). Confirmed in
prod: their `suggestion_runs` row has been stuck in `processing` for a
week, and `failed_jobs` shows `TimeoutExceededException:
GenerateRuleSuggestionsJob has timed out`.

### Root cause

- The user has 4,163 transactions — the largest onboarding dataset (max
with a completed run was 3,481). The Gemini generation exceeded the
job's `$timeout = 120`.
- The worker timeout is raised **outside** the `try/catch` in
`GenerateRuleSuggestions::run()`, so the code that sets `status =
Failed` never ran.
- `GenerateRuleSuggestionsJob` had **no `failed()` handler** (5 other
jobs do), so nothing flipped the run to `Failed`. It stayed
`processing`, `show()` kept returning `processing`, and the client
polled every 3s forever.
- The timeout never reached Sentry, so it was invisible. Only 1 user
affected, but it's a latent bug that recurs on any large account.

## Fix

**Backend** — add `failed()` to `GenerateRuleSuggestionsJob`: mark the
run `Failed` (only if not already terminal) and `report()` the exception
so these surface in Sentry.

**Frontend** (`step-ai-suggestions.tsx`) — belt-and-suspenders so the
client never spins forever even if the worker dies before it can mark
the run:
- `poll()` now guards against transient errors (network blip / expired
session / 5xx) instead of silently dying.
- A client-side deadline (3 min, just beyond the "up to two minutes"
copy) surfaces the existing "couldn't generate" screen with **Try again
/ Skip**.

Not included: raising the timeout / capping the number of groups sent to
Gemini so large accounts *complete* instead of just being able to skip.
Follow-up if we want big accounts to get suggestions.

## Tests

- `tests/Feature/Ai/GenerateRuleSuggestionsJobTest.php` — `failed()`
marks the run `Failed` + reports; doesn't overwrite an already-terminal
run.
-
`resources/js/components/onboarding/step-ai-suggestions-timeout.test.tsx`
— after the deadline the spinner gives way to the failed screen.

Green locally: pint, prettier, eslint, backend + frontend tests.
2026-07-20 18:10:51 +00:00
..
AiCategorizationGateTest.php AI auto-categorization: open to pro + consent, nudge free users (#561) 2026-06-19 14:08:40 +00:00
AiRuleLearnerTest.php fix(ai): surface learned-rule toast in edit modal and guard weak description keys (#635) 2026-07-04 11:00:15 +00:00
ApplyRuleSuggestionsTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
CategorizationOverrideRouteTest.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
CategorizationSchemaTest.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
CategorizeBackfillCommandTest.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
CategorizeOnboardingTransactionsJobTest.php AI auto-categorization: open to pro + consent, nudge free users (#561) 2026-06-19 14:08:40 +00:00
CategorizeTransactionWithAiListenerTest.php fix: stop double-dispatching transaction listeners (N+1 insert into jobs) (#620) 2026-07-02 13:26:45 +00:00
CategorizeTransactionWithAiTest.php AI auto-categorization: open to pro + consent, nudge free users (#561) 2026-06-19 14:08:40 +00:00
CategorizeTransactionsTest.php fix(ai): handle transient AI provider overloads — stop the Sentry noise and retry the dropped work (#595) 2026-06-26 20:07:06 +02:00
CategorizeUncategorizedTransactionsTest.php fix(queue): raise retry_after above the longest job timeout (PHP-LARAVEL-2D) (#645) 2026-07-05 09:31:23 +00:00
CategoryOverrideHandlerTest.php feat(ai): learn from category corrections so the AI stops repeating the same mistake (#608) 2026-06-29 19:12:15 +02:00
CategorySourceFilterTest.php feat(ai): auto-categorize transactions with AI (behind flag) (#535) 2026-06-15 16:35:20 +02:00
GenerateRuleSuggestionsJobTest.php fix(onboarding): stop the AI rule-suggestion step from hanging forever (#705) 2026-07-20 18:10:51 +00:00
RetryTransientAiCategorizationJobTest.php fix(ai): handle transient AI provider overloads — stop the Sentry noise and retry the dropped work (#595) 2026-06-26 20:07:06 +02:00
RuleSuggestionAggregatorTest.php feat(ai): learn from category corrections so the AI stops repeating the same mistake (#608) 2026-06-29 19:12:15 +02:00
RuleSuggestionConsolidatorTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
RuleSuggestionControllerTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
RuleSuggestionGeneratorTest.php fix(ai): don't report expected transient provider overloads (PHP-LARAVEL-44) (#655) 2026-07-07 10:55:02 +00:00
RuleSuggestionGuardTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00
SuggestRulesCommandTest.php feat(ai): suggest automation rules during onboarding (#523) 2026-06-13 22:51:15 +02:00