Skip to content

tech-debt(ci): GitHubApi is shared by three modules but lives inside a size-frozen one, so the shared client can no longer gain a method #15411

Open

Description

@mrveiss

What

GitHubApi — the REST client for every CI pipeline script — is defined at
pipeline-scripts/ci_dispatch_watchdog.py:693, inside a module that is grandfathered at its
#14236 size ceiling with zero headroom
:

pipeline-scripts/ci_dispatch_watchdog.py: 1487 lines, ceiling 1487

Three modules already depend on it:

  • pipeline-scripts/ci_dispatch_watchdog.py (owner)
  • pipeline-scripts/ci_red_cause.py
  • pipeline-scripts/ci_dispatch_retry.py

A shared client that cannot grow is not shared — it is frozen. Any new call any consumer needs
must be implemented outside the client, in the consumer, which is the fork this repository's
canonical rules exist to prevent.

This already happened, today

PR #15396 added two calls the retry sweep needs — rerun_run (POST .../rerun-failed-jobs) and
rate_limit_remaining (GET /rate_limit). Put on GitHubApi where they belong, they took the
file to 1520 lines against the 1487 ceiling and python_file_size_ratchet_test failed, with
the correct message:

a grandfathered file may not grow (#14236) — the exemption freezes the size it was granted for,
it does not license more

The ratchet is right. So both functions now live in pipeline-scripts/ci_dispatch_retry.py as
module-level helpers over api.request(...), and GitHubApi — the thing that should own an
actions/runs/{id}/rerun-failed-jobs call — does not have one. The next consumer that needs a
re-run will either import from ci_dispatch_retry (a script, not a client) or write its own.

Nothing is wrong with either change in isolation. The structure guarantees the fork.

Fix

Extract GitHubApi into its own module — e.g. pipeline-scripts/github_api.py — and have
ci_dispatch_watchdog, ci_red_cause and ci_dispatch_retry import it. Two effects:

  1. The shared client can gain methods again, so rerun_run and rate_limit_remaining move back
    where they belong.
  2. ci_dispatch_watchdog.py drops well below its ceiling, and the shrink gets locked in per
    tech-debt(ci): the file-size ratchet says 'raising a ceiling must fail' but only blocks raises above the frozen baseline, so a shrink can be spent back #14498 — the ratchet only ever tightens.

This is a move, not a rewrite: no behaviour changes and the existing tests cover it.

Second, smaller consolidation in the same family

pipeline-scripts/ci_red_cause.py:113-126 models a closed vocabulary as bare strings plus
frozensets:

CAUSE_STARVATION = "runner-starvation"
CAUSE_PROVISIONING = "provisioning-failure"
CAUSE_TEST = "test-failure"
CAUSE_SUPERSEDED = "superseded"
CAUSE_UNDETERMINED = "undetermined"
INFRASTRUCTURE_CAUSES = frozenset({CAUSE_STARVATION, CAUSE_PROVISIONING})
REAL_FAILURE_CAUSES = frozenset({CAUSE_TEST, CAUSE_UNDETERMINED})

That is an enum with its membership axes expressed as side tables — the exact shape #14263
catalogues across 62 status enums. It works today and is well documented, so this is an
opportunity rather than a defect: a StrEnum with the two groupings as classmethods would make an
unhandled cause a type error rather than a silent CAUSE_UNDETERMINED.

Worth doing with the extraction above, since both touch the same three files, and worth
not doing alone.

Tasks

Acceptance criteria

  • GitHubApi is defined once, outside any file at its size ceiling
  • No consumer defines its own REST call against the Actions API
  • ci_dispatch_watchdog.py's recorded ceiling is reduced to its new size, not left at 1487
  • repo_tests/ci_dispatch_watchdog_test.py and ci_dispatch_retry_test.py pass unchanged

Related

Activity

  1. modified the milestones: Backlog, v0.12.0 on Sep 12, 2026
  2. mrveiss commented on Oct 9, 2026

    @mrveiss
    OwnerAuthor

    Sighting from widening the duplication-guard scan to pipeline-scripts/ (#17377), jscpd 5.0.6: a 9-line build_api()" clone between pipeline-scripts/ci_red_cause.pyandpipeline-scripts/release_sync_main.py`. This is the same shared-client class as this issue. The duplication guard ratchets it once #17377 lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions