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:
NuklearRabbit
2026-08-05 14:07:05 +00:00
parent e5307a7c0f
commit 6f77a30dce
17 changed files with 347 additions and 29 deletions
+32
View File
@@ -1862,3 +1862,35 @@ correlation propagation, real upstream readiness) was implemented in the sibling
- Local gates were **not** re-run this session: the environment this ran in has no
network and no Docker, so `docker compose build api` + `pytest`/`ruff`/`mypy` could not
be executed. Run them before deploying.
## Prepared demo failure separated from real integration health (2026-08-05)
The demo seed's single staged delivery failure (`BK-H-0020`) pinned the n8n integration
to **degraded** on every fresh reset. A viewer therefore saw a red-ish automation badge
for a failure that exists on purpose — the demo told an untrue story about itself.
- The seeded failure now carries its own error code, `demoScenarioTimeout`
(`app.models.outbox.DEMO_SCENARIO_ERROR_CODE`), instead of the generic
`connectionError` a real timeout produces. No schema change and no migration: the code
column already existed, is already surfaced and is already localizable.
- `derive_n8n_status()` counts `unexpected_failed` and `demo_scenario_failed` separately
and only lets real failures move the state. `latest_failure_at` (a health signal) now
ignores the staged failure; `latest_demo_scenario_at` reports it separately.
- `/api/v1/workflows` exposes `is_demo_scenario`; the Automation page shows a "Prepared
demo scenario" badge, an explanation that it is a simulated temporary failure that does
not affect automation health, and a distinct "Retry demo scenario" action. Translated
in nl-BE, en-GB and fr-BE; i18n key parity verified against en-GB.
- The carve-out is deliberately narrow: a real failure still degrades n8n, proven by
`test_a_real_failure_still_degrades_the_integration`. The retry stays a real
redelivery through the dispatcher — nothing is marked succeeded without an actual n8n
round trip — and the audit records `demo_scenario: true/false`.
- Also in this pass (earlier commit `e5307a7`): the demo manifest's MCP Hub summary no
longer derives "operational" from `MCP_HUB_REGISTRATION_ENABLED` alone.
- **Local gates, actually executed this session** against a real PostgreSQL 16 and a
fresh install of the pinned dependencies: `pytest` — **181 passed**; `ruff check .` —
clean; `mypy app` — clean (50 files); `tsc --noEmit` — clean; `npm run build` — clean.
The suite was made order-independent where it asserts on the seeded scenario
(`_reseed()` helpers), since earlier test files legitimately mutate the outbox.
- **Not done, and not claimed**: no deployment and no browser verification — the
environment this ran in has no network to `192.168.10.150` and no Docker, so the live
Unraid instance still runs the previous revision. Playwright e2e was not re-run.