From dfafeedeecb5a36c9f043b10ca4341e5353af811 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Tue, 28 Jul 2026 18:10:23 +0000 Subject: [PATCH] labels: relax self caller cron to hourly, narrow issues triggers (#199) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The advisory */15 cron fired a full-board sweep four times an hour at GitHub's 1-minute billing floor; events carry real state changes in seconds, so the cron only backstops a forgotten handoff. Relax it to hourly and narrow the issues: trigger to [opened, closed] — the two actions with promptness-critical reconcile behavior — dropping the labeled/unlabeled churn source. Per-trigger why-comments added. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/self-labels.yml | 21 +++++++++++++++++++-- changelog.d/199.md | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 changelog.d/199.md diff --git a/.github/workflows/self-labels.yml b/.github/workflows/self-labels.yml index e9b8dac..f1d429d 100644 --- a/.github/workflows/self-labels.yml +++ b/.github/workflows/self-labels.yml @@ -5,11 +5,28 @@ name: labels # unpinned — correct only for the repo that IS the source). Consumers write: # uses: heavy-duty/ceremony/.github/workflows/labels.yml@ on: - schedule: [{cron: "*/15 * * * *"}] # advisory; the handoff label is the real wake + # 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. + schedule: [{cron: "0 * * * *"}] workflow_dispatch: # bootstraps missing labels on a fresh repo + # Narrowed to the two actions with promptness-critical reconcile behavior + # (#199): `opened` drives the mint→needs-triage check (issueflow's opened-only + # path), `closed` drives the blocker-closes→ready self-heal (crew#96/#98). The + # dropped actions — labeled/unlabeled/assigned/unassigned/edited/reopened — + # only feed validation and the 48h claim clock, which the hourly cron catches + # within one cadence; labeled/unlabeled were also the dominant issues-churn + # source. The PR handoff wake is pull_request_target:labeled, NOT issues, so + # this does not touch the handoff. issues: - types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened] + types: [opened, closed] pull_request_target: + # Every PR arrives from a fork, so these carry the head/draft/review facts + # the sweep derives state:* from. labeled/unlabeled are the handoff wake — + # the author's optimistic state:needs-human write, confirmed or corrected + # here in seconds (#11); synchronize re-derives on every push; # review_requested/review_request_removed wake the sweep that clears (or # restores) blocker:unrequested — without them the one event that makes # the label false could not clear it, and a quiet repo wore the red flag diff --git a/changelog.d/199.md b/changelog.d/199.md new file mode 100644 index 0000000..58a6d4b --- /dev/null +++ b/changelog.d/199.md @@ -0,0 +1 @@ +- `labels` caller — the advisory sweep cron relaxes from `*/15` to hourly and the `issues:` trigger narrows to `[opened, closed]`, cutting how often a full-board reconcile is billed without changing what a sweep does or delaying any real state change past one cadence (#199). Events still carry every transition in seconds; the cron only backstops a forgotten handoff. Each caller trigger now carries a comment saying why it is subscribed, and the reconcile concurrency stays `cancel-in-progress: false` — cancelling a sweep mid-board is the race that guard exists to prevent.