Repository navigation
test(backfill-images): fix the real signature regression #2812 misdiagnosed as a flake (#2813) - #2816
Merged
Merged
Conversation
…gnosed as a flake (#2813) The CI red `backfill-images-slug-filter.test.ts > restricts enumeration to the target slug` (`expected [] to deeply equal ['beta']`) was NOT a forks-pool timing flake. It is deterministic — fails 1/1 locally in isolation. Root cause: #2805 (48da7d8) widened collectImageUrls(publicDir, slug?: string) -> (publicDir, slugs?: string[]) and updated the prod call site + the new .js sibling test, but left this older .ts test passing a bare string 'beta'. The impl iterates `slugs?.length ? slugs : readdir(...)`; a string has truthy .length and iterates by CHARACTER ('b','e','t','a') -> no matching dirs -> empty map. retry:1 re-ran it, it lost again, and the plausible Node22/Vitest-4 forks-pool story made a dead signature read as stochastic noise. #2812's guard (`typeof collectImageUrls === 'function'`) was a no-op for this bug: the binding was a function; the call SHAPE was wrong. Fix (test-only, no production code touched): - Call sites pass arrays (['beta'], ['does-not-exist']), matching the #2805 signature. - The beforeEach guard now asserts the call CONTRACT (`collectImageUrls(publicDir, ['beta']).size === 1`), so a future signature/shape drift fails loudly at the guard instead of as a cryptic empty-map assertion. Verified: reverting a call to a bare string fails all 5 tests AT the guard line, confirming it is not a no-op. retry:1 policy (the issue's scope step): scanning the unit-tier CI log of DEV merge fdceca1 (which contains #2812 and still went red) shows EXACTLY ONE (retry xN) marker in the whole 1490-file / 11,541-test run — this test, which lost both attempts. There is no swarm of timing flakes behind retry:1. Keep retry:1 (it absorbs the documented cold-boot blip) but treat any retried-then-failed test as a deterministic bug first. Documented in docs/developers/reference/test-hygiene.md, alongside the structural finding that the beforeAll+async-import-shim shape is pervasive (119 shim modules, 615 beforeAll test files) and must NOT be mechanically guarded everywhere. Closes #2813 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
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.
TL;DR
The CI red that #2808/#2812 chased as a forks-pool timing flake was a deterministic signature regression. It fails 1/1 locally in isolation. #2812's hermetic-fixture rewrite shipped to DEV and the test still failed both attempts on the merge commit
fdceca151.Root cause
PR #2805 (
48da7d835) widened:…updated the production call site and the new
.jssibling test (test/unit/backfill-images-slug-filter.test.js, which calls with arrays), but left this older.tstest passing a bare string'beta'. The impl doesfor (const s of slugs?.length ? slugs : readdir(...))— a string has truthy.lengthand iterates by character ('b','e','t','a') → no matching dirs → empty map →expected [] to deeply equal ['beta'].retry:1re-ran it, it lost again, and the plausible "Node22/Vitest-4 forks pool" story made a dead signature read as stochastic noise.#2812's guard —
expect(typeof collectImageUrls).toBe('function')— was a no-op for this bug: the binding was a function; the call shape was wrong.Fix (test-only — no production code touched)
['beta'],['does-not-exist']), matching the Image-refresh step hit 361s on a full rebuild (publish spike #2802 follow-up) #2805 signature.beforeEachguard now asserts the call contract (collectImageUrls(publicDir, ['beta']).size === 1), so a future signature/shape drift fails loudly at the guard instead of as a cryptic empty-map assertion three lines down.Verified: 5/5 pass locally; reverting any call to a bare string fails all 5 tests at the guard line (
expected +0 to be 1), confirming the guard is not a no-op.retry:1 policy (the issue's scope step)
Ran the "surface every retry-dependent pass" step against the real CI environment — scanned the unit-tier log of DEV merge
fdceca151(the commit that contains #2812 and still went red):(retry xN)marker in the whole 1490-file / 11,541-test run — this test, and it lost both attempts. Summary:1 failed | 1487 passed | 2 skipped.retry:1. The single retried test was the deterministic regression above.Recommendation: keep
retry:1(it genuinely absorbs the documented cold-boot starvation blip; the smoke tier has the same lever for the same reason) but treat any retried-then-failed test as a deterministic bug first — reproduce in isolation before blaming the forks pool. No config change warranted on this evidence; the fix is diagnostic discipline, codified indocs/developers/reference/test-hygiene.md.Structural audit — don't mechanically guard the shape
The #2812 flake shape (per-file
beforeAllshared fixture + reaching a module through the workspace-first async-import shim) is pervasive: 119 modules contain the shim, 615test/**files usebeforeAll/afterAll, 432 boot a shared CAP fixture via module-levelcds.test(). Hundreds have both ingredients and are green. Bolting a contract guard onto all of them would be churn against a hypothesis this audit disproved — the shim/beforeAllshape was not the cause. Add a contract guard where a test's call shape can drift from its SUT's signature, not everywhere the shim appears.Scope
scripts/__tests__/backfill-images-slug-filter.test.ts— the actual fix.docs/developers/reference/test-hygiene.md— audit writeup + retry:1 policy (same doc as the Tests hardcoding counts/values that drift from source-of-truth constants — audit & convert #1089 source-of-truth-literal class; this is that class one layer up, at the function-signature level).Closes #2813.
🤖 Generated with Claude Code