fix: make podcaster-handoff failures visible (#487) (#495)

- Remove continue-on-error: true from the podcaster-handoff job so failures mark the workflow red - Remove the if-wrapper that swallowed handoff exit codes as warnings - Change script annotation from ::warning:: to ::error:: for actual handoff failures - Eligibility skips remain clean exits (::notice::) Operators can now clearly distinguish: - Eligibility skipped (notice, exit 0) - Endpoint/key not configured (notice, exit 0) - API rejected payload or command failed (error, exit 1 → red job) Closes #487 Co-authored-by: jmservera <jmservera@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Juan Manuel Servera committed Jun 15, 2026 at 19:24 UTC ea4449e1b88a11a73ac2549c7d7b4082cff0e656
3 files changed +11 -16
.github/workflows/crawl-and-publish.yml
+8 -13
@@ -1168,7 +1168,6 @@ jobs:
1168 needs: [analyze, generate, deploy]
1169 if: ${{ needs.analyze.outputs.run_mode == 'normal' }}
1170 runs-on: ubuntu-latest
1171 - continue-on-error: true
1171 permissions:
1172 contents: read
1173
@@ -1203,21 +1202,17 @@ jobs:
1202 PY
1203 )
1204 if ! python3 scripts/publish_manifest.py assert-eligible --manifest "$MANIFEST_FILE"; then
1206 - echo "::warning::Podcaster handoff skipped because the publish manifest is not eligible."
1205 + echo "::notice::Podcaster handoff skipped — publish manifest is not eligible."
1206 exit 0
1207 fi
1209 - ARGS=(
1210 - --week "$WEEK"
1211 - --article-url "$ARTICLE_URL"
1212 - --article-path "$PAGE_PATH"
1213 - --publish-run-id "$PUBLISH_RUN_ID"
1214 - --publish-mode "$RUN_MODE"
1215 - --manifest "$MANIFEST_FILE"
1208 + python3 scripts/podcaster_handoff.py \
1209 + --week "$WEEK" \
1210 + --article-url "$ARTICLE_URL" \
1211 + --article-path "$PAGE_PATH" \
1212 + --publish-run-id "$PUBLISH_RUN_ID" \
1213 + --publish-mode "$RUN_MODE" \
1214 + --manifest "$MANIFEST_FILE" \
1215 --podcast-config config/podcast.json
1217 - )
1218 - if ! python3 scripts/podcaster_handoff.py "${ARGS[@]}"; then
1219 - echo "::warning::Podcaster handoff failed or was rejected; weekly article publication remains complete."
1220 - fi
1216
1217 notify:
1218 if: ${{ (github.event_name == 'schedule' || github.event.inputs.publish_release == 'true') && needs.analyze.outputs.run_mode != 'dry-run' && needs.analyze.outputs.run_mode != 'candidate-only' }}
scripts/podcaster_handoff.py
+1 -1
@@ -483,7 +483,7 @@ def main(argv: list[str] | None = None) -> int:
483 )
484 post_handoff(endpoint, api_key, payload, timeout=args.timeout)
485 except PodcasterHandoffError as exc:
486 - print(f"::warning::{exc}")
486 + print(f"::error::Podcaster handoff failed: {exc}")
487 return 1
488 print("::notice::Podcaster handoff accepted.")
489 return 0
tests/test_pipeline.py
+2 -2
@@ -446,7 +446,7 @@ class WorkflowConfigTests(unittest.TestCase):
446 self.assertIsNotNone(download_step)
447 self.assertTrue(_uses_action(download_step, "actions/download-artifact"))
448 self.assertEqual(podcaster_job["if"], "${{ needs.analyze.outputs.run_mode == 'normal' }}")
449 - self.assertTrue(podcaster_job["continue-on-error"])
449 + self.assertNotIn("continue-on-error", podcaster_job)
450 self.assertNotIn("force-replace", podcaster_job["if"])
451 self.assertNotIn("restore", podcaster_job["if"])
452
@@ -467,7 +467,7 @@ class WorkflowConfigTests(unittest.TestCase):
467 self.assertIn('--publish-run-id "$PUBLISH_RUN_ID"', run_script)
468 self.assertIn('--publish-mode "$RUN_MODE"', run_script)
469 self.assertIn('--manifest "$MANIFEST_FILE"', run_script)
470 - self.assertIn("weekly article publication remains complete", run_script)
470 + self.assertNotIn("weekly article publication remains complete", run_script)
471 self.assertNotIn("--force", run_script)
472 self.assertNotIn("--dry-run", run_script)
473 self.assertNotIn("echo $PODCASTER_API_KEY", run_script)