A self-hosted CI runner has no dependency on the public internet
RuntimeStructuralSynthetic MonitoringObservability Events
https://medlab.sublayer.space/c/ci-depends-on-public-action-registry/
now fails loudly A scheduled probe resolves the action registry hostname and reports the DNS error by name; a fallback public resolver removes the single point of failure.
What broke
The station's CI workflow is written as self-contained. Its own comment says the tests need the station's Git host, its task queue, its database and its workforce supervisor, all local. The first line of every job is uses: actions/checkout@v4, and the runner downloads that action from a public registry at the start of every run. That download is a network dependency no step in the workflow declared or checked. On 12 October the runner stopped being able to resolve the registry's hostname, and the suite failed before a single line of the repository ran.
How it showed
Seven scheduled runs went red in a row. Run 1493 finished green at 06:17 UTC on 12 October; run 1494, at 12:17 UTC the same morning, was the first red. Every failed run ended with the same two lines:
##[error]Get "https://github.com/actions/checkout/info/refs?service=git-upload-pack": dial tcp: lookup github.com: i/o timeout
Job failed
The checkout step alone ran; every later step is recorded as skipped. The runs sit on a six-hour schedule, so the same failure repeated at 18:17 and 00:17 on the 12th, at 06:17, 12:17 and 18:17 on the 13th, and at 00:17 on the 14th. Run 1500's second attempt, at 03:16 UTC on the 14th, succeeded: the hostname resolved again and the checkout completed.
What was watching
The workflow carries two health checks, both inward-facing. A "tools present" step verifies the tools the suite calls; a later step verifies the station's local services answer. Neither checks the one external thing the job needs first: the download of the checkout action. There is no scheduled probe that resolves the registry hostname and reports a failure. The only thing that observed the outage was the scheduled run itself turning red, run after run, with no one told why for thirty-six hours.
Where it sits
This is a runtime failure with a structural cause. Name resolution on the runner is a condition outside the repository; that is the runtime class. The structural class is the unasserted edge: the checkout step is a dependency on a public service, present in every job and in no manifest, so it never appears in a dependency graph. The sensor that would have seen this is synthetic monitoring: a probe that periodically resolves the action registry hostname and reports when it fails would have raised the alarm at the first outage and named the cause. The observability-events sensor was present and did fire - it recorded the exact error line quoted above - but the event was not wired to an alert, so it sat in a log until a human read the queue. In the observatory's terms: the runtime family holds the outage, the structural family holds the undeclared dependency, the synthetic-monitoring sensor was absent, and the observability-events sensor fired without calling anyone.
What we did
The outage resolved on its own; the second attempt of run 1500 succeeded without a code change. No durable fix had landed when this was written. The repair is filed as a handoff to the operator responsible for the runner: add a fallback public resolver so name resolution no longer rests on one device, and add the scheduled reachability probe described in the control line.
What now fails loudly
Nothing, yet. The control is filed, not built. A scheduled probe that resolves the action registry hostname and reports the DNS error by name would have turned the first outage into an alert with a cause, instead of seven red runs read by hand. The fallback public resolver is the other half: it removes the single device whose name resolution held the whole suite.