Skip to content

Commit ad81228

Browse files
Jammy2211claude
authored andcommitted
feat(arxiv-digest): post a 'no new papers' heartbeat on empty days
Previously empty days were silent, so a quiet #papers was ambiguous — nothing found vs. a broken/delayed run. Per user (2026-07-13), always post: - count==0: a dedicated step writes a 'No new strong-lensing papers today' notice (no Claude call, zero subscription usage). - count>0 but Claude drops all as off-topic: Claude now writes the same notice instead of writing nothing. - POST always runs; a missing payload now means the Claude step failed silently (e.g. expired OAuth token) and fails loudly instead of masquerading as an empty day. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 9f8c318 commit ad81228

1 file changed

Lines changed: 57 additions & 10 deletions

File tree

.github/workflows/arxiv_papers.yml

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ name: pyauto-arxiv-papers
1111
# Scope (user, 2026-07-10): STRONG LENSING ONLY — astro-ph.CO / astro-ph.GA
1212
# papers whose abstract/title names strong lensing (tightest signal). Format:
1313
# CURATED — 1–3 AI-chosen highlights with short summaries, then a compact list.
14-
# Cadence: weekday mornings, skip silently on empty (no quiet-day post).
14+
# Cadence: weekday mornings. Empty days STILL post a short "no new strong-
15+
# lensing papers today" heartbeat (user, 2026-07-13) — so silence in #papers
16+
# always means a broken run, never a genuinely empty one.
1517
#
1618
# Timing: arXiv announces new astro-ph at 20:00 US Eastern, Sun–Thu, which is
1719
# ~01:00 UK (00:00 UTC in summer / 01:00 UTC in winter) — the papers are live in
@@ -81,8 +83,37 @@ jobs:
8183
echo "count=$count" >> "$GITHUB_OUTPUT"
8284
echo "Fetched $count strong-lensing paper(s) in the last ${LOOKBACK_HOURS}h."
8385
86+
- name: Build the "no new papers" notice
87+
# A genuinely empty day (zero keyword hits). We skip Claude entirely to
88+
# spend no subscription usage, but still write the heartbeat payload so
89+
# the POST step below has something to send. uk_date is read from
90+
# arxiv_papers.json, which the fetch always writes even at count=0.
91+
if: ${{ steps.fetch.outputs.count == '0' }}
92+
run: |
93+
set -euo pipefail
94+
python3 - <<'PY'
95+
import json
96+
uk_date = json.load(open("arxiv_papers.json"))["uk_date"]
97+
title = f"No new strong-lensing papers — {uk_date}"
98+
payload = {
99+
"text": title,
100+
"blocks": [
101+
{"type": "header",
102+
"text": {"type": "plain_text", "text": title}},
103+
{"type": "section",
104+
"text": {"type": "mrkdwn",
105+
"text": "No new strong-lensing papers on arXiv today. :telescope:"}},
106+
],
107+
}
108+
with open("slack_payload.json", "w") as f:
109+
json.dump(payload, f, indent=2)
110+
print(f"Wrote no-papers heartbeat for {uk_date}.")
111+
PY
112+
84113
- name: Summarise papers with Claude
85-
# Skip the Claude call entirely on empty days — no post, no usage.
114+
# Skip Claude on empty days to spend zero subscription usage — the
115+
# heartbeat above already wrote the notice. This runs only when there is
116+
# something to summarise.
86117
if: ${{ steps.fetch.outputs.count != '0' }}
87118
uses: anthropics/claude-code-action@v1
88119
with:
@@ -161,23 +192,39 @@ jobs:
161192
block holding the "*More:*" bulleted list of the rest.
162193
163194
IF, after dropping off-topic papers, NOTHING genuinely about strong
164-
lensing remains: do NOT write slack_payload.json at all (leave it
165-
absent). The POST step skips when the file is missing — an empty day
166-
makes no post.
195+
lensing remains, do NOT omit the file — instead write
196+
`slack_payload.json` with this exact "no new papers" notice (an empty
197+
day still gets a post, so silence in #papers always signals a broken
198+
run, never an empty one):
199+
200+
{
201+
"text": "No new strong-lensing papers — <uk_date>",
202+
"blocks": [
203+
{ "type": "header",
204+
"text": { "type": "plain_text",
205+
"text": "No new strong-lensing papers — <uk_date>" } },
206+
{ "type": "section",
207+
"text": { "type": "mrkdwn",
208+
"text": "No new strong-lensing papers on arXiv today. :telescope:" } }
209+
]
210+
}
167211
168212
Do not POST anything yourself, do not commit, do not modify any
169213
other file.
170214
171215
- name: POST to Slack
172-
if: ${{ steps.fetch.outputs.count != '0' }}
173216
env:
174217
SLACK_WEBHOOK_URL: ${{ secrets.PYAUTO_PAPERS_WEBHOOK_URL }}
175218
run: |
176-
# No payload = a genuinely empty day (fetch found rows, but Claude
177-
# judged none genuinely on-topic). Skip silently, do not fail.
219+
# Every path now writes slack_payload.json: the count=0 step writes the
220+
# "no new papers" heartbeat, and the Claude step writes either a digest
221+
# or that same notice. A MISSING file here is therefore no longer an
222+
# empty day — it means the Claude step failed silently (e.g. an expired
223+
# CLAUDE_CODE_OAUTH_TOKEN, the failure mode show_full_output guards
224+
# against). Fail loudly rather than masquerade as "nothing found".
178225
if [ ! -s slack_payload.json ]; then
179-
echo "No slack_payload.json — nothing genuinely on-topic today, skipping post."
180-
exit 0
226+
echo "::error::slack_payload.json missing — the Claude summarise step failed to write it (check for an expired CLAUDE_CODE_OAUTH_TOKEN). Empty days write the no-papers notice, so this is a real failure, not a quiet day."
227+
exit 1
181228
fi
182229
if [ -z "${SLACK_WEBHOOK_URL:-}" ]; then
183230
echo "::error::PYAUTO_PAPERS_WEBHOOK_URL not set — create the #papers Slack incoming webhook and add it as a repo secret."

0 commit comments

Comments
 (0)