From 136f8431a93f78e64d5cb66bbe8198be35916a99 Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Wed, 5 Aug 2026 08:54:29 +0000 Subject: [PATCH 1/5] perf(review-reviewers): cut cadence to 3-hourly, and anchor the window to the cron period MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anthropic quota exhaustion has now hard-failed the fleet twice in three days. review-reviewers runs hourly across a 5-repo matrix (120 Claude sessions/day) and takes ~70-79% of fleet spend, which keeps the subscription quota saturated; event-driven workflows that land mid-window fail at startup having done nothing. Cutting to `47 */3 * * *` takes it to 40 sessions/day. Outcome-acceptance signal evolves over hours to days, so little analytical value is lost. list-recent-runs.sh only anchored its completion window for a bare hourly cron (`MM * * * *`); any other shape fell back to a now-anchored 1h window. Cutting the cron alone would therefore have left each run seeing one hour out of every three — a silent two-thirds coverage hole. Generalize the detection to `MM */N * * *` where N divides 24, and derive the window from the cron period. For the hourly form `cron_hour_step` is 1 and every expression reduces to the original arithmetic. --- .claude/skills/running-tend/SKILL.md | 2 +- .github/workflows/review-reviewers.yaml | 12 +++++- .../scripts/list-recent-runs.sh | 43 ++++++++++++++----- .../skills/review-reviewers/SKILL.md | 2 +- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/.claude/skills/running-tend/SKILL.md b/.claude/skills/running-tend/SKILL.md index 34f97f43..46257fef 100644 --- a/.claude/skills/running-tend/SKILL.md +++ b/.claude/skills/running-tend/SKILL.md @@ -25,7 +25,7 @@ Tend has Claude-powered workflows beyond the generated `tend-*` set: | Workflow | File | Schedule | Purpose | |----------|------|----------|---------| -| `review-reviewers` | `review-reviewers.yaml` | `47 * * * *` | Hourly analysis of adopter repo sessions | +| `review-reviewers` | `review-reviewers.yaml` | `47 */3 * * *` | Every-3-hours analysis of adopter repo sessions | These use the tend composite action and produce `claude-session-logs*` artifacts, but their names don't match the `tend-*` prefix that scripts filter on by diff --git a/.github/workflows/review-reviewers.yaml b/.github/workflows/review-reviewers.yaml index abd8b538..223fd40b 100644 --- a/.github/workflows/review-reviewers.yaml +++ b/.github/workflows/review-reviewers.yaml @@ -1,5 +1,13 @@ name: review-reviewers -# Hourly outcome-based analysis of bot behavior across adopter repos. +# Every-3-hours outcome-based analysis of bot behavior across adopter repos. +# +# Cadence is a quota decision, not an analytical one. At hourly × a 5-repo +# matrix this workflow issued 120 Claude sessions/day and took ~70-79% of +# fleet spend, saturating the subscription quota and hard-failing the +# event-driven workflows (review, mention, triage, nightly) that serve users. +# Outcome-acceptance signal — was a bot PR merged, was a comment answered — +# evolves over hours to days, so 3-hourly loses little. `list-recent-runs.sh` +# anchors its window to the cron period, so the tiling holds at either rate. # # Each matrix entry is a repo to analyze. The job checks out the tend repo # (for creating improvement PRs/issues). TEND_BOT_TOKEN is sufficient for reading @@ -9,7 +17,7 @@ name: review-reviewers # TODO: Cross-repo pattern detection — correlate findings across repos on: schedule: - - cron: '47 * * * *' + - cron: '47 */3 * * *' workflow_dispatch: jobs: diff --git a/plugins/tend-ci-runner/scripts/list-recent-runs.sh b/plugins/tend-ci-runner/scripts/list-recent-runs.sh index c16ffa30..e37f06f6 100755 --- a/plugins/tend-ci-runner/scripts/list-recent-runs.sh +++ b/plugins/tend-ci-runner/scripts/list-recent-runs.sh @@ -76,26 +76,44 @@ for prefix in "${PREFIXES[@]}"; do WORKFLOWS+=("${matches[@]}") done -# Detect a simple hourly cron (e.g. "47 * * * *") from the workflow event -# payload so we can anchor the window to the most recent intended tick. +# Detect a fixed-period cron from the workflow event payload so we can anchor +# the window to the most recent intended tick: either hourly ("47 * * * *") or +# an every-N-hours step ("47 */3 * * *"). +# +# The step form is only accepted when N divides 24. Cron's `*/N` restarts the +# count at hour 0 each day, so a step that doesn't divide evenly (e.g. `*/5` +# fires at 0,5,10,15,20 then wraps after 4h) has no constant period, and a +# floor computed from one would silently under-reach across midnight. Those +# fall through to the now-anchored window below, same as any other cron shape. cron_minute="" +cron_hour_step=1 if [ -f "${GITHUB_EVENT_PATH:-}" ]; then schedule=$(jq -r '.schedule // empty' "$GITHUB_EVENT_PATH" 2>/dev/null || true) if [[ "$schedule" =~ ^([0-9]+)\ \*\ \*\ \*\ \*$ ]]; then cron_minute="${BASH_REMATCH[1]}" + elif [[ "$schedule" =~ ^([0-9]+)\ \*/([0-9]+)\ \*\ \*\ \*$ ]] \ + && [ "${BASH_REMATCH[2]}" -gt 0 ] && [ $((24 % BASH_REMATCH[2])) -eq 0 ]; then + cron_minute="${BASH_REMATCH[1]}" + cron_hour_step="${BASH_REMATCH[2]}" fi fi if [ -n "$cron_minute" ]; then - this_hour_tick=$(date -u -d "$(date -u +%Y-%m-%dT%H:00:00) $cron_minute minutes" +%s) + # One cron period in seconds. `cron_hour_step` is 1 for the hourly form, so + # every expression below reduces to the original hourly arithmetic. + period=$((cron_hour_step * 3600)) + # Hour-of-day of the most recent tick: the largest multiple of the step at or + # before the current hour. For the hourly form this is just the current hour. + this_tick_hour=$(( ($(date -u +%-H) / cron_hour_step) * cron_hour_step )) + this_hour_tick=$(date -u -d "$(date -u +%Y-%m-%d)T$(printf '%02d' "$this_tick_hour"):00:00 $cron_minute minutes" +%s) now_ts=$(date -u +%s) if [ "$now_ts" -lt "$this_hour_tick" ]; then - intended=$((this_hour_tick - 3600)) + intended=$((this_hour_tick - period)) else intended=$this_hour_tick fi # Default floor: one cron period back. Consecutive ticks tile exactly. - COMPLETED_AFTER=$((intended - 3600)) + COMPLETED_AFTER=$((intended - period)) # Dropped-tick recovery. GHA doesn't only *delay* scheduled ticks, it also # *drops* them: a tick that fires zero times leaves that hour's completions @@ -104,11 +122,13 @@ if [ -n "$cron_minute" ]; then # fired, resume from where the previous *actual* completed run of this # workflow left off: recover that run's intended tick and floor the window # there. When every tick fires, the previous run's intended tick == the - # default (intended - 3600), so this is a byte-identical no-op — still no + # default (intended - period), so this is a byte-identical no-op — still no # overlap between consecutive cycles. When a tick was dropped, it reaches - # back to cover the orphaned hour. Capped at 6h so a sustained outage can't - # create an unbounded window. The analyzing workflow runs on the current - # repo, so this query omits TARGET_REPO's -R. + # back to cover the orphaned period. Capped at 6h so a sustained outage can't + # create an unbounded window — one full period at hourly, and still two at + # the 3-hourly step, so a single dropped tick stays recoverable either way. + # The analyzing workflow runs on the current repo, so this query omits + # TARGET_REPO's -R. if [ -n "${GITHUB_WORKFLOW:-}" ]; then prev_start=$(gh run list --workflow "$GITHUB_WORKFLOW" --status completed \ --limit 10 --json databaseId,createdAt \ @@ -117,11 +137,12 @@ if [ -n "$cron_minute" ]; then if [ -n "$prev_start" ]; then prev_ts=$(date -u -d "$prev_start" +%s 2>/dev/null || echo "") if [ -n "$prev_ts" ]; then - prev_hour_tick=$(date -u -d "$(date -u -d "@$prev_ts" +%Y-%m-%dT%H:00:00) $cron_minute minutes" +%s) + prev_tick_hour=$(( ($(date -u -d "@$prev_ts" +%-H) / cron_hour_step) * cron_hour_step )) + prev_hour_tick=$(date -u -d "$(date -u -d "@$prev_ts" +%Y-%m-%d)T$(printf '%02d' "$prev_tick_hour"):00:00 $cron_minute minutes" +%s) if [ "$prev_ts" -ge "$prev_hour_tick" ]; then prev_intended=$prev_hour_tick else - prev_intended=$((prev_hour_tick - 3600)) + prev_intended=$((prev_hour_tick - period)) fi floor_cap=$((intended - 21600)) # never reach back more than 6h [ "$prev_intended" -lt "$floor_cap" ] && prev_intended=$floor_cap diff --git a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md index b9af0f82..459ce656 100644 --- a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md +++ b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md @@ -1,6 +1,6 @@ --- name: review-reviewers -description: Hourly outcome-based analysis of tend's CI behavior — checks whether tend's outputs were accepted or rejected, escalating to session logs only when outcomes look wrong. +description: Scheduled outcome-based analysis of tend's CI behavior — checks whether tend's outputs were accepted or rejected, escalating to session logs only when outcomes look wrong. argument-hint: "" metadata: internal: true From 8631cab8371281c4c0a934f8cfe4c075202c1077 Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:03:28 +0000 Subject: [PATCH 2/5] docs(review-reviewers): carry the period generalisation into the header and the skill prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cron detection was generalised to MM */N * * *, but three places still described a one-hour window: - list-recent-runs.sh's module header, which still documented hourly-only detection, a 1h window, and a 3h created lookback. - review-reviewers/SKILL.md's opening instruction, which framed the whole analysis as 'the past hour'. - The Step 2 survey-subagent prompt's tend-notifications mapping, which has no run-scoped anchor and so reconstructs outcomes from the window alone — told 'past hour' against a 3h run list, it would under-survey by exactly the two-thirds this change exists to prevent. Also corrects the 6h reach-back cap comment: 21600/3600 is six periods at hourly, not one. --- .../scripts/list-recent-runs.sh | 36 ++++++++++--------- .../skills/review-reviewers/SKILL.md | 4 +-- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/plugins/tend-ci-runner/scripts/list-recent-runs.sh b/plugins/tend-ci-runner/scripts/list-recent-runs.sh index e37f06f6..7781bd81 100755 --- a/plugins/tend-ci-runner/scripts/list-recent-runs.sh +++ b/plugins/tend-ci-runner/scripts/list-recent-runs.sh @@ -1,23 +1,25 @@ #!/usr/bin/env bash # Lists recently completed tend CI runs. # -# Fetches runs started in the past 3 hours, then filters to only those that -# are completed and whose updatedAt falls within a 1-hour completion window. -# This two-step approach is needed because `gh run list --created` filters -# by *start* time, not *end* time — a run started 2h ago may have just -# finished, and a run started 50min ago may still be running. +# Fetches runs started since two hours before the completion window's floor, +# then filters to only those that are completed and whose updatedAt falls +# within that window. This two-step approach is needed because +# `gh run list --created` filters by *start* time, not *end* time — a run +# started 2h ago may have just finished, and a run started 50min ago may +# still be running. # -# Window anchor: when invoked under a scheduled workflow with a simple -# hourly cron (`MM * * * *`), the completion window is anchored to the most -# recent intended cron tick instead of `now`. Consecutive cycles then tile -# exactly: [intended-1h, intended], then [intended, intended+1h]. Without -# this, GHA scheduler delay (20-40 min during peak hours) shifts each -# cycle's window relative to actual start time and drops runs that finished -# in the slack between consecutive actual starts. When GHA *drops* a tick -# entirely (not just delays it), the window's floor is instead pulled back to -# the previous actual run's intended tick so the orphaned hour still gets -# analyzed. For non-schedule events or non-hourly crons, falls back to a -# now-anchored 1h window. +# Window anchor: when invoked under a scheduled workflow with a fixed-period +# cron — hourly (`MM * * * *`) or an every-N-hours step (`MM */N * * *`, N +# dividing 24) — the completion window is anchored to the most recent intended +# cron tick instead of `now`, and is one cron period wide. Consecutive cycles +# then tile exactly: [intended-period, intended], then [intended, +# intended+period]. Without this, GHA scheduler delay (20-40 min during peak +# hours) shifts each cycle's window relative to actual start time and drops +# runs that finished in the slack between consecutive actual starts. When GHA +# *drops* a tick entirely (not just delays it), the window's floor is instead +# pulled back to the previous actual run's intended tick so the orphaned period +# still gets analyzed. For non-schedule events or cron shapes with no constant +# period, falls back to a now-anchored 1h window. # # Environment variables: # TARGET_REPO - Query a different repo (default: current repo) @@ -125,7 +127,7 @@ if [ -n "$cron_minute" ]; then # default (intended - period), so this is a byte-identical no-op — still no # overlap between consecutive cycles. When a tick was dropped, it reaches # back to cover the orphaned period. Capped at 6h so a sustained outage can't - # create an unbounded window — one full period at hourly, and still two at + # create an unbounded window — six full periods at hourly, and still two at # the 3-hourly step, so a single dropped tick stays recoverable either way. # The analyzing workflow runs on the current repo, so this query omits # TARGET_REPO's -R. diff --git a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md index 459ce656..eb2c496d 100644 --- a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md +++ b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md @@ -8,7 +8,7 @@ metadata: # Review Reviewers -Analyze tend's CI behavior on the target repo over the past hour. Focus on **outcomes** — what the bot produced publicly and whether it was accepted — rather than internal session mechanics. Create PRs or issues on tend when outcomes reveal behavioral problems. +Analyze tend's CI behavior on the target repo over the analysis window — the run list in Step 1 is anchored to the workflow's cron period, so take its span as the window rather than assuming any fixed number of hours. Focus on **outcomes** — what the bot produced publicly and whether it was accepted — rather than internal session mechanics. Create PRs or issues on tend when outcomes reveal behavioral problems. ## First steps @@ -232,7 +232,7 @@ Use a cheap subagent (e.g. Haiku / gpt-mini) and a prompt like: > - `tend-review`: `gh -R $ARGUMENTS run view --json headBranch` → find PR via > `gh -R $ARGUMENTS pr list --head --state all` → check bot reviews via > `gh api repos/$ARGUMENTS/pulls//reviews` -> - `tend-notifications`: check for recent bot comments/issue-close events in the past hour +> - `tend-notifications`: check for bot comments/issue-close events within the analysis window (this mapping has no run-scoped anchor, so it reconstructs outcomes from the window alone — use the window's actual span, not a fixed hour) > - `tend-mention`: map run to issue/PR from triggering comment, check for bot replies > - `tend-ci-fix`: map run → PR via `headBranch`, check for bot commits > From 3a1d13a45b43537541069c516d25b0c398be71eb Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:05:43 +0000 Subject: [PATCH 3/5] docs(review-reviewers): name the PR branch after the workflow, not the cadence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skill still told the agent to open its PRs on `hourly/review-`. The workflow no longer runs hourly, so every branch it creates would have carried a wrong cadence in its name. Prefixing with the workflow name instead of the cadence keeps it correct across future cadence changes — the same period-agnostic treatment the opening instruction and the Step 2 survey prompt just got. --- plugins/tend-ci-runner/skills/review-reviewers/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md index eb2c496d..0ea58e49 100644 --- a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md +++ b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md @@ -353,7 +353,7 @@ Search titles AND bodies for related keywords. Only comment on existing issues i **Prefer PRs over issues.** A PR with a clear description is immediately actionable. -- **PR** (default): Branch `hourly/review-$GITHUB_RUN_ID`, fix, commit, push, create with label `claude-behavior`. Put full analysis in PR description (run ID, outcome evidence, root cause, **gate assessment** including historical evidence count). Don't also create a separate issue. +- **PR** (default): Branch `review-reviewers/review-$GITHUB_RUN_ID`, fix, commit, push, create with label `claude-behavior`. Put full analysis in PR description (run ID, outcome evidence, root cause, **gate assessment** including historical evidence count). Don't also create a separate issue. - **Issue** (fallback): Only for problems too large or ambiguous to fix directly. Include run ID, outcome evidence, root cause analysis. Group multiple findings by broad theme. **Limit to at most 2 PRs per run** — if you have more findings, pick the highest-confidence ones and record the rest in the evidence gist. From b9523c6f80ee0a1b95fefc0e2c54b6bc9bbb142c Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:16:59 +0000 Subject: [PATCH 4/5] fix(review-reviewers): publish the completion window so callers can filter on it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The window's floor was computed and then discarded — used only by the final jq filter inside the script. Two consumers needed it and neither could get it: - Step 2's corruption scan interpolates a literal `` into five --jq filters with no stated source. - The tend-notifications outcome mapping has no run-scoped anchor, so it reconstructs outcomes from the window alone. Telling it to "use the window's actual span" was unresolvable from inside that prompt. Reconstructing the floor from the run list's own min/max updatedAt isn't equivalent: that's the span of runs that happened to fire, it collapses toward a point when one run lands in the period, and it's empty exactly when the list is empty and the all-clear gets recorded. Printing it also makes the fallback branch legible. A workflow_dispatch carries no .schedule, so it takes the now-anchored 1h window; under the old hourly cron that equalled one period, but at 47 */3 * * * a dispatched run covers one hour of three. Dispatch is how you re-run after a dropped tick or a quota outage, which is when coverage matters most. The dispatch path still doesn't guess a period — the short span is now visible rather than silent. stderr, so stdout stays the run-list JSON. Verified end-to-end against max-sixty/tend: window line on stderr, stdout parses as a 15-element array. --- plugins/tend-ci-runner/scripts/list-recent-runs.sh | 10 +++++++++- .../tend-ci-runner/skills/review-reviewers/SKILL.md | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/tend-ci-runner/scripts/list-recent-runs.sh b/plugins/tend-ci-runner/scripts/list-recent-runs.sh index 7781bd81..6f536181 100755 --- a/plugins/tend-ci-runner/scripts/list-recent-runs.sh +++ b/plugins/tend-ci-runner/scripts/list-recent-runs.sh @@ -19,7 +19,9 @@ # *drops* a tick entirely (not just delays it), the window's floor is instead # pulled back to the previous actual run's intended tick so the orphaned period # still gets analyzed. For non-schedule events or cron shapes with no constant -# period, falls back to a now-anchored 1h window. +# period, falls back to a now-anchored 1h window. Either way the window's floor +# is printed to stderr as `Completion window: >= `, since callers +# filter on it and can't recover it from the run list. # # Environment variables: # TARGET_REPO - Query a different repo (default: current repo) @@ -159,6 +161,12 @@ else COMPLETED_AFTER=$(date -d '1 hour ago' +%s) fi +# Publish the window. Callers need the floor for their own time filtering, and +# without it a fallback-branch run (any non-schedule event, e.g. a manual +# workflow_dispatch) looks the same as a scheduled one while covering only the +# last hour of a possibly longer period. stderr keeps stdout the run-list JSON. +echo "Completion window: >= $(date -u -d "@$COMPLETED_AFTER" +%Y-%m-%dT%H:%M:%SZ)" >&2 + all_runs="[]" for wf in "${WORKFLOWS[@]}"; do diff --git a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md index 0ea58e49..2567990e 100644 --- a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md +++ b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md @@ -213,6 +213,8 @@ TARGET_REPO=$ARGUMENTS ${CLAUDE_PLUGIN_ROOT}/scripts/list-recent-runs.sh The script discovers `tend-*` workflows by default. Pass additional prefixes as arguments to include other workflows (e.g., `review-reviewers` when analyzing tend itself). +It prints `Completion window: >= ` on stderr. **Note that timestamp — it is the analysis window's floor**, and Step 2 needs it both for the survey prompt and for the corruption scan's `--jq` filters; nothing downstream can reconstruct it from the run list. The window is one cron period wide on a scheduled run, but only one hour on any other event (a manual `workflow_dispatch` takes that path), so on a dispatched run expect it to cover less than a full period. + If empty, record the run as all-clear per "Recording below-threshold findings" above, then skip to Step 6. ## Step 2: Survey outcomes via cheap subagent @@ -222,7 +224,9 @@ Spawn a cheap subagent to check outcomes across all runs from Step 1. The subage Use a cheap subagent (e.g. Haiku / gpt-mini) and a prompt like: > Survey bot outcomes on `$ARGUMENTS` for the following runs: [run IDs from Step 1]. -> The bot's login is `$BOT_LOGIN`. +> The bot's login is `$BOT_LOGIN`. The analysis window starts at [completion-window +> floor from Step 1] and runs to now — substitute that timestamp everywhere +> `` appears below. > > For each run, determine: > 1. Did the bot produce visible output (review, comment, issue action, commit)? @@ -232,7 +236,7 @@ Use a cheap subagent (e.g. Haiku / gpt-mini) and a prompt like: > - `tend-review`: `gh -R $ARGUMENTS run view --json headBranch` → find PR via > `gh -R $ARGUMENTS pr list --head --state all` → check bot reviews via > `gh api repos/$ARGUMENTS/pulls//reviews` -> - `tend-notifications`: check for bot comments/issue-close events within the analysis window (this mapping has no run-scoped anchor, so it reconstructs outcomes from the window alone — use the window's actual span, not a fixed hour) +> - `tend-notifications`: check for bot comments/issue-close events since the window start above (this mapping has no run-scoped anchor, so it reconstructs outcomes from the window alone — don't substitute a fixed hour for it) > - `tend-mention`: map run to issue/PR from triggering comment, check for bot replies > - `tend-ci-fix`: map run → PR via `headBranch`, check for bot commits > From 3d82e527b02fd1d08dcb077a78c726cda9d87595 Mon Sep 17 00:00:00 2001 From: tend-agent <270458913+tend-agent@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:23:41 +0000 Subject: [PATCH 5/5] docs(review-reviewers): hedge the scheduled window width for dropped-tick recovery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default floor is one cron period back, but dropped-tick recovery pulls it to the previous actual run's intended tick, capped at intended - 21600 — so a scheduled run can publish a window up to 6h wide, two periods at 3-hourly. Step 1's description is what the agent reasons from when judging how much ground the window covers, so it shouldn't state the default as the maximum. --- plugins/tend-ci-runner/skills/review-reviewers/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md index 2567990e..27fc0ec3 100644 --- a/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md +++ b/plugins/tend-ci-runner/skills/review-reviewers/SKILL.md @@ -213,7 +213,7 @@ TARGET_REPO=$ARGUMENTS ${CLAUDE_PLUGIN_ROOT}/scripts/list-recent-runs.sh The script discovers `tend-*` workflows by default. Pass additional prefixes as arguments to include other workflows (e.g., `review-reviewers` when analyzing tend itself). -It prints `Completion window: >= ` on stderr. **Note that timestamp — it is the analysis window's floor**, and Step 2 needs it both for the survey prompt and for the corruption scan's `--jq` filters; nothing downstream can reconstruct it from the run list. The window is one cron period wide on a scheduled run, but only one hour on any other event (a manual `workflow_dispatch` takes that path), so on a dispatched run expect it to cover less than a full period. +It prints `Completion window: >= ` on stderr. **Note that timestamp — it is the analysis window's floor**, and Step 2 needs it both for the survey prompt and for the corruption scan's `--jq` filters; nothing downstream can reconstruct it from the run list. The window is normally one cron period wide on a scheduled run — wider when the script recovers a dropped tick — but only one hour on any other event (a manual `workflow_dispatch` takes that path), so on a dispatched run expect it to cover less than a full period. If empty, record the run as all-clear per "Recording below-threshold findings" above, then skip to Step 6.