Raxx · internal docs

internal · gated

RCA — tickets-e2e-smoke false FAIL: smoke script never updated for #4262 mailto-only contact page

Incident ID: 2026-08-09-tickets-e2e-smoke-mailto-drift Date: 2026-08-09 Severity: SEV-3 (non-blocking — the actual customer-facing golden path was healthy throughout; only the synthetic smoke's assertions were stale) Duration: Smoke test drift present since 2026-07-24 (PR #4335 merged); first detected/filed as a tracked issue 2026-08-07 07:06 UTC (#4429); root-caused and fixed 2026-08-09 Blast radius: CI/ops tooling only — tickets-e2e-smoke daily cron and the auto-filed type:reliability issue queue. No customer impact: tickets.raxx.app/new-conversation served HTTP 200 with a working mailto:support@raxx.app contact page the entire time. Author: sre-agent

Summary

The daily tickets-e2e-smoke cron (and pipeline #4832, a one-off manual trigger fired as collateral of the 2026-08-07 Woodpecker CI server replace — see docs/incidents/2026-08-07-woodpecker-server-replace-pip-cache-activation.md) failed and auto-filed issue #4429. Investigation found the customer-facing system under test was healthy: https://tickets.raxx.app/new-conversation returns HTTP 200 and serves a working "Contact Support" page whose submit button opens the visitor's email client pre-addressed to support@raxx.app. That page is the intended, durable, already-documented design (docs/ops/runbooks/freescout.md Failure mode G, shipped via PR

4335 / issue #4262 on 2026-07-24) — a deliberate interim fix for the

/new-conversation 404 (#4249) that predates the full web-form submission path planned under epic #651.

The smoke script (scripts/ops/tickets_e2e_smoke.py), however, was never updated after #4262 shipped. Step 2 asserted the page contained a method= form attribute (true only for a server-rendered form; the mailto page's <form id="form"> has none because a client-side JS handler intercepts submit). Step 3 POSTed synthetic form data to /new-conversation expecting a server-side ticket-creation response — there has never been one at this path; the static page returns HTTP 200 regardless of method, so Step 3 was producing a false-positive PASS while creating no ticket. Step 4 then failed to find that (nonexistent) ticket via the FreeScout API — masked by a second, independent bug: the API call was missing the CF-Access-Client-Id/ CF-Access-Client-Secret headers required by the /api/* CF Access application (decision=non_identity), so the actual response was an HTTP 403 CF Access block, not a clean "not found."

Both defects are fixed in PR #4446: Step 2 now accepts the documented mailto-only page shape, Step 3 SKIPs cleanly instead of asserting a meaningless POST, and both tickets_e2e_smoke.py and tickets_cleanup_smoke.py now send the CF Access service-token headers on every FreeScout API call.

Timeline (all times UTC)

Impact

What went well

What didn't go well

Root cause analysis

Detection

Resolution

Action items

# Action Owner Due Issue
1 Add a lint/checklist step that flags when a PR changes terraform/freescout/assets/new-conversation/index.html (or any file a smoke script asserts against) without touching the corresponding scripts/ops/tickets_e2e_smoke.py — even a comment-only CI reminder is enough to close the gap that let this drift for 2 weeks sre-agent 2026-08-23 #4449
2 Confirm the tickets-e2e-smoke-daily cron is actually firing every day on schedule (not just when incidentally triggered by unrelated manual runs) — check WP cron next_exec/execution history for gaps between 2026-07-24 and 2026-08-07 sre-agent 2026-08-16 #4450
3 Once epic #651 ships a real web-form submission path for /new-conversation, re-enable Step 3's live POST assertion (currently gated on is_mailto_only) and remove the SKIP branch sre-agent / feature-developer tracked against epic #651, no fixed date n/a — tracked on #651

References