A second build on the same day reused the tag, so the Flux image policy saw nothing new and the
Deployment kept the old digest (#1270 built but did not roll out). Tags are now YYYY-MM-DD-HHMM and
the policy accepts both forms, newest wins.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The agent can read its earlier review but nothing told it to. A re-review now opens with the
state of every earlier point, judges the new commits in full, and leaves unchanged code as it
was judged: no new suggestions, unverified points or nits about it, and no requests for more
tests or hardening of code that did not change.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The workflow-level path filter lacked review-bot/**, so a push touching only that directory
created no pipeline and the step-level filter was never evaluated. #1258 and #1268 merged
without an image build.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A 502 after ten minutes ended a review of homeassistant#382 with nothing posted. 502, 503 and
504 are retried like the 429, with the same waits and the same retry budget. The metrics are
now retries_total and retry_giveups_total.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The guessed wait (RATE_LIMIT_WAIT x retry) was uncapped while Retry-After was capped, so a large
RATE_LIMIT_WAIT could outlast the review budget. Both now share one constant.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A Blocking section that said 'none' but held a sentence turned the review into
REQUEST_CHANGES. The agent now ends its report with 'Verdict: request-changes|comment|approve';
no verdict means a plain comment, and an approval is downgraded when the report still holds
red, yellow or unverified sections.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Drops the text matching on tool results. The observed limit is HTTP 429 on starting a
conversation, which is handled by status; guessing at tool output text cannot be made
correct and dropped reviews when it was wrong.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A review whose head moved during the conversation is not posted; the PR is reviewed
again at the new head. A request that arrives while a PR is being reviewed is no
longer lost: the PR is reviewed once more when the running review ends. Tool errors
count as rate limits only with a limit phrase (429 as a status, too many requests,
rate limit reached/exceeded), so file names like rate_limit.go do not match. The whole
review is capped at one conversation timeout plus the longest waits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A tool result that merely contains the words 'rate limit' (a file about rate limits)
no longer marks the answer incomplete. Only short error messages naming a limit
(rate limit/rate_limit/ratelimit, too many requests, 429) count. Each conversation
gets the full review timeout, the waits between retries do not eat into it, and a
give-up is counted in rate_limit_giveups_total. Tests pin the first retry delay,
the Retry-After cap and the false positive.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replaces the hand-rolled retry loop with a failsafe-go retry policy: handles 429 and
rate-limited tool results only, delay from Retry-After (capped at 5m) else linear
backoff, context-aware.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Mistral documents requests per second (concurrent requests), tokens per minute and tokens per month, and X-RateLimit-Remaining, but no Retry-After and nothing about connector tool calls. When a 429 carries Retry-After it is used instead of the guessed wait (capped at five minutes); the Retry-After and rate limit headers of every 429 are logged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A conversation that got HTTP 429, or whose tool calls failed on the rate limit, is asked again after a growing wait (RATE_LIMIT_RETRIES, RATE_LIMIT_WAIT) instead of failing or posting a review built on half the files. The default is one worker, and the review timeout covers the waits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The review-bot service reviews pull requests now. The pipeline starts only when triggered by hand and stays as a reference.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Namespace, Deployment (one replica, scratch image, health and readiness probes), Service, ExternalSecret (webhook secret from apps/review-bot, Mistral key from apps/wiki, the rotated review-bot token), CiliumNetworkPolicies (Gitea in, Traefik and api.mistral.ai out), the namespace in the ClusterSecretStore allowlist, Gitea's egress to the service and its webhook host list, and Flux image automation for the review-bot image.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Gitea's pull_request webhook (HMAC-checked) queues the review at once; a periodic sweep over the configured repositories catches lost deliveries. The service keeps the listed Mistral agent in sync with the embedded prompt, asks it for a review, refuses answers that called non-read-only tools, cleans the report, derives the review event and posts as the review bot. State is the pr-review:sha marker in the bot's own review. /healthz, /readyz and /metrics. Standard library only, tests against fake Gitea and Mistral servers, built as a scratch image by build-ci-images.yml.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
run.sh asks a Mistral agent (mistral-large-4-0) through the Conversations API. The agent reads the repo and the PR through the read-only Gitea connector, so the review step no longer holds a Claude token or a local checkout. The Claude CLI invocation, the model picker and the context clones stay in run.sh as comments. The answer is cut at the first heading and empty or None-only sections are dropped before the review event is derived. A tool call that is not read-only fails the run and nothing is posted. A failed request now fails the pipeline.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
gitea-mcp advertises its -H URL as the authorization server in the OAuth protected-resource metadata, so clients doing discovery were sent to http://gitea.gitea.svc.cluster.local:3000. Switch -H to https://gitea.renner.uno; egress now goes to Traefik (as woodpecker-server and wiki already do) and the gitea:3000 grant on both sides is removed. Tool results' clone_url/html_url become public URLs too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>