diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index b34b363..0f68fd1 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -10,12 +10,14 @@ name: labels # and reconcile checks out the BASE branch only. Keep it that way. # # There is no pull_request_review_target, so a review landing cannot wake this -# workflow directly — and the caller's cron is a backstop, not the wake (#199 -# relaxed it from */15 to hourly): GitHub deprioritises short intervals anyway, -# so a quiet repo goes a while between ticks. The handoff wakes the sweep -# itself: the author sets state:needs-human, and the caller's `labeled` event -# confirms or corrects that optimistic write within seconds. The cron stays as -# the last resort for a forgotten handoff. +# workflow directly — which is why the caller's cron is load-bearing, not a +# safety net (#199 relaxed it from */15 to hourly, but did NOT drop it). The +# cron is the sweep's only discovery path for every transition no subscribed +# event carries: a verdict landing, blocker:ci-red set/cleared, a +# blocker:conflict when another PR merges under this one, and the time-based +# stale / 48h claim-reclaim. Where an event IS subscribed the wake is direct — +# the handoff sets state:needs-human and the caller's `labeled` event confirms +# or corrects that optimistic write within seconds. # # This cannot loop: reconciler writes use GITHUB_TOKEN, and GitHub does not # create workflow runs from GITHUB_TOKEN-triggered events. Agent writes use a diff --git a/.github/workflows/self-labels.yml b/.github/workflows/self-labels.yml index 0a4eb69..e955e52 100644 --- a/.github/workflows/self-labels.yml +++ b/.github/workflows/self-labels.yml @@ -5,11 +5,15 @@ name: labels # unpinned — correct only for the repo that IS the source). Consumers write: # uses: heavy-duty/ceremony/.github/workflows/labels.yml@ on: - # Hourly, not */15 (#199): the cron is a BACKSTOP, not the wake. Events below - # carry every real state change in seconds; the cron only catches a FORGOTTEN - # handoff, so a quiet repo loses at most the forgotten case, and only by ≤1h — - # while */15 fired a full-board sweep four times an hour at GitHub's 1-minute - # billing floor, 52% of one private consumer's runs for near-zero real work. + # Hourly, not */15 (#199): the cron is the sweep's ONLY wake for the four + # transition classes no subscribed event carries — a review verdict landing + # (there is no pull_request_review trigger here), blocker:ci-red set or cleared + # (no check_suite/check_run/workflow_run), a blocker:conflict when ANOTHER PR + # merges under this one, and the time-based stale / 48h claim-reclaim. The + # events below carry the rest in seconds. So hourly trades ≤1h of latency on + # those four for dropping */15's four full-board sweeps an hour at GitHub's + # 1-minute billing floor — 52% of one private consumer's runs. Do NOT delete + # this cron — it is the discovery path for those four, not a forgotten-handoff net. schedule: [{cron: "0 * * * *"}] workflow_dispatch: # bootstraps missing labels on a fresh repo # Narrowed (#199) to the actions that carry a queue-state change the hourly diff --git a/changelog.d/199.md b/changelog.d/199.md index b32e80b..69dd207 100644 --- a/changelog.d/199.md +++ b/changelog.d/199.md @@ -1,9 +1,12 @@ ### Changed -- `labels` — the advisory reconcile cron relaxes from `*/15` to hourly (#199). - Events still carry every state change in seconds; the cron only backstops a - forgotten handoff, so a full-board sweep is billed far less often without - delaying any real transition past one cadence. +- `labels` — the reconcile cron relaxes from `*/15` to hourly (#199), cutting a + private consumer's schedule-triggered full-board sweeps ~4× at GitHub's + 1-minute billing floor. +- `labels` — the hourly cron is the sweep's only wake for transitions no + subscribed event carries — a verdict landing, blocker:ci-red, a + blocker:conflict when another PR merges, the time-based stale/reclaim — so it + bounds their latency to ≤1h, delaying no event-carried transition (#199). - `labels` — the caller's `issues:` trigger narrows to `[opened, closed, edited, reopened]` (#199), the actions that carry a queue-state change the cron cannot wait a cadence for. The churn/validation diff --git a/docs/CONSUMERS.md b/docs/CONSUMERS.md index d81437c..5a4a4c9 100644 --- a/docs/CONSUMERS.md +++ b/docs/CONSUMERS.md @@ -296,10 +296,13 @@ The complete caller is: ```yaml name: labels on: - # Hourly, not */15 (#199): the cron is a BACKSTOP. Events below carry every - # real state change in seconds; the cron only catches a forgotten handoff, so - # a quiet repo loses at most that case, and by ≤1h. */15 billed a full-board - # sweep four times an hour at GitHub's 1-minute floor for near-zero work. + # Hourly, not */15 (#199): the cron is the sweep's only wake for the + # transitions no subscribed event carries — a review verdict landing (no + # pull_request_review trigger), blocker:ci-red set/cleared, a blocker:conflict + # when another PR merges under this one, and the time-based stale / 48h + # claim-reclaim. Events below carry the rest in seconds. Hourly trades ≤1h of + # latency on those four for dropping */15's four sweeps an hour at GitHub's + # 1-minute floor. Keep the cron — it is the discovery path, not a safety net. schedule: [{cron: "0 * * * *"}] workflow_dispatch: # bootstraps missing labels on a fresh repo pull_request_target: