ci: gate generated-artifact drift, and stop builds mutating tracked source (2/2) - #472
Open
josecarneiro wants to merge 9 commits into
Open
Conversation
…ource The repo commits the generated artifacts of @epilot/sdk and @epilot/cli, but nothing verified the committed copies matched their generators. CI ran generate-sdk and build on every push, tested the result and discarded it, so drift accumulated silently. Two gates in the test job: - after running both generators, fail if the tree is dirty, so a PR that changes a spec without regenerating is rejected with the command to run. - directly after `pnpm build`, fail if the tree is dirty, so a build can never quietly regenerate or re-fetch committed source. Checked before `pnpm test` so a dirty tree can only be the build's doing. The auto-release job now regenerates the CLI after bumping its version and stages all of packages/cli/. It previously staged only package.json: the pre-bump "Build and test CLI" step generated src/index.ts with the old version and "Rebuild CLI with bumped version" runs after the push, so neither produced output the release commit could carry. Gate 2 needs two client builds to stop generating. journey-client and configuration-hub-client were the only 2 of 52 running codegen from `build`; journey's `npm run openapi` fetched the live spec from docs.api.epilot.io and overwrote committed source, so a build had a network dependency and its result varied with whatever was deployed. Both now match the other 50: `build` only compiles, `typegen` moved to `prepublishOnly` so published tarballs still carry freshly generated types. Updating a spec stays the deliberate `npm run openapi` step from CONTRIBUTING.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MhYbcfHQfe7bk2R37P75zV
6 tasks
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
…ld-artifacts-outdated-1zq6jq-ci
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.
Part 2 of 2 — the actual fix. Stacked on #466, which does the one-off regeneration. Merge #466 first; GitHub will retarget this to
mainautomatically.Three files, ~40 lines. This is the part worth reviewing.
The problem
pnpm install && pnpm buildon a cleanmainleft 68 tracked files dirty. CI was building fine — it just never checked what it regenerated:CI regenerated the artifacts, then compiled and tested the freshly regenerated versions, then threw them away. That proves "the code compiles and tests pass." It never asks "do the committed files match what the generator just produced?" There was no
git diff --exit-codeanywhere in.github/workflows/, so drift was invisible by construction.The changes
Two gates in the
testjob:pnpm build, fail if the tree is dirty — a build can never quietly regenerate or re-fetch committed source. Placed beforepnpm testso a dirty tree can only be the build's doing, not a test writing a file.auto-releasenow stages what it regenerates. It previously staged onlypackages/cli/package.json. Two things had to be true together, and neither was:Generation already happened before release — that is why npm was always correct. But for the CLI it ran before the version bump, so
src/index.tsbaked in the old number, and the rebuild that fixes it runs after the push. Staging alone would have committed the wrong version.Gate 2 requires two client builds to stop generating. journey-client and configuration-hub-client were the only 2 of 52 clients running codegen from
build. journey'snpm run openapifetched the live spec from docs.api.epilot.io and overwrote committed source — so a build needed network access, mutated your working tree, and produced different output depending on what was deployed to prod at that moment. Both now match the other 50:buildonly compiles, andtypegenmoves toprepublishOnlyso published tarballs still carry freshly generated types. Updating a spec stays the deliberatenpm run openapistep fromCONTRIBUTING.md.Test plan
Verified locally on this branch (CI cannot run yet — see the note above):
pnpm buildexits 0 and leaves the tree clean (was 68 dirty files before this stack)pnpm lint— clean (524 files)mainafter the@epilot/cli@0.1.141release flagged exactly the four artifacts that release had left staleWhat this prevents
While the combined version of this work sat waiting for review,
@epilot/cli@0.1.141released off the back of #467 and re-introduced the identical drift onmainwithin the hour —definitions/entity-mapping.jsonstale against its spec,src/index.tsback to reporting0.1.51. The failure mode reproduces on its own roughly every release. These gates are what stop it.