feat(arxiv): a second daily digest for non-lensing papers - #356
Merged
Conversation
arxiv_papers.yml is strong lensing only. This adds its sibling, arxiv_interests.yml: the day's ten most relevant papers that are NOT strong lensing — black holes, dark matter, galaxy formation, statistics — filed into PyAutoMemory's new arxiv-interests.md, where the knowledge board renders them under the inbox with the same per-paper actions and a 🧹 button that clears a whole day and reveals the next. Separate workflow, not a second leg of the lensing digest: that one is the morning's Slack product and its Claude step is the single point of failure for the post. A broad second query, a much larger prompt and a second cross-repo push do not belong on that critical path — a bad day here must cost the interests list and nothing else. There is no Slack leg at all. Two stages, the house pattern. .github/scripts/arxiv_interests.py pages the whole announcement band across astro-ph.CO/GA/HE/IM and scores it against the reading interest profile (title hits count triple), keeping the top 60 with full abstracts; Claude then reads those and picks the ten, assigning each a reading-queue section. Neither stage could do the other's job: no keyword query answers "most interesting", and no prompt reads five hundred abstracts a day. Strong lensing is flagged, never excluded deterministically — a dark matter paper that mentions a lensing constraint matches the lensing net, gets dropped there as off-topic, and would fall through both lists. The prompt makes that one judgement, and the append on the Memory side dedupes against arxiv-inbox.md so nothing lands twice. It runs 30 minutes behind the lensing digest on the SAME announcement band (arxiv_fetch.announcement_band, imported not restated — two digests on different bands leave a seam a paper can fall through), which also means the inbox is already filed when the dedup runs. - arxiv_fetch.fetch() gains `start` for paging; the lensing query never needs it, a whole day of astro-ph always does. - spawn.py DROPs both new files: org secrets, a cron, a cross-repo push, and one reader's personal interest vocabulary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YTKUy8F2CevLpEgSz7xbnJ
Jammy2211
pushed a commit
that referenced
this pull request
Aug 27, 2026
Main moved (PyAutoMind#355/#356). Both conflicts were in the GENERATED dashboard pages, resolved by regenerating from the merged sources with `intake --apply dashboard` rather than by picking hunks; complete/index.md auto-merged. No source-of-truth file conflicted. All gates re-run green after the merge: lifecycle check, lifecycle index --check, registry_toc --check, intake dashboard --check, 252 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016c1SLkLDW6aEZCVf95XXeu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
arxiv_papers.ymlis strong lensing only. This adds its sibling,arxiv_interests.yml: the day's ten most relevant papers that are not strong lensing — black holes, dark matter, galaxy formation, statistics — filed into PyAutoMemory's newarxiv-interests.md, where the knowledge board renders them under the inbox with the same per-paper actions and a 🧹 button that clears a whole day and reveals the next.Pairs with PyAutoLabs/PyAutoMemory#66, which builds that surface. Independent: this side writes papers, that side renders them.
Why a separate workflow
The lensing digest works, it is the morning's product, and its Claude step is the single point of failure for the Slack post. A broad second query, a much larger prompt and a second cross-repo push do not belong on that critical path — a bad day here must cost the interests list and nothing else. There is no Slack leg at all; this exists to fill one surface.
Two stages
The house pattern — a deterministic stage that ranks, a Claude stage that judges. Neither could do the other's job: no keyword query answers "most interesting", and no prompt reads five hundred abstracts a day.
.github/scripts/arxiv_interests.pypages the whole announcement band across astro-ph.CO/GA/HE/IM and scores every paper against the reading interest profile (a term in the title counts triple, in the abstract once; the best-scoring topic becomes the suggested reading-queue section). Top 60 survive, with full abstracts.The scoring is a shortlist, never a verdict, and generous on purpose: a term that pulls in an off-topic paper costs one line of a 60-paper list Claude then ignores; a term missing costs a paper that never appears at all. Recall first, exactly as the lensing query is.
Strong lensing is flagged, not excluded
A deterministic exclusion would open a gap: a dark matter paper that mentions a lensing constraint in passing matches the lensing net, gets dropped by the lensing digest as off-topic, and falls through both lists. So each candidate carries
strong_lensingand the prompt makes that one judgement, in the only place that can. The append on the Memory side then dedupes againstarxiv-inbox.md, so nothing lands twice even if the judgement goes the other way.Timing
02:30 UTC, Mon–Fri, half an hour behind the lensing digest and on the same announcement band (
arxiv_fetch.announcement_band, imported not restated — two digests on different bands leave a seam a paper can fall through). Running second is load-bearing in one small way: by then the lensing digest has filed its papers intoarxiv-inbox.md, which is what the dedup reads. It also keeps the two cross-repo pushes off each other's toes.Empty days still stamp
last digest:and commit, so a quiet list is provably a quiet day rather than a broken filing — the same invariant the inbox carries (PyAutoMemory#58). There is deliberately no sweep: this list is a backlog the human clears a day at a time, and ageing batches out would silently delete the recommendations they asked to cycle through.Changes
.github/scripts/arxiv_interests.py(new) — the ranker, with a--selftestthe workflow runs before every fetch..github/workflows/arxiv_interests.yml(new) — fetch → Claude → file into PyAutoMemory, with the auth-vs-race split on the push retry thatarxiv_papers.ymllearned the hard way..github/scripts/arxiv_fetch.py—fetch()gainsstartfor paging. The lensing query never needs it (a band is ~1.5 papers); a whole day of astro-ph always does.scripts/spawn.py+docs/pyautobrain/spawn_spec.md— both new files DROP from the spawned templates: org secrets, a cron, a cross-repo push by name, and one reader's personal interest vocabulary, which is instance content by definition.Testing
pytest tests/245 passed, including the extended spawn-template contract.arxiv_fetch.py --selftestandarxiv_interests.py --selftestboth PASS; the latter's 11 checks cover topic routing for each of the four buckets, title-vs-abstract weighting, the lensing flag, and that ranking is deterministic and caps correctly.Not verified live: arXiv is unreachable from this session's network policy, so the ranker's scoring is tested offline only. The real band volume — and therefore whether the
MAX_PAGES = 12paging guard is generous enough — is unmeasured. The first run logsannounced=/scored=/shortlisted=counts to check against, and a truncated band emits a::warning::rather than silently dropping the band's oldest papers.Generated by Claude Code