fix(ci): prevent overwrite of prior weeks on publish branch (#160)

* fix(ci): prevent overwrite of prior weeks on publish branch - Change cron to minute 30 to avoid GitHub Actions congestion (#155) - Analyze job: only copy current week's analysis files to publish (#154) - Generate job: only copy current week's content page to publish (#156) Closes #155, closes #154, closes #156 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(ci): address PR review feedback - Hydrate metrics from publish before tracking to preserve ledger - Hydrate analyzed data from publish before rollup generation to prevent stale rollups overwriting publish - Use generate-content output page_path instead of reconstructing path - Hard-fail when current-week required files are missing instead of silently no-op'ing Addresses Copilot reviewer feedback on PR #160. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Juan Manuel Servera committed May 25, 2026 at 15:46 UTC 82a00bfebdcaaf8fc253768ff1510e68a513a3a7
1 file changed +34 -3
.github/workflows/crawl-and-publish.yml
+34 -3
@@ -2,7 +2,7 @@ name: Crawl and publish weekly data
2
3 on:
4 schedule:
5 - - cron: '0 8 * * 1'
5 + - cron: '30 8 * * 1'
6 workflow_dispatch:
7 inputs:
8 publish_release:
@@ -290,6 +290,10 @@ jobs:
290 CURRENT_DATETIME="${{ steps.analysis-context.outputs.current_datetime }}"
291 PRESS_FILE="${{ steps.press-context.outputs.press_file }}"
292 mkdir -p data/metrics
293 + # Hydrate metrics ledger from publish so track_token_usage.py appends to
294 + # the canonical token-usage.jsonl rather than starting fresh each run.
295 + git fetch origin publish 2>/dev/null && \
296 + git checkout origin/publish -- data/metrics/ 2>/dev/null || true
297 PROMPT_FILE=$(mktemp)
298 python3 scripts/analyze_fallback.py --raw-json "$WEEK_FILE" --output "$OUTPUT_FILE" --current-datetime "$CURRENT_DATETIME" --print-prompt > "$PROMPT_FILE"
299
@@ -437,7 +441,12 @@ jobs:
441 git checkout -f -B "$DATA_BRANCH" "origin/$DEFAULT_BRANCH"
442 fi
443 mkdir -p data/analyzed data/metrics
440 - cp -r analyzed-data-backup/* data/analyzed/ 2>/dev/null || true
444 + # Only copy current week's analysis files — do not overwrite prior weeks
445 + # Required: current week's summary must exist or the pipeline is broken
446 + cp "analyzed-data-backup/${WEEK}-summary.md" data/analyzed/
447 + # Optional sidecars: conditionally generated
448 + cp "analyzed-data-backup/${WEEK}-correlations.json" data/analyzed/ 2>/dev/null || true
449 + cp "analyzed-data-backup/${WEEK}-press-context.md" data/analyzed/ 2>/dev/null || true
450 cp -r metrics-data-backup/* data/metrics/ 2>/dev/null || true
451 rm -rf analyzed-data-backup metrics-data-backup
452 # Restore squad learning state
@@ -504,6 +513,22 @@ jobs:
513 print(f"page_path={page_path.as_posix()}")
514 PYGEN
515
516 + - name: Hydrate analyzed data from publish
517 + env:
518 + WEEK: ${{ needs.analyze.outputs.week }}
519 + run: |
520 + set -euo pipefail
521 + git fetch origin publish
522 + # Restore prior weeks' analyzed files from publish so generate_rollups.py
523 + # sees accurate historical data. Skip the current week's file (already
524 + # present from the downloaded artifact).
525 + git ls-tree -r --name-only origin/publish -- data/analyzed/ 2>/dev/null | while read -r f; do
526 + case "$f" in
527 + *"${WEEK}"*) continue ;;
528 + esac
529 + git checkout origin/publish -- "$f" 2>/dev/null || true
530 + done
531 +
532 - name: Generate rollups
533 run: python3 scripts/generate_rollups.py
534
@@ -512,6 +537,7 @@ jobs:
537 DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
538 DATA_BRANCH: publish
539 WEEK: ${{ needs.analyze.outputs.week }}
540 + PAGE_PATH: ${{ steps.generate-content.outputs.page_path }}
541 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
542 run: |
543 set -euo pipefail
@@ -532,7 +558,12 @@ jobs:
558 git checkout -f -B "$DATA_BRANCH" "origin/$DEFAULT_BRANCH"
559 fi
560 mkdir -p content/weekly content/monthly content/yearly
535 - cp -r content-weekly-backup/* content/weekly/ 2>/dev/null || true
561 + # Required: use exact page_path from generate-content step; hard-fail if missing
562 + RELATIVE_FROM_WEEKLY="${PAGE_PATH#content/weekly/}"
563 + mkdir -p "$(dirname "$PAGE_PATH")"
564 + cp "content-weekly-backup/${RELATIVE_FROM_WEEKLY}" "$PAGE_PATH"
565 + # Monthly/yearly rollups are safe to copy since generate_rollups.py was seeded
566 + # with hydrated prior-week data (see Hydrate analyzed data step above)
567 cp -r content-monthly-backup/* content/monthly/ 2>/dev/null || true
568 cp -r content-yearly-backup/* content/yearly/ 2>/dev/null || true
569 rm -rf content-weekly-backup content-monthly-backup content-yearly-backup