refactor(platform)!: move CI clients out of extension/ to platform/ - #579
Merged
Conversation
## Summary
### Why?
`platform/extension/buildrunner/{buildkite,githubactions}` were filed as extensions, but neither is one. Per [CLAUDE.md](CLAUDE.md), an `extension/{ext}` package holds the behavioral interface, its `Config`, and the `Factory` interface — `platform/extension/buildrunner/` had no Go package at its root at all, just two impl directories under an empty namespace. Both packages say so in their own doc comments: "It intentionally holds no BuildRunner interface or domain entity types."
What they actually are is vendor HTTP clients over `platform/http` — REST calls plus provider-specific vocabulary (Buildkite's state strings, GitHub Actions' status/conclusion pair, id encoding). That makes them siblings of `platform/http` and `platform/errs`, not extensions. The real `BuildRunner` contracts already live where they belong, at `submitqueue/extension/buildrunner` and `stovepipe/extension/buildrunner`; these clients are what those extensions' backends wrap.
### What?
Moves both packages up to `platform/buildkite` and `platform/githubactions` and deletes the now-empty `platform/extension/buildrunner/`. Pure relocation — no behavior, no signatures, no test logic changed.
Import paths and Bazel labels updated across the four consumer packages (`{submitqueue,stovepipe}/extension/buildrunner/{buildkite,githubactions}`), which keep their `platformbuildkite`/`platformgithubactions` aliases.
`platform/README.md` gains an entry for the two clients and a line on the `platform/` vs `platform/extension/` test, so the next vendor client lands in the right place.
In [doc/rfc/stovepipe/steps/build.md](doc/rfc/stovepipe/steps/build.md), only the *adopted* option is repathed. The rejected alternatives there describe a shared `BuildRunner` **interface**, which genuinely would have been an extension — so their `platform/extension/buildrunner` references are correct as written and left intact. The adopted option now also records why the shipped package is not an extension: it is precisely the option that declines to define a shared interface.
## Test Plan
- ✅ `bazel test //platform/buildkite/... //platform/githubactions/... //submitqueue/extension/buildrunner/... //stovepipe/extension/buildrunner/...` — 8/8 pass
- ✅ `bazel build //...` — 309 targets
- ✅ `make fmt` (no changes), `make lint`, `make check-gazelle`, `make check-tidy`
behinddwalls
marked this pull request as ready for review
August 12, 2026 03:55
mnoah1
approved these changes
Aug 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why?
platform/extension/buildrunner/{buildkite,githubactions}were filed as extensions, but neither is one. Per CLAUDE.md, anextension/{ext}package holds the behavioral interface, itsConfig, and theFactoryinterface —platform/extension/buildrunner/had no Go package at its root at all, just two impl directories under an empty namespace. Both packages say so in their own doc comments: "It intentionally holds no BuildRunner interface or domain entity types."What they actually are is vendor HTTP clients over
platform/http— REST calls plus provider-specific vocabulary (Buildkite's state strings, GitHub Actions' status/conclusion pair, id encoding). That makes them siblings ofplatform/httpandplatform/errs, not extensions. The realBuildRunnercontracts already live where they belong, atsubmitqueue/extension/buildrunnerandstovepipe/extension/buildrunner; these clients are what those extensions' backends wrap.What?
Moves both packages up to
platform/buildkiteandplatform/githubactionsand deletes the now-emptyplatform/extension/buildrunner/. Pure relocation — no behavior, no signatures, no test logic changed.Import paths and Bazel labels updated across the four consumer packages (
{submitqueue,stovepipe}/extension/buildrunner/{buildkite,githubactions}), which keep theirplatformbuildkite/platformgithubactionsaliases.platform/README.mdgains an entry for the two clients and a line on theplatform/vsplatform/extension/test, so the next vendor client lands in the right place.In doc/rfc/stovepipe/steps/build.md, only the adopted option is repathed. The rejected alternatives there describe a shared
BuildRunnerinterface, which genuinely would have been an extension — so theirplatform/extension/buildrunnerreferences are correct as written and left intact. The adopted option now also records why the shipped package is not an extension: it is precisely the option that declines to define a shared interface.Test Plan
bazel test //platform/buildkite/... //platform/githubactions/... //submitqueue/extension/buildrunner/... //stovepipe/extension/buildrunner/...— 8/8 passbazel build //...— 309 targetsmake fmt(no changes),make lint,make check-gazelle,make check-tidy