Skip to content

ci: keep a blocking job that exercises the built bundles - #748

Merged
sroussey merged 2 commits into
claude/coverage-dist-bundle-fix-ew0vj8from
claude/coverage-blocking-dist-job
Aug 13, 2026
Merged

ci: keep a blocking job that exercises the built bundles#748
sroussey merged 2 commits into
claude/coverage-dist-bundle-fix-ew0vj8from
claude/coverage-blocking-dist-job

Conversation

@sroussey

@sroussey sroussey commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Based on #741 (retarget to main once that merges). Rebased onto origin/main (67bed681).

⚠️ Two CI notes, read these first

1. build is red, and it is inherited. main has not built since 5b94e05a@workglow/anthropic#build-types fails with Anthropic_StructuredGeneration.ts(57,41): error TS2739 … missing max_tokens, messages, model. This stack previously passed build only because its base predated the break; after rebasing onto current main it inherits the failure. Not caused by this PR and not fixed here — another agent owns that fix.

2. The test-vitest-dist job failed on its first run. It has been diagnosed and fixed — and the bundles were not the problem. Details below.

What

#741 makes vitest resolve every @workglow/* specifier to the package's src, which is what makes the coverage numbers mean anything. But vitest.config.ts attaches the plugin to every project unconditionally — not only to coverage runs — and testsRunAgainstSource defaults to source.

Enumerating the jobs in .github/workflows/test.yml: typecheck-budget, test-discovery, build, six test-vitest-*, merge-vitest-coverage, cleanup. There is no bun test job in the blocking workflow at all (grep test:bun .github/workflows/test.yml → nothing). So after #741, no job that can block a merge resolves a @workglow/* specifier through exports. A bun build entry that silently dropped a re-export reaches main and surfaces only in nightly-bun-parity.yml, which states in its own header that "Failures here are informational. They never block a merge", runs on a cron, and excludes rag,browser,provider-hft,provider-nodellama,provider-api,provider-cactus.

The .claude/CLAUDE.md sentence and the matching vitest.config.ts JSDoc both asserted that bundle integrity "is not left unguarded by the default" because of that nightly run. Wrong on both counts — it is not blocking, and it is not the whole suite.

Why this fix

  1. test-vitest-dist, a blocking job — needs: build, downloads the existing build-output artifact, runs bun run test:vitest:unit with WORKGLOW_TEST_TARGET: dist. It reuses the artifact the six existing jobs already share, so it costs a runner, not a build.
  2. scripts/test.ts skips --coverage when targeting dist. The denominator names packages/*/src and providers/*/src, so a bundle-targeted run reported all ~1286 source files at 0% — not a measurement of anything, and merging such a fragment would drag the total toward zero for reasons unrelated to how well the tree is tested. Skipping it is also what lets the new job reuse test:vitest:unit verbatim and produce no fragment, so merge-vitest-coverage needs no change.
  3. The two stale claims corrected, in .claude/CLAUDE.md and in the vitest.config.ts JSDoc that repeats it.

Explicitly rejected alternative — "scope the plugin to coverage runs only". It does not fix this. scripts/test.ts adds --coverage whenever CI is set, so in CI every run is a coverage run and would still resolve to src. The gap would be exactly as wide, with the config now implying otherwise.

Beyond the original plan: test-vitest-dist was added to cleanup's needs list. cleanup deletes the build-output artifact, and without that edge it could race a still-downloading test-vitest-dist.

What the first test-vitest-dist run actually found

The bundles are fine. The job ran the entire unit tier against built output and reported:

Test Files  1 failed | 514 passed | 3 skipped (518)
     Tests  1 failed | 5879 passed | 71 skipped (5951)

5879 tests passed against dist. The single failure was this PR's own new test, not a wiring defect:

FAIL  scripts  testRunnerArgs.test.ts > scripts/test.ts coverage flag
      > asks for coverage on an ordinary CI run
AssertionError: expected '["npx","vitest","run","examples/cli/s…' to contain '"--coverage"'

Root cause: the test spawned the runner with {...process.env, CI: "1"} and let WORKGLOW_TEST_TARGET come from the ambient environment. The test-vitest-dist job exports that variable for the whole step, so inside that job the "ordinary CI run" case inherited dist and became a second copy of the dist case — asserting --coverage is present while the runner correctly omitted it. The test failed in the one job it was added to support.

Fixed by pinning the variable explicitly in both cases ("source" / "dist") rather than inheriting it. Verified by re-running under the job's exact ambient environment:

$ WORKGLOW_TEST_TARGET=dist CI=1 vitest run --project scripts scripts/testRunnerArgs.test.ts
  Test Files  1 passed (1) / Tests  2 passed (2)

# and the old form reproduced under the same env, for contrast:
OLD form (inherits WORKGLOW_TEST_TARGET) has --coverage: false   ← the failure
NEW form (explicit source)               has --coverage: true

So the job is working exactly as intended: it ran the tier against the bundles, and the only thing it caught was an environment-dependent assumption in a brand-new test. That is a better first result than a green run would have been.

The other red job on this run, test-vitest-ai-provider-api, is a pre-existing job this PR does not touch.

Tests

scripts/testRunnerArgs.test.ts (2 cases), spawning the runner in --dry-run mode, which prints the command it would have spawned:

case pre-fix
CI=1, target source → command contains --coverage (the baseline) passes
CI=1, target dist → command does not contain --coverage fails

Deliberately a vitest file, not an addition to scripts/test.test.ts — that one imports bun:test, and a regression test for "blocking CI does not cover X" that itself does not run in blocking CI would be self-defeating. scripts is a real vitest project, so this runs in test:vitest:unit.

Actually executed locally:

  • vitest --project scripts: 4 files, 16 passed; and 2 passed under WORKGLOW_TEST_TARGET=dist CI=1.
  • With scripts/test.ts reverted: 1 failed / 15 passed — the dist case, as expected.
  • Manual confirmation of both dry-run outputs.
  • .github/workflows/test.yml parsed with a YAML loader: 12 jobs, test-vitest-dist present with needs: build and WORKGLOW_TEST_TARGET: dist, cleanup.needs includes it, merge-vitest-coverage.needs unchanged.
  • prettier --check clean.

Executed in CI: the new job itself — see above.

Risk / blast radius

One extra CI job, running the full unit tier a second time. From the first run: ~3m20s wall clock (03:04:05 → 03:07:26), comparable to the existing tiers and fully parallel with them.

If that ever proves unacceptable, the cheaper follow-up is a single dist-targeted suite that dynamically imports every runtime entry from stubSpecsFor and asserts each bundle namespace's export names are a superset of the source module's — narrower and aimed exactly at "a bun build entry silently dropped a re-export". Flagged as follow-up rather than primary because importing every entry has real side-effect and native-module hazards under Node, which the full tier does not.

A local CI=1 WORKGLOW_TEST_TARGET=dist run no longer writes coverage/. Nothing in the workflow reads it on that path.

The coverage denominator itself is untouched here — that is #749, deliberately separate, so the coverage delta stays readable.

Unverified

  • The build failure inherited from main (see the note at the top) is not diagnosed or fixed here.
  • Local runs were under Node v22.22.2, not the Node 24 CI uses; CI is the authority and has now exercised the real path.

Copy link
Copy Markdown
Collaborator Author

The build fix works. build and typecheck-budget now pass on this branch — the @workglow/anthropic#build-types error that has had main red since 5b94e05a is resolved, and CI got far enough to start the test tier, which it has not done on main in three commits.

The remaining failure, test-vitest-ai-provider-api, is not caused by this PR and is not fixable in code:

PermanentJobError: Authentication failed for XAI (StructuredGenerationTask): 403
"Your team … has either used all available credits or reached its monthly spending limit.
 To continue making API requests, please purchase more credits or raise your spending limit."
    at Xai_StructuredGeneration_Stream (providers/xai/src/ai/common/Xai_StructuredGeneration.ts:38:18)

That is an xAI billing state, not a defect. This PR changes one cast in the Anthropic provider and touches nothing under providers/xai. Blocker for a human: top up the xAI credits or raise the spending limit, then re-run. Nothing here should be merged or reverted on account of it.

Two things worth deciding separately, neither blocking this PR:

  • test:vitest:ai-provider-api makes real, billed provider calls on every PR run. That makes the check non-deterministic in a way no code change can repair — a spending limit, an expired key or a provider outage turns every open PR red at once, and it did. Worth considering whether it should be skipIf on missing credentials/credits (the pattern describe.skipIf(!RUN_QUEUE_TESTS) already used elsewhere in the suite), moved off the PR-blocking path, or both.
  • The 403 body is echoed into the public job log along with the team UUID. Harmless as credentials go, but it is provider account metadata appearing in CI output.

Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Correcting my previous comment — I misidentified this PR. It is the test-vitest-dist CI job, not an Anthropic build fix, and the green build here is not evidence of anything being repaired.

The accurate reading:

  • build / typecheck-budget pass here because this branch's base is old. ci: keep a blocking job that exercises the built bundles #748Add workspace source resolution for accurate coverage reporting #741main@9695d80d, which predates 5b94e05a — the commit that started the @workglow/anthropic#build-types failure (Anthropic_StructuredGeneration.ts(57,41), TS2739). Current main is 72120f33 and is red. So this branch simply has not inherited the break yet, and will once it rebases onto current main. A separate fix for that is in flight.

  • test-vitest-ai-provider-api — unchanged from my last comment, and still not this PR's problem: xAI returns 403 (used all available credits or reached its monthly spending limit) from Xai_StructuredGeneration.ts:38. A human needs to top up or raise the limit. The point about that job making real billed calls on every PR stands.

  • test-vitest-dist failing is this PR working as designed. It is the job this PR adds, and the PR body predicted this outcome verbatim: "Whether the dist unit tier currently passes… cannot be run here… If the bundles have an existing wiring defect, this job is what will surface it — which is the point, but it may mean a red first run that needs its own fix."

    That is now the interesting result rather than a nuisance: the first blocking run against the built bundles found something the six existing jobs never could, which is the entire argument for the job. Its failure should be diagnosed on its merits and fixed — either here or in a follow-up — not treated as a reason to drop the job.

Sorry for the noise.


Generated by Claude Code

claude added 2 commits August 13, 2026 03:54
Resolving @workglow/* to src is what makes the coverage numbers mean anything,
but the plugin is attached to every project unconditionally — not only to
coverage runs — so with the default in force no vitest job resolves a specifier
through `exports` at all. There is also no `bun test` job in the blocking
workflow. So after the source-resolution change, nothing that can block a merge
loads a built bundle: a `bun build` entry that silently dropped a re-export
would reach main and surface only in the nightly Bun parity run, which is
explicitly informational, runs on a cron, and excludes six sections.

Adds test-vitest-dist: reuses the existing build-output artifact and runs the
unit tier with WORKGLOW_TEST_TARGET=dist. It is in cleanup's needs list, since
cleanup deletes the artifact it downloads.

Scoping the plugin to coverage runs instead would not have worked: scripts/test.ts
adds --coverage whenever CI is set, so in CI every run is a coverage run and
would still resolve to src.

Also skips --coverage for a dist-targeted run. The denominator names package
sources, so such a run reported all ~1286 of them at 0% — not a measurement of
anything, and it is what lets the new job reuse test:vitest:unit unchanged and
produce no fragment for merge-vitest-coverage.

The CLAUDE.md and vitest.config.ts notes claimed bundle integrity was covered by
the nightly parity run; both now say what actually guards it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H797qbH356jjznKgUax63o
The coverage-flag test spawned the runner with `{...process.env, CI: "1"}` and
let WORKGLOW_TEST_TARGET come from the ambient environment. The new
test-vitest-dist job exports that variable for its whole step, so inside that
job the source-target case inherited `dist` and became a second copy of the
dist case — asserting `--coverage` is present while the runner correctly
omitted it. It failed in the one job it was added to support.

Both cases now state the target explicitly, so the assertions hold whatever the
runner is invoked under.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H797qbH356jjznKgUax63o
@sroussey
sroussey force-pushed the claude/coverage-blocking-dist-job branch from 5df29d6 to f097116 Compare August 13, 2026 03:54
@sroussey
sroussey merged commit e31022f into claude/coverage-dist-bundle-fix-ew0vj8 Aug 13, 2026
11 of 12 checks passed
@sroussey
sroussey deleted the claude/coverage-blocking-dist-job branch August 13, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants