feat(orchestrator): build-lifecycle capabilities (symbols, visual baseline, provisioning, service directory, anti-cheat) - #144
Merged
Conversation
…eline, provisioning, service directory, anti-cheat) Implements five capabilities that were drafted as standalone @game-ci/* plugin skeletons (#128, #130, #132, #133, #136) as real orchestrator features instead. A plugin exists to add user-facing command surface - a new verb, engine, or deploy target (steam-deploy, runtime-test-framework, the engine plugins). None of these five are that. They are things that happen *to* a build or a running job, which is what orchestrator already does: it owns providers/ (where a job runs) plus services/ for cache, hooks, output, preflight, reliability, secrets and sync. Two of them overlapped existing orchestrator surface outright - anti-cheat registered options and no command at all (that is middleware-service), and screen-capture duplicated the built-in `images` output type. What landed: symbol-collector.ts + `symbols` output type - finds dSYM bundles, PDB, Breakpad, DWARF and IL2CPP maps under a build. Sits beside the existing coverage/logs/metrics built-ins because symbols must be captured at build time or they are gone: once the machine is torn down, every future crash report from that build is unsymbolicatable. A .dSYM is reported as one bundle entry rather than descended into, since the symbolicator needs the bundle structure intact. Uploading is left to the existing ArtifactUploadHandler - no vendor-specific upload path here. visual-baseline.ts + `visual-baseline` output type - digest-based comparison of this run's captures against the accepted reference set. Deliberately NOT perceptual diffing: a byte hash answers "did this change at all" exactly, with no image codec, and pretending it were a threshold diff would be worse than not offering one. An empty baseline reports as unverified rather than as a pass, so the check cannot go vacuous after an accidental baseline deletion. dedicated-server-provisioner.ts - docker-compose, systemd unit and ufw rules from a typed config. Pure functions; nothing is written or executed, so a generator bug cannot mutate a real host. Port protocol is always explicit (a UDP game port published as TCP yields a server that starts cleanly and is unreachable), the unit is ordered after docker.service so a reboot does not race the daemon, and it does not run as root by default. service-directory.ts - registry for exposed job endpoints, with the disclosure rules as the actual content. An ephemeral tunnel URL is an unauthenticated entry point into a machine holding source and credentials, and CI logs are often public, so visibility is explicit per service and formatForLog redacts the whole private URL - a random subdomain IS the secret, so partial masking would still leak it. Does not start tunnels; a caller registers whatever URL it resolved. anti-cheat-middleware.ts - preset over the existing Middleware type, running at post-build (before default-priority packaging, or an unprotected binary ships) with allowFailure forced false. The SDKs are NDA-gated so the command is caller-supplied rather than guessed; credentials go through OrchestratorSecret instead of being interpolated into a shell string. All five are exported from the package entry point. Tests: 50 new, passing under BOTH vitest and bun - they avoid vi.mock(module, fn), which is what makes the 244 pre-existing orchestrator failures fail under bun's runner, so this adds none of them. tsc --noEmit is clean and oxfmt has been applied.
|
Warning Review limit reachedNext included review available in 46 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The registry tests assert the number of built-in types, so adding `symbols` and `visual-baseline` broke them: 8 -> 10 built-in, and 9 -> 11 for the built-in-plus-one-custom case. Also adds both new names to the it.each parity list, so they get the same defined/name/builtIn coverage every other built-in type has rather than only being counted. Caught by CI, not locally: I had run only the new test files. Full `vitest run` now passes except two failures that reproduce identically on a clean main (an rclone step test, and cli-integration timing out under parallel load) - both pre-existing and unrelated.
frostebite
added a commit
to game-ci/documentation
that referenced
this pull request
Aug 24, 2026
…ns page Consolidates #586 (docs: plugin catalog for the 14 new game-ci/cli plugins) into this PR instead of merging it separately - #586 targeted docs/03-github-cli/04-configuration-and-plugins.mdx, which this PR renumbers to 05-configuration-and-plugins.mdx (it inserts 04-orchestrate-advanced/), so the two would otherwise collide on the same page under different filenames. Content is updated to match what actually shipped, not #586's original snapshot: - live-show, dev-tunnel, crash-symbol-upload, screen-capture, dedicated-server-provisioning and anti-cheat are removed from the plugin list - the first was dropped entirely (game-ci/cli#146: duplicated runtime-test-framework's player-launching, and the rest of its scope - broadcast, an AI-driven playthrough agent - doesn't belong in a CI tool), the other five were re-implemented as real Orchestrator capabilities rather than plugin skeletons (game-ci/cli#144), and are documented in a new "Not plugins: build-lifecycle capabilities" section instead. - steam-deploy and runtime-test-framework are marked "Implemented, loaded by default" rather than folded in with the drafts - they are real, working commands, just still subject to change. - Added a warning block reflecting game-ci/cli#145: every plugin here is experimental, none are published to npm, and each one warns at runtime (drafts on load, the two implemented ones when their command is actually used). #586 will be closed as superseded once this merges.
This was referenced Aug 24, 2026
frostebite
added a commit
that referenced
this pull request
Aug 24, 2026
…only symbols (#147) Only crash-symbol collection belongs in the Orchestrator. Debug symbols have to be captured at build time or they are gone for good, which genuinely is orchestrator's output-collection domain - it stays as the `symbols` output type and symbol-collector.ts, from #144. The other four capabilities from that same PR are moved back to being plugins, matching the other 10 experimental drafts (#145): visual-baseline.ts -> plugins/screen-capture (`capture` command) service-directory.ts -> plugins/dev-tunnel (`tunnel` command) dedicated-server-provisioner.ts -> plugins/dedicated-server-provisioning (`provision-server` command) anti-cheat-middleware.ts is dropped; plugins/anti-cheat is restored to its original options-only shape (its actual command, if there ever is one, has to come from EasyAntiCheat/BattlEye SDK integration, which is NDA-gated and was never real to begin with - the Middleware-based wiring only made sense while this lived inside orchestrator). The ported logic itself is unchanged (same generators, same tests) - only its home moves. Each of the three command-based plugins gets the same onLoad warning and `throws "not implemented yet"` command dispatch as the other drafts; anti-cheat keeps its existing onLoad warning, reworded to match the standard "[game-ci] WARNING: ... EXPERIMENTAL ..." phrasing used everywhere else. All four are marked `"private": true` like the rest, and their READMEs get the standard EXPERIMENTAL banner plus a "What's real" section pointing at the tested logic underneath. output-type-registry.ts and its test drop back to 9 built-in types (was 10 with visual-baseline); orchestrator's index.ts drops the four exports. Fixed while moving: screen-capture's tsconfig resolves a stricter BinaryLike type for crypto.Hash#update than orchestrator's does, even with identical @types/node - digestDirectory now passes a Uint8Array view instead of the raw Buffer, which satisfies both. Verified: `bun install --frozen-lockfile` passes; each new plugin's suite passes under both vitest and bun (34 tests, unchanged from before the move); onLoad/createCommand behavior driven directly (4 onLoad warnings, 3 commands throw on use); orchestrator's output-service suite (69 tests) still passes with the count fixed to 9 built-ins.
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.
Implements five capabilities as real orchestrator features, replacing the standalone plugin skeletons drafted in #128, #130, #132, #133 and #136 (now removed from #142).
Why these belong here
A plugin exists to add user-facing command surface — a new verb, engine, or deploy target (
steam-deploy,runtime-test-framework, the engine plugins). None of these five are that. They are things that happen to a build or a running job, which is exactly orchestrator's domain: it already ownsproviders/(where a job runs) plusservices/for cache, hooks, output, preflight, reliability, secrets and sync.Two overlapped existing orchestrator surface outright:
options:and no command at all — it hooks into an existing build, which is preciselyservices/hooks/middleware-service.imagesoutput type ("Screenshots, render captures, atlas previews").What landed
symbol-collector.ts+symbolsoutput type — finds dSYM bundles, PDB, Breakpad, DWARF and IL2CPP maps. Sits beside the existingcoverage/logs/metricsbuilt-ins, because symbols must be captured at build time or they're gone: once the machine is torn down, every future crash report from that build is unsymbolicatable. A.dSYMis reported as one bundle entry rather than descended into — the symbolicator needs the bundle intact. Uploading is left to the existingArtifactUploadHandler; no vendor-specific upload path here.visual-baseline.ts+visual-baselineoutput type — digest-based comparison against the accepted reference set. Deliberately not perceptual diffing: a byte hash answers "did this change at all" exactly with no image codec, and pretending it were a threshold diff would be worse than not offering one. An empty baseline reports as unverified rather than a pass, so the check can't go vacuous on a first run or after an accidental baseline deletion.dedicated-server-provisioner.ts— docker-compose, systemd unit andufwrules from a typed config. Pure functions: nothing written, nothing executed, so a generator bug can't mutate a real host. Port protocol is always explicit (a UDP game port published as TCP gives a server that starts cleanly and is silently unreachable); the unit is orderedAfter=docker.serviceso a reboot doesn't race the daemon; it doesn't run as root by default.service-directory.ts— registry for exposed job endpoints, where the disclosure rules are the actual content. An ephemeral tunnel URL is an unauthenticated entry point into a machine holding source and credentials, and CI logs are often public or archived — so visibility is explicit per service, andformatForLogredacts the whole URL. A random subdomain is the secret, so partial masking would still leak the reachable address. It doesn't start tunnels; a caller registers whatever URL it resolved (cloudflared, ngrok, LAN, k8s Service).anti-cheat-middleware.ts— preset over the existingMiddlewaretype. Runs atpost-build(ahead of default-priority packaging, or an unprotected binary ships) withallowFailureforced tofalseand not configurable — a build that skipped its integrity step but still produced a shippable player is the worst outcome, since it looks successful. The SDKs are NDA-gated, so the command is caller-supplied rather than guessed, and credentials go throughOrchestratorSecretinstead of being interpolated into a shell string.All five are exported from the package entry point.
Verification
vi.mock(module, fn)— which is what makes the 244 pre-existing orchestrator tests fail under bun's runner — so this adds none to that baseline.tsc --noEmitclean;oxfmtapplied to the new files only.plugins/unity/dist,bun.lock) deliberately reverted rather than committed.Merge order
Please merge this before #142 — #142 has already had these five skeletons removed, so landing this first keeps the catalog coherent at every commit.