Skip to content

feat(review): one-shot AI review cadence, configurable globally + per-repo #4636

Description

@JSONbored

Problem

AI-generated review content (the main dual-AI reviewer, the AI slop advisory, and the linked-issue-satisfaction assessment) currently re-runs on every automatic trigger for a PR — every synchronize (push), every individual CI check-run completion, and every scheduled sweep tick — subject only to each feature's own head-SHA-scoped cache. Two of the three (slop, linked-issue-satisfaction) have materially weaker protection than the main reviewer: they have no SHA-independent reuse path and no commit-threshold pause, so a PR that sits open with repeated pushes or a noisy CI matrix can burn AI spend far beyond a single review's worth. Confirmed in production: PR #4585 (44 AI calls / ~$6.18 in 90 minutes) and a worse historical case ($76 across two metagraphed PRs in one day).

Fix

Add a genuine one-shot review cadence: once a PR has had its first AI pass (per feature — main review / slop / linked-issue-satisfaction each track their own), no further automatic trigger (push, CI-completion, sweep) spends another AI call for that feature. The only way to get a fresh pass is an explicit maintainer action — the existing "Re-run Gittensory review" PR-panel checkbox or a maintainer's @gittensory review command (both already set forceAiReview, which unconditionally bypasses the one-shot gate).

The deterministic gate (CI status, mergeability, static-rule blockers) is untouched by this — it must keep re-evaluating on every pass regardless of cadence, so a PR that fixes its CI failure is still recognized as mergeable.

Configurability

This must be a genuine dial, not a hardcoded behavior change, since other self-hosted deployments may prefer the traditional continuous re-review-on-push behavior:

  • Global (operator) default: a new env var, fleet-wide, defaults to one-shot when unset.
  • Per-repo override: .gittensory.yml, can go either direction (a repo can opt into continuous even if the fleet default is one-shot, or vice versa).
  • Ships with one-shot as the out-of-the-box default — matches the intended behavior all along; continuous re-review is the opt-in for operators who want it.

Scope

  • New AiReviewCadence type + nullable RepositorySettings.aiReviewCadence field (DB + yml + OpenAPI + dashboard route, full config-as-code parity).
  • New env var for the fleet-wide default, resolved only at the point of use (not baked into DB/yml resolution).
  • Gate added at all three AI dispatch sites inside maybePublishPrPublicSurface (the single function all trigger paths — push, CI-completion, sweep — already converge on).
  • Main review reuses the existing SHA-independent getLatestPublishedAiReview fallback (mirrors the existing frozen/paused-reuse pattern) so the comment's content stays stable after the first pass.
  • Slop / linked-issue-satisfaction get new lightweight "has this PR (or this specific linked issue) ever had a pass" existence checks — silent skip on a repeat trigger, mirroring the existing commitThresholdReached precedent for slop.
  • Full test coverage, including both cadence values and the forceAiReview bypass.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

Status
Done

Relationships

None yet

Development

No branches or pull requests

Issue actions