← All experiments
In progressStarted October 22, 2026Updated October 27, 2026
Can a commit that says "Fixes <issue id>" resolve a Sentry issue by itself, and how do we let a nightly AI fix errors without giving it a token that can deploy?
Teaching Sentry to Close Its Own Issues
Yes, with two conditions. A "Fixes" commit resolves a Sentry issue only when it ships in a release with commits attached, so we made the build create those. And the nightly AI fixer holds a token that cannot push; a separate script, never seen by the AI, holds the token that can merge.
- Sentry
- @sentry/nextjs
- GitHub fine-grained tokens
- Claude Code
- Bash
Relevant services: Second Brain Audit — €750 · Thrivbe AI
Hypothesis
Fixed errors should leave the Sentry view without anyone clicking Resolve. A
Fixes <ID> line in a commit message should be enough. A second goal pulls the
other way: a nightly job that reads untrusted error text and writes fixes must
never hold a token that can deploy, because a merge to main is a deploy.
What we built
- Releases with commits. In the Command Center build,
withSentryConfignow gets an auth token, the org and project, and releasesetCommitsset to auto, ignoring missing and empty commit lists. The token is read at build time from the secret manager. - A merge lock for the nightly fixer. The AI step runs with a token that has Issues read and write and Contents read only. It commits fixes in local clones and writes a manifest. A script runs after the AI exits, with its own token (Contents and pull requests write, no one else can read it), and that script alone pushes and merges. A push probe from the AI token returns 403.
- A permission probe for scoped tokens. Before we merge code that calls an API with a scoped token, we run the exact query with the real production token.
Learnings
- The GitHub link is not enough. Linking repos in Sentry does not make
Fixeswork. The commit must sit in a release with commits attached. When we looked, most releases had a commit count of 0, and Command Center had none. - Proof, end to end. After the build change (pull request 95), a follow-up
pull request (97) carrying
Fixes COMMAND-CENTER-1resolved the issue in its release. - Root cause on the server. The deploy script runs the build without the secret wrapper, so secret references in the env file stay unresolved at build time. Wrapping the build would fix every app at once. That is a server change and waits for the owner. Our general auth token also gets a 403 on release create, so a release-scoped token would be cleaner.
- Unattended AI plus a merge token is the wrong shape. A security review flagged it, and the owner chose a merge lock. Merge rules now live in the lock script, not in the prompt. Known ceiling: the AI step still runs as root, so the real upgrade is an unprivileged user for that step.
- Test with the production token. In a client portal, a GitHub page passed
local tests, then showed "could not be reached" in production. Local tests
used a personal login that can read everything. The production token is a
fine-grained token with read-only Metadata, Issues and Pull requests. On it,
the GraphQL
defaultBranchReffield returns HTTP 200 with a "Resource not accessible" error, and our handler treated any error entry as a failure. The fix dropped the field. Ref and tree fields need Contents read.
Log
- 2026-10-27: Entry written. Other apps do not yet create releases with
commits, so
Fixesstill does not resolve their issues. The owner decides the roll-out. - 2026-10-25: Command Center release commits live (pull request 95, proved by 97). Nightly fixer running with the merge lock (pull requests 463 and 475).
- 2026-10-24: Merge lock chosen after the security review.
- 2026-10-22: Owner picks "auto-fix and merge" for the nightly job.
