Skip to content

fix(ci): rescue daily-regen from GitHub's silently dropped cron ticks#9649

Merged
MarkusNeusinger merged 13 commits into
mainfrom
claude/github-auto-refresh-broken-yzk1d9
Jul 23, 2026
Merged

fix(ci): rescue daily-regen from GitHub's silently dropped cron ticks#9649
MarkusNeusinger merged 13 commits into
mainfrom
claude/github-auto-refresh-broken-yzk1d9

Conversation

@MarkusNeusinger

Copy link
Copy Markdown
Owner

Summary

  • Diagnosis: GitHub's scheduler has been silently dropping daily-regen.yml's cron ticks in multi-day streaks since early June (full 10×/day cadence until Jun 3, then gaps of 4–13 days: Jun 3→8, Jun 8→20, Jul 1→14, Jul 14→20; only 5 scheduled runs in the last 13 days instead of ~130). Less-frequent crons in the same repo (watchdog-stuck-jobs every 6 h, bot-serving-check daily) kept firing throughout, and every daily-regen run that did start was green — so the workflow itself is healthy and nothing alarmed. All scheduled runs here start with a ~2–3.5 h scheduler delay, and GitHub documents top-of-hour overload as a cause for delayed/dropped schedule events; daily-regen is the repo's most frequent cron (2 h spacing ≈ the observed delay) and the only one affected.
  • Fix 1: move the cron off the top of the hour (0 0,2,…17 0,2,…), the documented mitigation for the high-load window.
  • Fix 2: watchdog-stuck-jobs.yml (which fires reliably) gains a cron-liveness section: if no daily-regen run of any trigger type has started for >10 h outside the 17–21 UTC Berlin-evening quiet window, it re-dispatches daily-regen.yml with default inputs via the existing DRY_RUN-aware dispatch helper — capping any future starvation at roughly half a day instead of two weeks.
  • Also adds the previously missing watchdog-stuck-jobs.yml row to the workflow table in docs/workflows/overview.md.

Test plan

  • YAML parses (yaml.safe_load) for both edited workflows
  • Extracted watchdog run: script passes bash -n
  • Threshold sanity-checked against the schedule: max legitimate gap between ticks is 6 h (16:xx → 22:xx UTC quiet window) plus observed ≤2–3.5 h scheduler delay, so >10 h silence is unambiguous starvation; rescue is skipped 17–21 UTC so a dispatched bulk-generate never starts in the Berlin evening
  • Observable only on real scheduled runs (known verification gap for .github/workflows/ changes): after merge, confirm ticks land at :17 and that the next watchdog runs log the liveness line

Checklist

  • CHANGELOG.md updated under [Unreleased] (Keep-a-Changelog categories,
    bold-titled bullets, PR ref) — required for every non-pipeline PR
  • Related documentation updated (e.g. docs/reference/, docs/workflows/,
    docs/contributing.md) if behavior changed

🤖 Generated with Claude Code

https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN


Generated by Claude Code

GitHub's scheduler has been dropping daily-regen.yml's schedule events in
multi-day streaks since early June (e.g. only 5 scheduled runs in the last
13 days instead of ~130), while less-frequent crons in the same repo
(watchdog-stuck-jobs, bot-serving-check) kept firing with their usual
2-3 h delay. Every run that did start succeeded, so nothing alarmed and
the oldest specs simply stopped being refreshed.

Two defences:
- daily-regen's cron moves off the top of the hour (:00 -> :17), the
  documented high-load window in which GitHub delays/drops schedule
  events.
- watchdog-stuck-jobs gains a cron-liveness section: if no daily-regen
  run (any trigger) has started for >10 h outside the 17-21 UTC
  Berlin-evening quiet window, it re-dispatches the workflow with
  default inputs, capping future starvation at roughly half a day.

Also documents watchdog-stuck-jobs.yml in docs/workflows/overview.md,
which had been missing from the workflow table.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 20:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the reliability of the repository’s scheduled “daily regen” maintenance by moving the daily-regen.yml cron away from GitHub’s top-of-hour overload window and adding a watchdog-based liveness rescue to re-dispatch the workflow if it appears starved.

Changes:

  • Shift daily-regen.yml scheduled ticks from :00 to :17 on even UTC hours to reduce missed schedule events.
  • Extend watchdog-stuck-jobs.yml to detect prolonged absence of daily-regen runs and re-dispatch it outside the quiet window.
  • Document the updated scheduling behavior and watchdog responsibilities, and add a matching CHANGELOG.md entry.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
docs/workflows/overview.md Updates the workflow overview table to include watchdog-stuck-jobs.yml and clarifies the daily-regen.yml cadence/minute offset.
CHANGELOG.md Adds an [Unreleased] fix entry describing the cron starvation mitigation and watchdog rescue.
.github/workflows/watchdog-stuck-jobs.yml Adds a “cron-liveness” section to re-dispatch daily-regen.yml after >10h without a run outside the quiet window.
.github/workflows/daily-regen.yml Moves the cron schedule off the top of the hour (to minute 17) and documents the rationale and watchdog rescue behavior.

Comment thread .github/workflows/watchdog-stuck-jobs.yml Outdated
Review feedback: a manual daily-regen run on a non-default branch must
not mask a starved main schedule, and startedAt is null while the newest
run is still queued (which the previous query misread as 'no runs
found'). Scope gh run list to --branch main and measure the gap from
createdAt, which is always populated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 20:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/watchdog-stuck-jobs.yml Outdated
Review feedback: integer-hour truncation could print '10h (> 10h)' when
the real gap is 10h59m. Log h+mm so the message matches the threshold
evaluation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 21:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread CHANGELOG.md Outdated
Review feedback: the rescue keys off the newest run's createdAt, not
whether a run has started.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 21:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread .github/workflows/daily-regen.yml Outdated
Comment thread .github/workflows/watchdog-stuck-jobs.yml Outdated
…under CET

Review feedback: the 18-21 UTC window was documented in Berlin/CEST
terms, but Actions cron is UTC year-round, so the local-time mapping
shifts by an hour under winter time. Document the accepted drift in
both daily-regen and the watchdog liveness guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 21:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment thread docs/workflows/overview.md Outdated
Comment thread CHANGELOG.md Outdated
Review feedback: 18/20 UTC are also even hours but sit in the quiet
window, and the watchdog rescue's worst case is just under a day (the
>10h mark can land in the skipped 17-21 UTC checks), not half a day.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 21:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/watchdog-stuck-jobs.yml
Review feedback: NOW is captured before the A/B scans, so the gap was
underestimated by however long those took.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 20, 2026 21:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/watchdog-stuck-jobs.yml
…stop

Pins claude-code-action to 11ba604 (last working, Jul 1) and stops the
job right after the Claude step to check whether Claude produces the impl
file + PNGs (permission_denials). Disables the failure handler so the run
cannot comment on / retry #1010. Dispatched against this branch only via
workflow_dispatch ref; main is untouched. Reverted immediately after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 21, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Comment thread .github/workflows/impl-generate.yml Outdated
Comment on lines +461 to +467
# ========================================================================
# VALIDATION TEST — inspect what Claude produced, then STOP before any
# side-effecting steps (PR / GCS / issue comment). Remove after test.
# ========================================================================
- name: TEST — inspect Claude output and stop (validation run)
if: always()
env:
Comment thread .github/workflows/impl-generate.yml Outdated
Comment on lines +1045 to +1046
- name: Handle generation failure
if: failure() && steps.issue.outputs.number != ''
if: false # VALIDATION: disabled during test so it can't comment/retry on #1010
Comment on lines 421 to 426
- name: Run Claude Code to generate implementation
id: claude
continue-on-error: true
timeout-minutes: 60
uses: anthropics/claude-code-action@1298632ce7736903d02a1435002705aa2a594a6c # v1
uses: anthropics/claude-code-action@11ba60486e4aec9ddfeafcf4bb3f00b028ac2c16 # v1 (VALIDATION: July-1 pin, revert after)
with:
Comment thread CHANGELOG.md Outdated
…tion'

daily-regen re-generates implementations for the oldest specs (dispatches
bulk-generate), not specs themselves; clearer wording per review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 21, 2026 07:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

.github/workflows/impl-generate.yml:425

  • The workflow is pinned to a temporary claude-code-action SHA with a "revert after" note. This kind of validation-only pin is easy to forget and can silently change behavior vs the previously vetted pin; if this PR’s scope is daily-regen/watchdog reliability, this should be reverted to the prior pin (or moved to a dedicated validation PR).
        uses: anthropics/claude-code-action@11ba60486e4aec9ddfeafcf4bb3f00b028ac2c16  # v1 (VALIDATION: July-1 pin, revert after)

.github/workflows/impl-generate.yml:466

  • This validation step is unconditional (if: always()) and exits 1, which will force every impl-generate run to fail and stop the pipeline before PR/GCS/issue-comment side effects. If this PR is intended to ship, this needs to be removed or at least disabled/guarded so normal runs can complete.
      - name: TEST — inspect Claude output and stop (validation run)
        if: always()

.github/workflows/impl-generate.yml:1046

  • Handle generation failure is fully disabled (if: false), which removes the workflow’s normal failure reporting/auto-retry behavior. If the validation block above is being removed/disabled, this should be restored so failures still get tracked and capped retries behave as designed.
      - name: Handle generation failure
        if: false  # VALIDATION: disabled during test so it can't comment/retry on #1010

Comment thread .github/workflows/impl-generate.yml Outdated
Validation run refuted the action-version hypothesis: the July-1 action
pin (11ba604) produced the same empty result (no PNGs, no file changes).
Revert that pin to the current SHA and instead un-hide Claude's output so
the next run's logs show exactly which tool calls are permission-denied.
Diagnostic only; the hermetic TEST stop + disabled failure handler stay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vs46U1fqUJQcpf2jE3YdN
Copilot AI review requested due to automatic review settings July 23, 2026 20:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

.github/workflows/impl-generate.yml:456

  • Same as the primary Claude step: leaving show_full_output: true enabled in the retry path will also increase verbosity for normal runs after merge. Revert to the default (or gate behind an opt-in) so production logs stay stable.
        uses: anthropics/claude-code-action@1298632ce7736903d02a1435002705aa2a594a6c  # v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          # VALIDATION (diagnostic only, revert after): un-hide Claude's output so
          # the logs reveal exactly which tool calls are being permission-denied.
          show_full_output: true
          claude_args: "--model ${{ steps.inputs.outputs.model }}"
          # bulk-generate dispatches us from the github-actions bot; explicitly allow it.
          allowed_bots: '*'

.github/workflows/impl-generate.yml:473

  • This validation step is unconditional (if: always()) and ends with exit 1, which will make every impl-generate run fail and prevents all downstream steps (metadata/PR/review) from executing. This will effectively disable the implementation pipeline if merged.
      - name: TEST — inspect Claude output and stop (validation run)
        if: always()
        env:

.github/workflows/impl-generate.yml:1052

  • Failure handling is disabled via if: false, so generation failures would stop being tracked/commented and auto-retries would no longer occur. If the validation-only changes are removed/disabled, this condition should be restored so normal failure handling continues to work.
      - name: Handle generation failure
        if: false  # VALIDATION: disabled during test so it can't comment/retry on #1010

Comment on lines 425 to 433
uses: anthropics/claude-code-action@1298632ce7736903d02a1435002705aa2a594a6c # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# VALIDATION (diagnostic only, revert after): un-hide Claude's output so
# the logs reveal exactly which tool calls are being permission-denied.
show_full_output: true
claude_args: "--model ${{ steps.inputs.outputs.model }}"
# bulk-generate dispatches us from the github-actions bot; explicitly allow it.
allowed_bots: '*'
Root cause of the pipeline breakage is found and fixed in PR #9651 —
no further validation runs on this branch are needed or even possible:
the action's OAuth token exchange 401s any run whose workflow file
differs from the default branch ('Workflow validation failed. The
workflow file must exist and have identical content to the version on
the repository's default branch.'). That 401 is also why the earlier
July-1-pin validation run produced an empty result: Claude never
started, so it neither confirmed nor refuted the action-version
hypothesis. The actual mechanism (confirmed by local repro): CLI
2.1.171+ ignores permissions.allow from .claude/settings.json in
untrusted workspaces, and CI checkouts are never trusted; explicit
--settings in claude_args is honored and fixes it.

impl-generate.yml is now byte-identical to main again, leaving this PR
with only its cron-offset + watchdog-liveness content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 23, 2026 21:10
@MarkusNeusinger

Copy link
Copy Markdown
Owner Author

Coordination note (from the local session): root cause found & fixed elsewhere — no more validation runs on this branch.

To any watcher of this PR (including the parallel Claude session that pushed e2d81a2):

  1. The July-23 validation run (30043934965) did not refute the action-version hypothesis — it never ran Claude at all. The action's OAuth token exchange rejects any run whose workflow file differs from main (401: Workflow validation failed. The workflow file must exist and have identical content to the version on the repository's default branch.). The same applies to the show_full_output diagnostic commit — any modified impl-generate.yml on a branch 401s before Claude starts. Branch-side validation is structurally impossible.
  2. The real root cause is confirmed by local reproduction: since the July 5 action bump (CLI 2.1.170 → 2.1.211), Claude Code ignores permissions.allow from .claude/settings.json in untrusted workspaces (Ignoring 7 permissions.allow entries … this workspace has not been trusted), and a CI checkout is never trusted → every Write/Edit/Bash denied → 18–20 denials, zero files, repo-wide since July 1.
  3. The fix is PR fix(workflows): restore CI Claude permissions broken by claude-code-action bump (pipeline generated nothing since July 5) #9651: pass --settings ${{ github.workspace }}/.claude/settings.json in claude_args on all 12 action steps (explicit --settings is honored by the trust gate — locally verified: denial without the flag, file written + 0 denials with it).
  4. This branch has been cleaned: 5bf1678ae reverts all temporary validation changes; impl-generate.yml is byte-identical to main again. This PR is back to its original cron-offset + watchdog-liveness scope.

Please do not push further diagnostic commits or dispatch further validation runs here. Post-merge confirmation of #9651 will be a single real impl-generate dispatch on main.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

…fresh-broken-yzk1d9

# Conflicts:
#	CHANGELOG.md
Copilot AI review requested due to automatic review settings July 23, 2026 21:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@MarkusNeusinger
MarkusNeusinger merged commit ee3bee4 into main Jul 23, 2026
8 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the claude/github-auto-refresh-broken-yzk1d9 branch July 23, 2026 22:00
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.

3 participants