Unexplained: CI lost its path to Forgejo at 17:42Z on 2026-08-28 and recovered on its own at 18:15Z #982
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#982
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Consolidating the 2026-08-28 CI outage, because its cause was never found and the evidence is currently spread across two closed issues, a burn-down record, and one session's working memory.
The hairpin fix that came out of this is not the explanation. It landed 23 minutes after CI had already recovered. So if this recurs, the removed hairpin is no longer available as an answer and this list is where the next person should start.
Timeline, all measured
Both ends are unexplained. Nothing is known to have changed at 17:42Z, and nothing is known to have changed at 18:15Z.
The strongest clue
At 17:56Z, in the middle of the failure window,
ward-doctorissued a curl toforgejo.coilysiren.meand got back a real HTTP 404. A 404 is an application response. The host was up, TLS completed, Traefik routed, and Forgejo answered.At the same time
gatewas taking 133 seconds to a connect timeout against the same hostname from the same cluster.So this was never "Forgejo is down" or "the path is broken." It was a path that worked for some flows and not others, concurrently. Any explanation has to account for that asymmetry, and most of the obvious ones do not.
Ruled out, with the evidence
99.110.50.213, which matched the live WAN address measured againstcheckip.amazonaws.comthe same afternoonresolve_release_reffallback - fires only after a network failure. It converted an unreadable error into a 404 and cost an hour of misdirection, but it is a diagnostic defect, not a causeStanding hypotheses, none confirmed
A. Gateway conntrack or NAT state exhaustion. Runner traffic was double-NATed, masqueraded by flannel and hairpinned again at the router. That path degrades under concurrency rather than failing cleanly, and it self-recovers when state ages out. Fits the asymmetry, the duration, and the spontaneous recovery. Not measurable - no access to the router, and no counters were captured at the time.
B. Transient upstream or WAN event. Would produce the same shape and also self-recover. Not measurable retroactively.
C. Concurrency threshold. Roughly 25 runner pods across both clusters long-poll the task queue continuously. A burst may have pushed the hairpin past a limit. Partially testable in principle, except klipper-lb SNATs every client to one pod IP so the Traefik access log cannot attribute load by source.
D. Something local to ser8. The failing runners were ser8's flight-deck pool, and ser8's own OOM lands inside the window. No mechanism found, kept only because the coincidence is unexplained.
A and C are the same family and are the most likely. Neither is provable from what was captured.
Why this is worth keeping open
The hairpin is gone. Both clusters now resolve
forgejo.coilysiren.mein-cluster to the tailnet address, landed in #976, and #912 is closed. So the leading hypothesis is no longer reachable as an explanation for a recurrence. If checkout starts timing out again, hypotheses A and C are off the table and something new is happening.Nothing was instrumented to catch this next time. That is the real gap.
Done-condition
Either the 17:42Z trigger is identified, or instrumentation exists that would identify an equivalent event. The second is the achievable one:
Related