Skip to content

fix(watchdog): check that a rebuild is actually triggered, not just that a mirror builds - #14

Merged
oxyc merged 1 commit into
masterfrom
fix/watchdog-rebuild-hook-coverage
Jul 31, 2026
Merged

oxyc merged 1 commit into
masterfrom
fix/watchdog-rebuild-hook-coverage

Conversation

@oxyc

@oxyc oxyc commented Jul 31, 2026

Copy link
Copy Markdown
Member

What happened

Tagging generoi/gds-mcp v0.6.3 did not make it installable. Nothing in that repo calls update.yml, so the index only picked the tag up on the 3h cron. Until then:

$ composer update generoi/gds-mcp
Nothing to modify in lock file

Composer exits 0 against a stale index, so downstream this reads as "already up to date" rather than as a failure. The mirror had to be rebuilt by hand.

Why the watchdog could not have caught it

1. The MANUAL exemption was doing more than it looked like. It exempts hand-released packages from check 1 ("no Build workflow"), which is correct — they aren't mirrors. But nothing then asked whether a release triggers a rebuild. Four of the seven MANUAL packages had no trigger at all:

Has a rebuild trigger No trigger
gds-assistant (release.yml) gds-mcp
b2b-roles (release.yml) gds-block-animations
gravityforms-altcha (release.yml) gds-content-translation
gravityforms-elisadesk

These need a trigger more than the mirrors do: a mirror is bumped daily by its updater, whereas a hand-tagged package moves only when someone tags it.

2. Check 5 hardcoded build.yml:

gh api "repos/$repo/contents/.github/workflows/build.yml" ... | grep -q 'PACKAGIST_UPDATE_PAT' || continue

Every hand-released package puts the call in release.yml, so the three packages whose only rebuild trigger is this hook were silently skipped by the check meant to verify it works.

Changes

  • New check 6 — NO_REBUILD_HOOK over every non-archived satis package, MANUAL included. Severity info: the 3h cron still indexes the tag, so it costs latency, not correctness.
  • hook_workflow() scans every file in .github/workflows instead of guessing a filename.
  • Reads via .content + base64 instead of the raw media type. The raw Accept header does not reliably return raw bytes across gh versions; when it returns JSON instead, the grep matches nothing and every repo silently looks unhooked — the same false-negative shape as the bug being fixed. This one bit me while auditing: my first pass using the raw header reported gds-assistant as unhooked when its release.yml plainly carries the call.
  • Check 1 now records non-archived repos to active.txt, reused by checks 5–6 rather than re-querying archived state.
  • Header docs updated: MANUAL exempts check 1 only.

Verification

hook_workflow() was extracted verbatim and run against repos with known answers:

PASS  generoi/gds-assistant                    got=release.yml
PASS  generoi/gravityforms                     got=build.yml
PASS  generoi/gds-mcp                          got=<none>
PASS  generoi/qliro-one-for-woocommerce        got=<none>
PASS  generoi/gds-content-translation          got=<none>

gds-assistant → release.yml is precisely the case the old check missed. YAML parses and the step list is unchanged; the extracted run-block passes bash -n.

Current state of the fleet

A full audit of all 72 type: vcs packages: 63 hooked, 9 not.

Once those merge, check 6 should report only the last two groups.

Note

I could not read the PACKAGIST_UPDATE_PAT allow-list myself (403 — needs admin:org), so I can't say which of the 63 hooked repos actually get instant rebuilds. The watchdog's app token can read it; this PR makes that check cover the hand-released packages for the first time.

🤖 Generated with Claude Code

…hat a mirror builds

Tagging generoi/gds-mcp v0.6.3 did not make it installable. Nothing in that
repo calls update.yml, so the index only picked the tag up on the 3h cron;
until then `composer update` printed "Nothing to modify in lock file" and
exited 0 against a stale index. Read downstream as "already up to date".

The watchdog could not have caught it, for two reasons:

1. `MANUAL` exempted gds-mcp from check 1. That is right for "no Build
   workflow" — it is hand-released, not a mirror — but it also meant nothing
   ever asked whether a release triggers a rebuild. Four of the seven MANUAL
   packages had no trigger at all: gds-mcp, gds-block-animations,
   gds-content-translation, gravityforms-elisadesk.

2. Check 5 read `.github/workflows/build.yml` and nothing else. Every
   hand-released package puts the call in release.yml, so the packages whose
   only rebuild trigger is this hook were the ones it never looked at —
   gds-assistant, b2b-roles and gravityforms-altcha were all skipped.

Adds check 6 (NO_REBUILD_HOOK, info) over every non-archived satis package,
MANUAL included, and rewrites the lookup to scan all workflow files.

Also drops the raw media type in favour of `.content` + base64. The raw Accept
header does not reliably return raw bytes across gh versions; when it returns
JSON instead, the grep matches nothing and every repo silently looks unhooked —
the same false-negative shape as the bug being fixed.

An audit of all 72 vcs packages puts the current state at 63 hooked, 9 not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@oxyc
oxyc merged commit e2949cf into master Jul 31, 2026
@oxyc
oxyc deleted the fix/watchdog-rebuild-hook-coverage branch July 31, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant