fix: make weekly release notify idempotent

Closes #238

Juan Manuel Servera committed Jun 5, 2026 at 19:21 UTC 268f5e7dcdd05d177b51a575c24a3cff1364bac3
3 files changed +18 -1
.github/workflows/crawl-and-publish.yml
+8 -1
@@ -771,8 +771,15 @@ jobs:
771 SUMMARY_FILE: ${{ needs.analyze.outputs.summary_file }}
772 run: |
773 WEEK=$(basename "$SUMMARY_FILE" | sed 's/-summary.md//')
774 + TAG="week-${WEEK}"
775 + TITLE="Week ${WEEK} — Tech Trends Summary"
776
775 - gh release create "week-${WEEK}" --title "Week ${WEEK} — Tech Trends Summary" --notes-file "$SUMMARY_FILE" --latest
777 + if gh release view "$TAG" >/dev/null 2>&1; then
778 + echo "::notice::Release $TAG already exists; updating it instead of failing."
779 + gh release edit "$TAG" --title "$TITLE" --notes-file "$SUMMARY_FILE" --latest
780 + else
781 + gh release create "$TAG" --title "$TITLE" --notes-file "$SUMMARY_FILE" --latest
782 + fi
783
784 - name: Post to Discussions
785 env:
.squad/agents/fry/history.md
+6
@@ -87,3 +87,9 @@
87 - Tests to add: merge helper validation (schema, dedupe, sorting, error handling), per-source failure handling, fallback paths, reproducibility gates, citation preservation.
88 - Metrics: per-source (name, host, duration, article counts, errors) and aggregate (source_count, failed_source_count, total articles, artifact size).
89 - Decision recorded in .squad/decisions.md.
90 +
91 +## Issue #238 notify triage (2026-06-05)
92 +
93 +- Run 27026348186 completed crawl, analyze, generate, and deploy successfully; only `notify` failed.
94 +- Root cause: `gh release create week-2026-W23` is not idempotent when the weekly release tag already exists, so rerunning/publishing the same week produced HTTP 422 `Release.tag_name already exists`.
95 +- QA fix: make notify update an existing weekly release with `gh release edit` instead of failing, while preserving release creation for new weeks.
tests/test_pipeline.py
+4
@@ -288,6 +288,10 @@ class WorkflowConfigTests(unittest.TestCase):
288 release_step = next((s for s in notify_job["steps"] if s.get("name") == "Create GitHub Release"), None)
289 self.assertIsNotNone(release_step)
290 self.assertEqual(release_step["env"]["SUMMARY_FILE"], "${{ needs.analyze.outputs.summary_file }}")
291 + release_run = release_step["run"]
292 + self.assertIn('gh release view "$TAG"', release_run)
293 + self.assertIn('gh release edit "$TAG"', release_run)
294 + self.assertIn('gh release create "$TAG"', release_run)
295
296 webhook_run = webhook_step["run"]
297 self.assertIn("curl -s -X POST \"$WEBHOOK_URL\"", webhook_run)