fix: stop the prepared demo failure from degrading n8n integration health
The demo seed plants exactly one failed delivery (BK-H-0020) to demonstrate retry and audit. Because derive_n8n_status() counted any failure, every fresh reset pinned the n8n integration to "degraded" -- the demo showed a warning about a prop, which tells a viewer something untrue about the automation. The seeded failure now carries its own error code, demoScenarioTimeout, rather than the generic connectionError a real timeout produces. No column and no migration: last_error_code already existed, is already surfaced to the UI and is already localizable. - integration status splits failed into unexpected_failed and demo_scenario_failed; only unexpected failures may move the state. A staged failure alone leaves n8n operational. - latest_failure_at is a health signal and now ignores the staged failure; latest_demo_scenario_at reports it separately. - /api/v1/workflows exposes is_demo_scenario. The Automation page labels the run as a prepared demo scenario, explains that it is a simulated temporary failure that does not affect automation health, and offers a distinct "retry demo scenario" action. Translated in nl-BE, en-GB and fr-BE. - the carve-out stays narrow: a real failure still degrades n8n, and a genuine later failure of the same event overwrites the demo code with the real one. - the retry itself is unchanged and real: the event goes back on the outbox and the dispatcher delivers it to n8n like any other, so 19+1 becomes 20+0 only on an actual round trip. The audit records which kind of failure was retried. Tests that assert on the seeded scenario now reseed first, since earlier test files legitimately mutate the outbox and the suite shares one database. Verified locally against a real PostgreSQL 16: 181 passed, ruff clean, mypy clean (50 files), tsc clean, frontend build clean. Not deployed and not browser-verified.
This commit is contained in:
@@ -67,3 +67,34 @@ secret-free failure details to Fleet Ops. See `n8n/workflows/MANIFEST.md` for st
|
||||
- supports explicit manual retry;
|
||||
- preserves last error and response metadata;
|
||||
- does not hold a database transaction open during network I/O.
|
||||
|
||||
## Prepared demo failure versus real failure
|
||||
|
||||
The demo seed deliberately plants exactly one failed delivery (`BK-H-0020`, see
|
||||
`seed/workflow_runs.csv`). It exists to demonstrate retry and audit, so it must never be
|
||||
read as evidence that the automation is unhealthy.
|
||||
|
||||
It is distinguished by its `last_error_code`, `demoScenarioTimeout`
|
||||
(`app.models.outbox.DEMO_SCENARIO_ERROR_CODE`) — not by a new column, so no migration is
|
||||
involved. A real timeout produces `connectionError`; the two are never confused.
|
||||
|
||||
Consequences, all enforced by tests:
|
||||
|
||||
- `/api/v1/integrations/status` reports `failed` (everything), `unexpected_failed` (real
|
||||
failures only) and `demo_scenario_failed` separately.
|
||||
- Only `unexpected_failed` can move n8n off `operational`. A prepared failure alone
|
||||
leaves the integration **operational** — a staged prop may not raise a red flag.
|
||||
- `latest_failure_at` is a health signal and therefore ignores the prepared failure;
|
||||
`latest_demo_scenario_at` reports it separately.
|
||||
- `/api/v1/workflows` marks the run with `is_demo_scenario: true`. The Automation page
|
||||
labels it "Prepared demo scenario", explains that it is a simulated temporary failure,
|
||||
and offers a distinct "Retry demo scenario" action.
|
||||
- A genuine later failure of that same event overwrites the code with the real one, and
|
||||
from that moment it counts as a real failure — the carve-out is narrow by construction.
|
||||
|
||||
The retry itself is real in both cases: the event goes back on the outbox and the
|
||||
dispatcher delivers it to the configured n8n webhook like any other, so 19 succeeded +
|
||||
1 failed becomes 20 succeeded + 0 failed only when n8n genuinely accepts the delivery.
|
||||
Nothing is marked succeeded without a real round trip. The audit entry records
|
||||
`demo_scenario: true/false` so a staged retry is never mistaken for a production fix.
|
||||
A demo reset recreates the original 19 + 1 scenario.
|
||||
|
||||
@@ -36,7 +36,12 @@ Vehicle `MO-016` has two imported overlapping reservations. Expected: visible qu
|
||||
|
||||
### S5 — Failed workflow
|
||||
|
||||
One seeded outbox/workflow record is failed with a safe simulated connection error. Expected: dashboard and Automation page show it; Operations Manager can retry.
|
||||
One seeded outbox/workflow record is failed with a safe simulated connection error, coded
|
||||
`demoScenarioTimeout` so it is recognisable as a prepared scenario rather than a real
|
||||
incident. Expected: dashboard and Automation page show it, labelled as a prepared demo
|
||||
scenario; n8n stays "Operational"; the Operations Manager can retry it, after which the
|
||||
overview reads 20 succeeded and 0 failed. See `docs/11-n8n-integration.md`, "Prepared demo
|
||||
failure versus real failure".
|
||||
|
||||
### S6 — Grounded damage question
|
||||
|
||||
|
||||
Reference in New Issue
Block a user