diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 97847083..3ce95b5f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,6 +23,12 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: - uses: actions/checkout@v4 + with: + # Full history: bin/generate_last_modified.rb derives per-file dates + # via `git log -1 --format=%cI`. A shallow (depth-1) checkout collapses + # every file to the tip commit's date, so last_modified.yml regenerates + # differently than committed and fails validate:generated_freshness. + fetch-depth: 0 - name: Set up Node uses: actions/setup-node@v4 with: @@ -36,6 +42,12 @@ jobs: run: ./bin/pipeline ci - name: Playwright smoke check timeout-minutes: 12 + env: + # The first pwcli command cold-fetches @playwright/cli and its browser; + # on a fresh runner that exceeds the harness's 20s per-command timeout + # and aborts smoke at status 124 before any assertion runs. Loosen the + # cap for CI only — local runs keep the fast 20s default. + PWCLI_CMD_TIMEOUT: 180s run: | set -o pipefail ./bin/pipeline smoke 2>&1 | tee tmp/playwright-smoke.log diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 01ff52c4..ddca717a 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,6 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + # Full history: bin/generate_last_modified.rb derives per-file dates + # via `git log -1 --format=%cI`. A shallow (depth-1) checkout collapses + # every file to the tip commit's date, so last_modified.yml regenerates + # differently than committed and fails validate:generated_freshness. + fetch-depth: 0 - name: Set up Node uses: actions/setup-node@v4 with: @@ -26,6 +32,12 @@ jobs: run: ./bin/pipeline validate - name: Playwright smoke check timeout-minutes: 12 + env: + # The first pwcli command cold-fetches @playwright/cli and its browser; + # on a fresh runner that exceeds the harness's 20s per-command timeout + # and aborts smoke at status 124 before any assertion runs. Loosen the + # cap for CI only — local runs keep the fast 20s default. + PWCLI_CMD_TIMEOUT: 180s run: | set -o pipefail ./bin/pipeline smoke 2>&1 | tee tmp/playwright-smoke.log diff --git a/_data/community_stories.yml b/_data/community_stories.yml index 067b4b2d..10d4f9e5 100644 --- a/_data/community_stories.yml +++ b/_data/community_stories.yml @@ -1,5 +1,5 @@ --- -generated_at: '2026-06-29T01:31:09Z' +generated_at: '2026-07-08T12:57:57Z' tracks: - id: craftsmanship-lineage title: Craftsmanship Lineage @@ -10,15 +10,15 @@ tracks: as it moved from hallway conversations into durable community practice. interview_ids: - sergio-pereira-chicago-alt-net-software-craftsmanship-north-america-2011 - - ray-hightower-chicagoruby-software-craftsmanship-north-america-2011 - - michael-norton-cleveland-pittsburgh-community-software-craftsmanship-north-america-2011 - - london-software-craftsmanship-software-craftsmanship-north-america-2011 - - max-lancaster-dc-alt-net-software-craftsmanship-north-america-2011 - - zach-shaw-boston-sc-software-craftsmanship-north-america-2011 + - bobby-johnson-south-sound-net-software-craftsmanship-north-america-2011 + - charler-baker-denver-community-software-craftsmanship-north-america-2011 - drew-shefman-houston-adobe-user-group-software-craftsmanship-north-america-2011 - dustin-updyke-pittsburgh-sc-software-craftsmanship-north-america-2011 + - london-software-craftsmanship-software-craftsmanship-north-america-2011 + - max-lancaster-dc-alt-net-software-craftsmanship-north-america-2011 + - michael-norton-cleveland-pittsburgh-community-software-craftsmanship-north-america-2011 + - ray-hightower-chicagoruby-software-craftsmanship-north-america-2011 - ross-south-bend-software-craftsmanship-software-craftsmanship-north-america-2011 - - bobby-johnson-south-sound-net-software-craftsmanship-north-america-2011 - id: user-groups-as-learning-systems title: User Groups as Learning Systems summary: Conversations rooted in user-group ecosystems where engineers shared methods, @@ -41,11 +41,11 @@ tracks: interview_ids: - justin-love-windycityrails-2012 - milan-dobrota-jen-lindner-windycityrails-2012 - - stephen-anderson-windycityrails-2012 - - ryan-singer-windycityrails-2012 - - kevin-zolkiewiecz-windycityrails-2012 - - ginny-hendry-windycityrails-2012 - - eric-macadie-windycityrails-2012 + - adam-grandy-windycityrails-2012 - benjamin-oakes-windycityrails-2012 + - brian-liles-windycityrails-2012 + - eric-macadie-windycityrails-2012 + - ginny-hendry-windycityrails-2012 + - jim-remsik-windycityrails-2012 + - kevin-zolkiewiecz-windycityrails-2012 - movie-on-9-6-12-at-1-05-pm-windycityrails-2012 - - adam-grandy-windycityrails-2012 diff --git a/_data/interview_topics.yml b/_data/interview_topics.yml index ebe5fe31..76fb2aa5 100644 --- a/_data/interview_topics.yml +++ b/_data/interview_topics.yml @@ -1,5 +1,5 @@ --- -generated_at: '2026-06-29T01:31:09Z' +generated_at: '2026-07-08T12:57:57Z' summary: total_topics: 72 total_interviews_with_topics: 183 @@ -10,13 +10,13 @@ items: count: 29 transcript_count: 29 sample_interview_ids: - - chad-fowler-goto-conference-2015 - - anita-sengupta-goto-conference-2015 - - corey-haines-goto-conference-2015 - trisha-gee-goto-conference-2015 - rebecca-parsons-goto-conference-2015 - max-de-marzi-goto-conference-2015 - dean-wampler-goto-conference-2015 + - corey-haines-goto-conference-2015 + - chad-fowler-goto-conference-2015 + - anita-sengupta-goto-conference-2015 - alexandra-masterson-goto-conference-2015 - slug: developer-community-and-conference-conversations topic: developer community and conference conversations @@ -26,11 +26,11 @@ items: - interview-with-eric-kingery-general - interview-with-stephen-anderson-general - interview-with-carina-c-zona-general - - interview-with-katrina-owen-general - interview-with-zachary-shaw-general + - interview-with-katrina-owen-general - interview-with-michael-ficarra-general - - interview-with-rob-reynolds-general - - interview-with-randy-ellis-general + - interview-with-sandro-mancuso-and-tom-brand-general + - interview-with-ryan-slobojan-general - slug: community-building-and-user-group-organizing topic: community building and user-group organizing count: 21 @@ -39,8 +39,8 @@ items: - ryan-gerry-goto-conference-2014 - max-de-marzi-goto-conference-2014 - fred-guime-goto-conference-2014 - - micah-martin-software-craftsmanship-north-america-2013 - sandro-mancuso-software-craftsmanship-north-america-2013 + - micah-martin-software-craftsmanship-north-america-2013 - adewale-oshineye-software-craftsmanship-north-america-2013 - stephen-anderson-software-craftsmanship-north-america-2013 - mike-stringer-general @@ -50,8 +50,8 @@ items: transcript_count: 18 sample_interview_ids: - russ-olsen-goto-conference-2014 - - interview-with-giles-bowkett-author-rails-general - interview-with-matt-ruby-creator-of-vooza-general + - interview-with-giles-bowkett-author-rails-general - ashe-dryden-general - james-edward-grey-iii-general - charles-oliver-nutter-general @@ -74,8 +74,8 @@ items: count: 7 transcript_count: 7 sample_interview_ids: - - bill-scott-general - kumar-mcmillan-general + - bill-scott-general - daniel-x-o-neil-general - arthur-kay-general - carl-erickson-software-craftsmanship-north-america-2012 diff --git a/bin/generate_community_stories_page.rb b/bin/generate_community_stories_page.rb index 8a2114d6..8ce8863d 100755 --- a/bin/generate_community_stories_page.rb +++ b/bin/generate_community_stories_page.rb @@ -10,7 +10,9 @@ OUT_PAGE_PATH = File.join(ROOT, "interviews", "stories", "index.html") interviews = Generators::Core::YamlIo.load(INTERVIEWS_PATH, key: "items") -sorted = interviews.sort_by { |item| item["recorded_date"].to_s } +# Tiebreaker on id: recorded_date has ties and sort_by is not stable, so the +# first(10) track selections below must not depend on sort-impl tie order. +sorted = interviews.sort_by { |item| [item["recorded_date"].to_s, item["id"].to_s] } craftsmanship = sorted.select do |item| item["conference"].to_s.downcase.include?("software craftsmanship") diff --git a/bin/generate_interview_topics_page.rb b/bin/generate_interview_topics_page.rb index fac93eef..39dd3794 100755 --- a/bin/generate_interview_topics_page.rb +++ b/bin/generate_interview_topics_page.rb @@ -40,7 +40,10 @@ def slugify(value) end topic_items = topics.map do |topic, rows| - sorted_rows = rows.sort_by { |row| row["recorded_date"].to_s }.reverse + # Tiebreaker on id: recorded_date has ties (e.g. 7 interviews on one date), and + # sort_by is not stable, so first(N) sampling below would depend on sort-impl + # tie order. Committed output must be a pure function of data — id makes it total. + sorted_rows = rows.sort_by { |row| [row["recorded_date"].to_s, row["id"].to_s] }.reverse transcript_count = sorted_rows.count do |row| asset = assets_by_id[row["video_asset_id"]] asset && !asset["transcript_id"].to_s.strip.empty? diff --git a/bin/validate_generated_freshness.rb b/bin/validate_generated_freshness.rb index 3aee5b23..6f04b5d9 100644 --- a/bin/validate_generated_freshness.rb +++ b/bin/validate_generated_freshness.rb @@ -44,4 +44,10 @@ def git_diff_names(paths) warn 'Generated artifact freshness validation failed:' warn ' Run `bundle exec rake build` and commit regenerated tracked artifacts.' changed.each { |path| warn " - #{path}" } + +# Print the actual drift, not just filenames. Without this the gate is a black +# box — you see WHICH files differ but not HOW, which turns a CI-only reproduction +# into guesswork. --no-color keeps the log diff-clean. +diff, = Open3.capture2('git', '--no-pager', 'diff', '--no-color', '--', *changed, chdir: ROOT) +warn "\n--- drift diff ---\n#{diff}" exit 1