Skip to content

fix: unbreak scheduled PR pipeline (silent gh-pr-create denials since June 14)#1047

Open
lroolle wants to merge 2 commits into
mainfrom
fix/scheduled-pr-pipeline
Open

fix: unbreak scheduled PR pipeline (silent gh-pr-create denials since June 14)#1047
lroolle wants to merge 2 commits into
mainfrom
fix/scheduled-pr-pipeline

Conversation

@lroolle

@lroolle lroolle commented Jul 8, 2026

Copy link
Copy Markdown
Member

The incident

Every scheduled run since ~June 14: fetch works → Claude commits and pushes a branch → gh pr create silently denied → Bark notification sent anyway → run exits green. 31 orphan docs/claude-code-v2.1.* branches, zero PRs, main stale for 3 weeks, and daily false-positive notifications.

Root cause: the workflow tracked anthropics/claude-code-action@main, whose claude_args parsing changed to split --allowedTools Bash(gh pr:*),… on whitespace — producing Bash(gh + pr:*), two invalid rules. Bash(git:*) survived (no space), which is why branches kept getting pushed while PR creation died.

The fix (defense in depth)

layer change
permissions moved to .claude/settings.json — JSON is immune to arg-parsing changes; CI already loads project settings
supply chain action pinned to v1.0.168 instead of moving @main
tripwire new Verify outcome step: pushed branch without PR, or dirty workspace after agent step → red run
notifications bark only after a real PR URL exists; failure alert otherwise
fetcher failures recorded in .metadata.json + per-host breakdown printed (731/run were silently discarded)

Jina.ai deprecated (second commit)

The 731 failures broke down as: 574 = r.jina.ai rate limiting (blog + support proxied fetches), 157 = platform terraform pages with no .md variant. Resolution — remove the jina dependency entirely:

  • support.claude.com: every article now serves a .md variant directly (verified 2026-07-08) → fetched like platform/code/mcp docs. 355/355 articles vs 4/355 through rate-limited jina.
  • anthropic.com blog: still HTML-only (no llms.txt / .md / content negotiation) → frozen. content/blog/ stays as a static archive; sources disabled in sources.json with dated notes; --section choices trimmed.
  • platform terraform pages: skipped with a printed note (404 on .md upstream).
  • No JINA_API_KEY secret needed — that plumbing is removed.

Verified

  • Full run: 3,231/3,231 downloaded, 0 failed (was 2,907/3,638, 731 failed, 79.7%)
  • --section support isolated run: 355/355
  • YAML + Python syntax checked; .claude/settings.json load path confirmed against the action's settingSources: [user, project, local]

Follow-ups (not in this PR)

🤖 Generated with Claude Code

Since ~June 14 every scheduled run pushed a docs branch, failed
silently on 'gh pr create', barked a notification, and exited green:
claude-code-action@main changed claude_args parsing so
'Bash(gh pr:*)' split on the space into two invalid permission rules.
Result: 31 orphan branches, zero PRs, three weeks of stale main.

- Move tool permissions to .claude/settings.json (JSON survives any
  arg parsing; settingSources=project already loads it in CI)
- Pin claude-code-action to v1.0.168 instead of the moving @main
- Add a Verify outcome tripwire: pushed branch without a PR, or
  uncommitted changes after the agent step, now fail the run
- Bark protocol: notify only after a real PR URL exists; bark a
  failure alert otherwise
- fetcher: record failures in .metadata.json (they were discarded),
  print per-host failure breakdown, support JINA_API_KEY (r.jina.ai
  rate limiting caused 574 of 731 failures), skip terraform pages
  that serve no .md variant (the other 157)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 8, 2026 03:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: df50edb8be

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
BRANCH=$(git branch --show-current)
if [ -n "$(git status --porcelain)" ]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't fail intentionally ignored low-signal diffs

This dirty-workspace tripwire conflicts with the prompt above that still tells the agent to “do nothing, exit 0” when the fetch produces only low-signal changes such as blog/research, GitHub mirror content, or .metadata.json. In those scheduled runs the fetcher has already modified the worktree, so an agent that correctly decides no commit/PR is warranted leaves changes behind and this verification step turns the run red even though nothing silently failed. Either have the agent reset ignored changes before exiting or exempt the explicitly ignored paths here.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

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 restores reliability and observability of the scheduled “Fetch Claude Code Docs” pipeline after PR creation was silently denied (while runs still reported success), by pinning the Claude Code action, moving tool permissions into project settings, and adding a post-run tripwire plus better fetch failure reporting.

Changes:

  • Pin anthropics/claude-code-action to a fixed version and move tool permissions to .claude/settings.json to avoid workflow-arg parsing regressions.
  • Add a “Verify outcome” step and tighten notification guidance so the workflow fails loudly when no PR is created or the workspace is left dirty.
  • Improve the fetcher with Jina API key support, terraform page skipping, and failure recording/printing.

Reviewed changes

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

File Description
scripts/fetcher.py Adds optional Jina auth headers, skips terraform pages, and records/prints failures for better visibility into fetch issues.
.gitignore Stops ignoring root .claude/ wholesale while keeping only .claude/settings.json tracked.
.github/workflows/fetch-claude-docs.yml Pins the action, wires JINA_API_KEY, updates notification protocol, and adds a post-agent tripwire to fail on silent PR creation failures.
.claude/settings.json Defines tool permissions in project settings to avoid fragile CLI arg parsing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/fetcher.py Outdated
Comment on lines +223 to +224
content = await self.fetch_bytes(
session, f"https://r.jina.ai/{url}", headers=self._jina_headers())
Comment thread scripts/fetcher.py Outdated
Comment on lines +246 to +247
content = await self.fetch_bytes(
session, f"https://r.jina.ai/{url}", headers=self._jina_headers())
Comment thread scripts/fetcher.py
Comment on lines +440 to +443
by_host = defaultdict(int)
for r in failed:
by_host[r["url"].split("/")[2]] += 1
print("\nFailed by host:")
Comment thread scripts/fetcher.py
Comment on lines +480 to +483
"failures": [
{"url": r["url"], "error": str(r.get("error", ""))[:200]}
for r in results if r.get("status") == "failed"
],
support.claude.com now serves a .md variant for every article
(verified 2026-07-08: 200 text/markdown on all sitemap URLs), so
support articles fetch directly like platform/code/mcp docs - no
proxy, no rate limits, 355/355 instead of 4/355 through jina.

anthropic.com blog (engineering/research/news/product) remains
HTML-only (no llms.txt, no .md, no content negotiation), and the
jina path had been ~95% dead from rate limiting anyway. Freeze it:
content/blog/ stays as a static archive, sources disabled in
sources.json with dated notes, --section choices trimmed.

Full run after: 3231/3231 downloaded, 0 failed (was 2907/3638,
731 failed). Also removes the JINA_API_KEY workflow plumbing added
earlier on this branch - no secret needed anymore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

2 participants