review-reviewers: pause the hourly sweep, keep it as a manual spot-check - #966
Conversation
The outside-in sweep caught real wrong-outward-action defects early — rubber-stamped approvals over red checks, corrupted published comment bodies, dropped mentions on stale PRs — but its recent output has converged on maintaining its own evidence machinery, at the fleet's highest per-run cost and a seven-day quota ceiling that twice took the user-facing workflows down with it. Each adopter's daily tend-review-runs already reviews that repo's runs from the inside and routes bundled-skill defects upstream, so pausing removes the direct loop rather than the only one. Dropping the cron and keeping workflow_dispatch leaves it one click away for a release, harness switch, or model bump. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tend-agent
left a comment
There was a problem hiding this comment.
Two notes, neither blocking.
The re-enable path inherits a window limit the docs don't mention. list-recent-runs.sh anchors on the previous successful run of the calling workflow and clamps that floor at 6h (floor_cap=$((now - 21600))), warning on stderr when the clamp bites. With the cron gone, any dispatch more than 6h after the last one hits the clamp: a spot-check run the day after a release analyses only the last 6h of the target repo, and Step 1 of the skill then tells the session to "Record a coverage gap, not an all-clear" rather than reporting on the release it was dispatched for. Inline suggestion adds a line to the overlay paragraph so whoever dispatches knows to do it promptly.
The bundled skill this workflow invokes still describes itself as hourly: plugins/tend-ci-runner/skills/review-reviewers/SKILL.md carries description: Hourly outcome-based analysis of tend's CI behavior… in its frontmatter and opens with "Analyze tend's CI behavior on the target repo over the past hour" — the past hour being the one window a dispatched run will never be looking at. (The hourly/review-$GITHUB_RUN_ID-… branch prefix further down is cosmetic; the frontmatter description is what shows in the skill list.) It's outside this diff — happy to push a commit rewording those two if you want it folded in here.
The skill described itself as hourly in its frontmatter and told the session to analyze 'the past hour'. With the cron gone, the window-anchoring in list-recent-runs.sh no longer applies at all: it keys on an hourly cron, so a dispatched run silently takes a now-anchored hour, and the coverage-gap warnings live on the path it doesn't take. A spot-check dispatched after a release would have reported an all-clear over an hour that didn't contain it. Scope the claims to the window instead of widening it — the window logic is being reworked separately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tend-agent
left a comment
There was a problem hiding this comment.
The new window paragraphs describe a mechanism list-recent-runs.sh doesn't have, and the bundled-skill one contradicts the paragraph directly above it.
The script has no trigger-aware branch — nothing in plugins/tend-ci-runner/scripts/ reads GITHUB_EVENT_NAME, schedule, or cron. The single branch is on GITHUB_WORKFLOW: when it's set, the floor is the previous successful run of the calling workflow (gh run list --workflow "$GITHUB_WORKFLOW" --status success), clamped at floor_cap=$((now - 21600)); the COMPLETED_AFTER=$((now - 3600)) past-hour path is the else, for running the script outside Actions. GITHUB_WORKFLOW is set inside the agent sandbox — I checked in this session — so a dispatched review-reviewers takes the anchored path exactly like the cron did. Its window is "since the last successful dispatch, floored at 6h", not one hour.
And it isn't silent: list-recent-runs.sh prints WARNING: the last successful '$GITHUB_WORKFLOW' run started …, more than 6h back whenever the clamp bites, which with the cron gone is the normal case. That's the same WARNING the paragraph above the insertion (If the script printed a WARNING: on stderr…) already routes to a coverage-gap record — so the new text tells the session the warnings live on a path it isn't on, when it is.
Two knock-ons if a session follows the new text as written: it would report a one-hour window when the script actually analyzed up to six, and "Read the window off the script" has nothing to read on the clean path — the floor is only ever printed inside a WARNING.
The PR description carries the same claim ("anchors its window to the cron tick only under an hourly cron"), so it's worth correcting there too.
Suggestions inline restate both paragraphs against the script's actual behaviour. I'd also note the resolved thread from the last round: the replacement wording isn't a rephrasing of the 6h point, it's a different mechanism.
The clean path prints no window bounds — only the clamp WARNING does, and that lives on the anchored path a dispatched run never takes. Tell the session to derive the hour rather than look for it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tend-agent
left a comment
There was a problem hiding this comment.
Both window paragraphs describe list-recent-runs.sh as it exists on this branch, not as it will exist after merge. The branch is behind main: #965 (0712d15) landed at 10:51Z, ~20 minutes before 1af440e, and replaced the cron-payload anchoring outright. git merge-base --is-ancestor 0712d15 825dbee is false, and this PR doesn't touch the script, so the merge takes main's version.
In that version there is no cron_minute, no intended, and no reference to the event payload anywhere in the file — grep -n 'GITHUB_EVENT\|schedule\|cron' over it returns nothing. The single branch is if [ -n "${GITHUB_WORKFLOW:-}" ]: the floor is the previous successful run of the calling workflow, clamped at now - 21600, with both WARNING: lines on that path. COMPLETED_AFTER=$((now - 3600)) is its else — for invoking the script outside Actions. The rewritten header says so directly: "manual dispatches all need no special handling: whatever run last succeeded is the anchor" and "Outside GitHub Actions (no GITHUB_WORKFLOW), the window is simply the past hour". generator/tests/test_list_recent_runs.py reaches the 1h path the same way — the test that covers it is docstringed "An ad-hoc invocation (no GITHUB_WORKFLOW) covers the past hour and never queries for an anchor" and gets there by del env["GITHUB_WORKFLOW"], not by changing a payload.
Ran it rather than only reading it, same method as last round but against the merged tree — {"inputs":{}} as the payload, GITHUB_WORKFLOW=review-reviewers, bash -x, at 11:28:34Z:
+ now=1786620514 # 11:28:34Z
+ floor_cap=1786598914 # 05:28:34Z
+ prev_start=2026-08-13T11:08:23Z
+ COMPLETED_AFTER=1786619303 # 11:08:23Z — the anchor, not now-3600 (10:28:34Z)
Dispatch payload, and it anchored. So after merge a dispatched run's window is "since the previous successful review-reviewers run, floored 6h back". With the cron gone, consecutive dispatches will usually be more than 6h apart, which makes the clamp the normal case and its WARNING: a routine one — not something that can't fire on this path. Two knock-ons for a session that follows the new text: it reports an hour when the script handed it up to six, and it's told the coverage-gap warnings live on a path it isn't on, which contradicts the paragraph immediately above the insertion in review-reviewers/SKILL.md — the one that routes exactly that WARNING: to a coverage-gap record.
This also settles the earlier round: we were reading two different files. Your trace is accurate for the branch's copy, and my withdrawal cited L89/L132/L166 in that same copy — neither of us was looking at what merges. Rebasing onto main is the fix; the suggestions inline are the post-rebase wording.
The PR description carries the same claim (anchors its window to the cron tick only under an hourly cron), so it's worth updating there too. The workflow-file header, the frontmatter description, and the table row all read correctly to me.
#965 replaced the cron-payload anchoring while this branch was open. On the post-merge script the only branch is GITHUB_WORKFLOW set vs unset, so a dispatched run anchors on the previous successful run and clamps 6h back, warnings included — the now-anchored hour is the fallback for invoking the script outside Actions. Verified by running the merged tree both ways. The skill's note shrinks to the part the existing WARNING paragraph doesn't already cover: scope claims to the window. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tend-agent
left a comment
There was a problem hiding this comment.
The rebase lands the window description on what merges — I re-ran the merged tree's list-recent-runs.sh under a workflow_dispatch payload and it takes the anchored path, floor at the previous successful run clamped to now - 21600, so both new paragraphs match the script.
Two past hour references survive elsewhere in review-reviewers/SKILL.md, both outside this diff. The one with teeth is in Step 2's run→output mapping: the tend-notifications bullet reads check for recent bot comments/issue-close events in the past hour. Step 1 now hands the session up to 6h of runs, so a notifications run that finished four hours before the dispatch has its output outside that lookback and reads as silent. The repo-wide sweep above it doesn't cover this — it's parameterised on $WINDOW_START/$WINDOW_END and catches uniform emptiness, not a partial miss on the older half of the window. Under the cron the mismatch only bit on a dropped tick; dispatch-only makes it the normal case, which is the same reason the two paragraphs in this PR needed rewording.
The other is cosmetic, but it sits in the line that defines what the evidence log means — "Recording below-threshold findings" still says For all-clear hours, record a single Low-evidence "all-clear" entry and confirm which hours were analyzed.
Happy to push a commit moving both to window wording if you want it folded in here rather than left for a follow-up.
Step 2's run-to-output map still told the survey subagent to look for tend-notifications output 'in the past hour'. With the floor now up to 6h back, a notifications run early in the window has its comments looked for in the wrong span and reads as silent — a false negative on the one workflow whose output isn't reachable from headBranch. The evidence-log and branch-prefix wording follow the same change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e, not the cron's queue lag The 20-40 min figure was the scheduler's queue-to-start delay; a dispatch starts within a minute. The ceiling is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Release 0.1.16: the version bump, the lockfile sync, and the `CHANGELOG.md` section that `pypi-release.yaml` publishes verbatim as the release notes. 11 commits since 0.1.15. On the shipped surface: a cost gate on self-initiated fixes (#960), tested CI-poll scripts and an anchor-based run window (#965), one review-anchor resolver plus the head-resolution fix past 100 commits (#971), the mention engagement gate as a tested script (#970), `review-reviewers` paused to manual dispatch (#966), the stale re-anchored approval on rebased dependency PRs (#890), and a line-anchored evidence-log selector (#963). After merge: tag `0.1.16` to publish, then regenerate tend's own workflows with `uvx tend@latest init` and restamp `review-reviewers.yaml`, whose action pin `init` never rewrites. > _This was written by Claude Code on behalf of max-sixty_
Automated nightly regeneration of tend's workflow files. **tend version:** 0.1.15 → 0.1.17 **Notable changes** - 👀 reactions now mark a session in flight: the bot reacts when an issue or PR is opened, and the reaction comes off when the session ends (max-sixty/tend#974, max-sixty/tend#979). - Mention gating was reworked — coarser pre-check gates, tested poll scripts, and an anchor-based run window replace the hand-rolled matching (max-sixty/tend#965, max-sixty/tend#971). - Self-initiated fixes are now gated on cost as well as evidence, so the bot doesn't open a PR whose value doesn't justify the session (max-sixty/tend#960). - `tend check` reads the bot's own bypass verdict on repos where the actor list is withheld, instead of reporting a false FAIL (max-sixty/tend#976). - Weekly no longer trusts a re-anchored approval on a rebased dependency PR (max-sixty/tend#890), and review-reviewers is paused as a scheduled sweep, kept as a manual spot-check (max-sixty/tend#966). Compare: max-sixty/tend@0.1.15...0.1.17 Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
Drops the
47 * * * *cron fromreview-reviewers, leavingworkflow_dispatch. Its recent output had converged on maintaining its own evidence machinery, at the fleet's highest per-run cost and a seven-day quota ceiling that twice took the user-facing workflows down with it; each adopter's dailytend-review-runsalready reviews that repo's runs from the inside and routes bundled-skill defects upstream, so this removes the direct loop rather than the only one.The skill is scoped to match: it described itself as hourly and told the session to analyze "the past hour". It now states the window
list-recent-runs.shactually hands it — floor at the previous successful run of the workflow, clamped 6h back — which with no cron makes the clamp the normal case rather than an outage signal, and scopes its claims to that window. (An earlier revision of this PR described a cron-payload branch; #965 replaced that logic while this branch was open, and the text was rebased onto what merges.)What the sweep caught, and when
Its unique catches — the ones no inside-out session would have found — cluster in April–June: rubber-stamped APPROVEs over visibly failing checks (#667), backslash-backtick corruption in already-published comment bodies across repos (#359, #405, #424, #562), stale PRs silently dropping mentions (#391), and the stale/re-anchored approval family (#798, #821, #884).
The last two weeks are dominated by fixes to its own machinery — evidence-gist plumbing, survey-window arithmetic, matrix branch naming, run→output attribution — while per-run cost climbed from $5.31 to $10.49. That is the shape the cost gate in #960 was written for.
Re-enable by dispatching it after a change that could move bot behavior fleet-wide: a release, a harness switch, a model bump — within the hour of that change, per the window note in the overlay.