fix(ci): stop regenerating the OpenAPI spec twice in the same UI build - #2444
Conversation
`ui:build` (extension:build + vite build) also runs `ui:openapi`, which recomputes and rewrites apps/gittensory-ui/public/openapi.json unconditionally. In both call sites that chain it after `ui:openapi:check` in the same job (ci.yml's "UI build" step, ui-deploy.yml's "Validate frontend" step), that regeneration is pure repeat work: the check step immediately before it just proved the committed spec is already byte-identical to what regenerating it would produce. ci.yml's "UI build" step's trigger condition (push || ui==true) is a strict subset of "OpenAPI drift check"'s (push || ui==true || uiContract==true), so the check step is guaranteed to have already run and passed whenever the build step runs. ui-deploy.yml chains both unconditionally in one command. In both places, run ui:build's other two steps (extension:build, the vite build) directly instead of the aggregate script. ui:build itself is untouched, so anyone invoking it standalone (local dev, or any future call site without a preceding check) still gets a correct, freshly-generated spec. Verified locally: running `ui:openapi:check` then the two split commands produces an identical build to `npm run ui:build`, and leaves apps/gittensory-ui/public/openapi.json byte-for-byte unchanged (untouched by git status) throughout.
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-02 01:08:42 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 3 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
…ssion test The prior commit removed the aggregate ui:build call from both places that chain it after ui:openapi:check in the same job. Add a small guardrail test (mirroring workflow-runner-labels.test.ts's raw-string read-and-assert style) that fails if either step's run command regresses back to invoking `npm run ui:build` -- verified locally by reverting the fix and confirming this test catches it before restoring.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2444 +/- ##
=======================================
Coverage 95.90% 95.90%
=======================================
Files 224 224
Lines 25175 25175
Branches 9154 9154
=======================================
Hits 24143 24143
Misses 419 419
Partials 613 613 🚀 New features to boost your workflow:
|
Summary
ui:build(extension:build && vite build) also runsui:openapi, which recomputes and rewritesapps/gittensory-ui/public/openapi.jsonunconditionally. Both places that chain it afterui:openapi:checkin the same job/step —ci.yml's "UI build" step,ui-deploy.yml's "Validate frontend" step — pay for that regeneration twice: the check step immediately before it already proved the committed spec is byte-identical to what regenerating it would produce.ui:build's other two steps (extension:build, the vite build) directly in both places instead of the aggregate script.ui:builditself is untouched, so anyone invoking it standalone (local dev, or any future call site without a preceding check) still gets a correct, freshly-generated spec — this is scoped to the two places that already verify freshness first.ci.yml's "UI build" step's trigger condition (push || ui==true) is a strict subset of "OpenAPI drift check"'s (push || ui==true || uiContract==true), so the check step is guaranteed to have already run and passed whenever the build step runs — confirmed by reading bothif:conditions.test/unit/ci-ui-build-openapi.test.ts: a small guardrail test (mirroringworkflow-runner-labels.test.ts's style) that fails if either step regresses back to invoking the aggregatenpm run ui:build. Verified it actually catches the regression by reverting the fix locally and confirming the test fails, then restoring.Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.md.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coverage— full unsharded run green (96.51% stmts / 95.49% branches), including the new guardrail test.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderatenpm run test:cigreen end to end.ui:openapi:checkthen the two split commands (extension:build, the vite build) directly — build succeeds, andapps/gittensory-ui/public/openapi.jsonis untouched (git statusshows no diff) throughout, confirming no redundant regeneration and no behavior change to the output.test/unit/ci-ui-build-openapi.test.tsfails, then restored the fix and confirmed it passes again.Safety
Notes
validate-code's remaining cost after that PR merged).