fix(ci): make generated artifacts deterministic; unblock freshness + smoke gates#25
Merged
Conversation
actions/checkout@v4 defaults to fetch-depth: 1 (shallow). bin/generate_last_modified.rb reads per-file dates via `git log -1 --format=%cI`; on a depth-1 clone that returns the tip commit's date for every file, so CI regenerates _data/last_modified.yml with uniform wrong dates and validate:generated_freshness fails (a full local clone passes). Set fetch-depth: 0 in validate.yml + deploy.yml so CI has full history and regenerates identical bytes. Unblocks the Pages deploy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The freshness gate failed in CI (not locally) on community_stories.yml and interview_topics.yml. Root cause: both select interview IDs via `sort_by(recorded_date).first(N)`, and recorded_date has ties (e.g. 7 interviews on 2023-10-23). sort_by is not stable, so which IDs land in first(N) at a tie boundary was not a pure function of the data — it drifted between the dev and CI Ruby builds. Ruled out libyaml line-wrapping: interviews.yml has 145 wrapped lines and never drifted, so wrapping is platform-stable here. Add `id` as a total-order tiebreaker to both recorded_date sorts so committed generated artifacts are deterministic regardless of sort implementation. Also instrument validate_generated_freshness.rb to print the actual `git diff` on failure, not just filenames — the missing diff is why this was CI-only guesswork. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
With the freshness gate now passing, CI reached the Playwright smoke step and failed at status 124 (~21s in) on the very first pwcli command. Root cause: bin/smoke_playwright.sh caps each pwcli call at PWCLI_CMD_TIMEOUT (20s), but the first call cold-fetches @playwright/cli and its browser on a fresh runner, which exceeds 20s and aborts before any assertion runs. Set PWCLI_CMD_TIMEOUT=180s for the CI smoke step only (local keeps the fast 20s default) so the one-time cold fetch fits. Applied to both validate and deploy. Co-Authored-By: Claude Opus 4.8 <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.
Problem
The Pages deploy was silently blocked at the
validate:generated_freshnessgate. Diagnosed from CI's actual output (local always passed). Two independent causes, uncovered in sequence:community_stories.ymlandinterview_topics.ymlselect interview IDs viasort_by(recorded_date).first(N).recorded_datehas ties (e.g. 7 interviews on2023-10-23), andsort_byis not stable — so which IDs land infirst(N)at a tie boundary was not a pure function of the data, and differed between the dev and CI Ruby builds. Ruled out libyaml line-wrapping (my first theory):interviews.ymlhas 145 wrapped lines and never drifted, so wrapping is platform-stable here.pwclicommand cold-fetches@playwright/cli+ its browser under a 20s per-command cap, before any assertion runs.Fix
idtiebreaker to bothrecorded_datesorts → committed artifacts are a pure function of their input, independent of sort implementation.validate_generated_freshness.rbnow prints the actualgit diffon failure, not just filenames — the missing diff is why this was CI-only guesswork.PWCLI_CMD_TIMEOUTto 180s for the CI smoke step only (local keeps the fast 20s default). Applied tovalidate.yml+deploy.yml.fetch-depth: 0(full history forlast_modifieddate derivation) — defensive hardening, harmless.Verified
Freshness gate green in CI (the run progressed past
validateto the smoke step). Smoke-timeout fix verification in progress on the latest push.Merge note
This is the keystone. Merge first — it unblocks both gates and lets the deploy (same smoke step) complete. PRs #26 and #27 branch off pre-fix
masterand should be rebased onto updatedmasterafter this merges, or their CI will show the same (already-fixed) red.🤖 Generated with Claude Code