fix(ci): comment router and spam scanner fail every run after the hydrator gained new scripts - #915
Conversation
…rating jobs repair comment router and spam scanner sparse-check-out this repository and name the hydrator scripts individually. setup-state has since gained two more dependencies from the same directory: scripts/worker-blobs.ts, a static import of scripts/hydrate-state.ts even though the blob transport is dormant, and scripts/prepare-worker-record-cache.ts, which its cache step runs once records-source is worker. Neither is checked out, so setup-state fails and both lanes fail every run. Add both paths to the two sparse lists and derive the requirement in a test: it reads the scripts setup-state executes, follows their relative imports, and asserts every sparse hydrating checkout lists the closure. A hand-maintained list is what drifted, so the test does not restate today's list.
|
Codex review: needs maintainer review before merge. Reviewed July 29, 2026, 6:08 PM ET / 22:08 UTC. ClawSweeper reviewWhat this changesThe PR adds Merge readinessThis remains necessary: it is the open candidate fix for the comment-router and spam-scanner outage tracked in #914. The patch and its supplied before/after production and sparse-checkout proof are strong, but GitHub reports the branch as conflicted with current Priority: P1 Review scores
Verification
How this fits togetherThe comment router and spam scanner are scheduled GitHub Actions lanes that sparse-check out the ClawSweeper repository, hydrate operational state through the shared flowchart LR
A[Scheduled or comment dispatch] --> B[Comment router or spam scanner]
B --> C[Sparse repository checkout]
C --> D[Shared state setup]
D --> E[Hydrator and cache scripts]
E --> F[State hydration]
F --> G[Routing or spam triage output]
Before merge
Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Rebase onto current Do we have a high-confidence way to reproduce the issue? Yes, from source and supplied runtime evidence: materializing the old sparse lists omits statically imported state scripts and produces the documented module-resolution failure before routing or scanning begins. The PR body also shows the focused regression test failing when the workflow is reverted and passing with the added closure members. Is this the best way to solve the issue? Yes, conditionally: adding the missing scripts to the two affected sparse lists and testing the shared action’s current relative-import closure is the narrowest maintainable repair. The branch must first be rebased because its conflicted merge result has not been proven. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 8365a79af804. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (4 earlier review cycles)
|
Closes #914
What Problem This Solves
Fixes an issue where every
repair comment routerandspam scannerrun fails atsetup-state, before any routing or scanning happens, so@clawsweepercomment commands,waiting repair-dispatch retries, and spam triage are not processed at all.
Both jobs sparse-check-out this repository and name the hydrator scripts one by one:
./.github/actions/setup-statenow needs two more scripts from that directory, and neitheris checked out, so the action cannot run:
scripts/worker-blobs.ts— a static import at the top ofscripts/hydrate-state.tssince feat(state): R2-backed ledger/v1 + assets blob transport, migration workflow, and opt-in dual-read (phase 3 foundation) #899. The blob transport is dormant by default (
CLAWSWEEPER_LEDGER_SOURCEdefaults to git), but a static import is resolved before that default is consulted, so
the fail-safe does not cover it.
scripts/prepare-worker-record-cache.ts— run by theResolve Worker record snapshot cache keystep wheneverrecords-sourceisworker, which these two call sites becamein feat(state): make the records-source cutover flippable via repo variable #908.
The last successful router run was
run 30297600459 at
2026-07-27T19:17:31Zon9b4c227.c32e826landed at19:20:52Zand every run sincehas failed: 483 failures and no successes for the router, 13 and no successes for the spam
scanner, still failing on
aad59aaas ofrun 30352119688
(
2026-07-28T10:46:47Z).Why This Change Was Made
The two missing paths are added to both sparse lists. Because a hand-maintained list is
exactly what drifted here, the accompanying test does not restate today's list: it reads
the scripts
setup-stateexecutes, follows their relative imports transitively(
from "./x.ts"andimport("./x.ts"), either quote style), and asserts that every sparsehydrating checkout contains that closure. It also pins the affected call sites to those two
jobs, so a third one has to be acknowledged deliberately. It is a drift guard for the
import style this repository actually uses, not a general module resolver — an
extensionless, package-relative, or re-exported dependency would still need a manual entry.
Two alternatives are deliberately not taken here, as both are product decisions: making the
blob import lazy so a dormant transport is not an import-time dependency, and dropping the
sparse checkout from these two jobs.
User Impact
Both lanes hydrate generated state and run again. Operators also stop seeing the misleading
secondary failure: when
setup-statefails,setup-pnpmis skipped but the next stepstill runs, reporting
pnpm: command not found(exit 127) andCould not access .../clawsweeper-state/jobs/jobsinstead of the real cause.Evidence
Production failure, first run after
c32e826(run 30298180330,
2026-07-27T19:25:32Z, headc32e826):Production failure after
b9edc42(run 30328480253,
2026-07-28T04:20:35Z, headb9edc42). The cache step now fails first; it only runs whenrecords-source == 'worker', so its presence also shows the repository variable is set:Actions logs expire, so those lines are quoted rather than only linked.
The new test is red on the unfixed workflows and green with this patch:
(The aggregate count that follows differs by runner aggregation mode, so only the per-test
lines and
fail 0are quoted here.)A local reproduction materializes exactly the sparse list of
repair-comment-router.ymlat
b9edc42and runs the two commandssetup-stateruns (Nodev24.18.0):Areproduces the production error exactly. InChydration completes and the cachescript resolves, stopping at its own missing-secret precondition.
Scope check: parsing every workflow shows these are the only two jobs that sparse-check-out
this repository and call
setup-state. The closure is four scripts —hydrate-state.tsand
prepare-worker-record-cache.tsare the entry points, they reachworker-blobs.tsandworker-records.ts, andworker-records.tsimports only Node builtins.pnpm run checkon Nodev24.18.0ran 2,899 tests with 10 failures, all of which thishost causes and none of which this patch touches. Reverting the three changed files back to
b9edc42and re-running only the affected files reproduces the same ten by name:The causes are local: this host has Git
2.34.1, soGit must support --no-lazy-fetch for bounded missing-object recoveryfails the ledger recovery paths, and the bun/npmcontainment fixtures are absent. Everything else, including the whole workflow suite,
passed. CI is authoritative for these files.
Proof summary
Behavior addressed:
setup-stateaborts in the two sparse hydrating jobs becausescripts/worker-blobs.tsandscripts/prepare-worker-record-cache.tsare not checkedout, failing every
repair comment routerandspam scannerrun.Real environment tested: production GitHub Actions runs on
c32e826andb9edc42for the failure; a local Node
v24.18.0reproduction of the exact sparse file set forbefore/after.
Exact steps or command run after this patch:
Evidence after fix: the reproduction block above — hydration returns its
{"hydrated":[...],"recordsSource":"git",...}result instead ofERR_MODULE_NOT_FOUND,and the cache script resolves and stops at its own missing-secret precondition.
Observed result after fix: the test block above —
sparse hydrating checkouts carry the whole setup-state script closurepasses withfail 0, and fails by name when the workflows are reverted.What was not tested: no secret was exported and no request reached the Worker, so a
real
records-source=workerhydration is not demonstrated end to end. What isdemonstrated is module resolution plus the git-source hydration path; the outage itself
rests on the two production run logs above. The ten unrelated local
pnpm run checkfailures are host-caused and reproduce on the base commit, as shown above.