Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a736c1e
feat(ci): integrate unresolved review comments into issue detection a…
khaira777 Aug 28, 2026
8a7de8b
no-mistakes(review): Fix review dedup, findings, bot coverage; focuse…
khaira777 Aug 28, 2026
236198a
no-mistakes(review): Support GitHub Advanced Security review comments…
khaira777 Aug 28, 2026
d705c6b
no-mistakes(review): Fix review pagination, timeout state, IPC bounds…
khaira777 Aug 28, 2026
a910275
no-mistakes(review): Preserve review evidence, sanitize controls; foc…
khaira777 Aug 28, 2026
0afe162
no-mistakes(review): Bound provider errors, preserved CI context; tes…
khaira777 Aug 28, 2026
ca99482
no-mistakes(review): Respect review policy, selection, redaction, and…
khaira777 Aug 28, 2026
935f2f8
no-mistakes(review): Split review budgets, preserve scope, and retain…
khaira777 Aug 28, 2026
cba746e
no-mistakes(review): Persist review state and enforce scoped repair b…
khaira777 Aug 28, 2026
4f9aa8c
no-mistakes(review): Block review autofix during unresolved CI reruns
khaira777 Aug 28, 2026
e7977d9
no-mistakes(review): Gate review autofix on readiness; mark findings …
khaira777 Aug 28, 2026
b0a57d6
no-mistakes(review): Preserve review targets through CI fix timeouts
khaira777 Aug 28, 2026
142f4fa
no-mistakes(review): {"summary":"bound timeout review targets and val…
khaira777 Aug 29, 2026
64c653d
no-mistakes(document): update CI step documentation for review-commen…
khaira777 Aug 29, 2026
31c4539
no-mistakes(ci): Diagnosed and resolved the failing checks: 1. Fixed …
khaira777 Aug 29, 2026
72fa550
no-mistakes(ci): Diagnosed and resolved the failing CI checks: 1. `te…
khaira777 Aug 29, 2026
1716bec
no-mistakes(ci): Fixed Greptile Review failure by requesting `pullReq…
khaira777 Aug 29, 2026
f762362
fix(scm/github): fail closed when review comments response lacks PR head
khaira777 Aug 29, 2026
06e4e50
no-mistakes(document): document CI review-comment gate and auto-fix b…
khaira777 Aug 29, 2026
261c629
no-mistakes(ci): Diagnosed and fixed test package timeout in `interna…
khaira777 Aug 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/provider-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ If one daemon serves repositories that require non-overlapping accounts, give ea
- PR creation and update on pushes
- CI check polling with exponential backoff (30s → 60s → 120s) until the PR is merged, closed, or the configured `ci_timeout` idle window elapses
- Failed job log fetching (`gh run view --log-failed`) for the CI auto-fix step
- Unresolved Greptile review-thread comments supplied to CI auto-fix prompts; see the [CI step reference](/no-mistakes/reference/pipeline-steps/#ci) for filtering and prompt-safety details
- Unresolved review-thread comments from supported GitHub review bots; see the [CI step reference](/no-mistakes/reference/pipeline-steps/#ci) for supported identities, readiness behavior, and prompt-safety details
- PR mergeability polling, and agent-driven resolution when the provider reports an actual merge conflict

### GitHub fork contributions
Expand Down
5 changes: 3 additions & 2 deletions docs/src/content/docs/reference/global-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ The key is matched against the checkout path recorded at `init`. After moving a
### auto_fix

Maximum follow-up auto-fix attempts per step. Set a step to `0` to disable the follow-up auto-fix loop, so findings require manual approval.
For review findings, including unresolved review comments surfaced by the CI step, `0` disables automatic repair; those blocking findings still require manual approval.
The document step attempts documentation fixes during its initial pass, so unresolved documentation findings pause for approval instead of using an automatic follow-up loop.
For empty `commands.lint`, the document step's combined housekeeping pass also attempts safe lint fixes, and the lint step consumes its result; unresolved blocking lint findings then pause for approval instead of starting another automatic fix loop.

Expand All @@ -544,11 +545,11 @@ For empty `commands.lint`, the document step's combined housekeeping pass also a
| Field | Type | Default | Description |
| ------------------- | ----- | ------- | ------------------------------------------------------------------------------------------- |
| `auto_fix.rebase` | `int` | `3` | Rebase conflict auto-fix attempts |
| `auto_fix.review` | `int` | `0` | Review finding auto-fix attempts |
| `auto_fix.review` | `int` | `0` | Review findings and CI-discovered review-comment auto-fix attempts |
| `auto_fix.test` | `int` | `3` | Test failure auto-fix attempts |
| `auto_fix.document` | `int` | `3` | Not used by the automatic document pass |
| `auto_fix.lint` | `int` | `3` | Lint issue auto-fix attempts |
| `auto_fix.ci` | `int` | `3` | CI auto-fix attempts for CI failures, plus GitHub, GitLab, Forgejo, and Azure DevOps merge conflicts |
| `auto_fix.ci` | `int` | `3` | CI auto-fix attempts for CI failures, plus GitHub, GitLab, Forgejo, and Azure DevOps merge conflicts; review comments use `auto_fix.review`, and mixed repairs consume both |

Legacy alias: `auto_fix.babysit`.

Expand Down
8 changes: 4 additions & 4 deletions docs/src/content/docs/reference/pipeline-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,23 +299,23 @@ Monitors PR health after creation and auto-fixes CI failures. Mergeability polli
- Keeps waiting, rather than pausing, while any check can still finish on its own, so a cancellation observed alongside a running check is decided only once the rollup has stopped moving
- Never re-runs checks across a head change: if the published branch head no longer equals the commit the run delivered, the step clears any ready-to-merge signal and pauses for user approval with the expected and observed commits, because re-running checks would certify a revision this run never produced
- On CI failure: fetches failed job logs (GitHub via `gh run view --log-failed`, GitLab via `glab ci trace`, Forgejo via the exact native check target plus `forgejo-axi run view --log-failed` when runtime routes are available, Bitbucket Cloud via failed pipeline step logs; Azure DevOps has no first-class build-log command, so the agent fixes from the failing-check list without logs), sends them to the agent with user intent when available, and, if the agent produces changes, commits them with [`commit.fix_message`](/no-mistakes/reference/global-config/#commitfix_message). What happens next follows one rule on every CI-fix path: a repair is published without revalidating only when its continuity with the reviewed, published head can be proven, meaning the repaired head is the run's review-approved commit or a descendant of it. A provable repair is published immediately through the Push step's own guarded force-push path and the monitor keeps watching the same run; anything else is held locally, the run's review approval is revoked, and validation restarts from Review so Push republishes it only after Review approves it. [`ci.revalidate_repairs`](/no-mistakes/reference/repo-config/#cirevalidate_repairs) sets the intent identically on every path: `false` (default) publishes when it is provable, `true` revalidates outright. A merge-conflict repair rebases, so its continuity is never provable and it always revalidates. Forgejo status gating remains active when logs are unsupported or unavailable
- On GitHub, includes unresolved review-thread comments from supported review bots (currently Greptile) in CI repair prompts when an auto-fix attempt starts; the comments are framed as untrusted external data and the rendered section is capped at 32 KiB
- On GitHub, treats unresolved review-thread comments from supported review bots (Greptile, CodeRabbit, GitHub Code Quality and Advanced Security/CodeQL, and Codex) as CI issues that block readiness, appear as structured findings at approval gates, and enter CI repair prompts when an auto-fix attempt starts; the comments are framed as untrusted external data and the rendered section is capped at 32 KiB
- States the configured repair policy in the step log before the first poll, so a run's log says which of the two paths a repair would take without cross-referencing the config in force at the time
- Settles the local gate mirror before atomically recording the published head and push binding, so a publication that stalls part way records nothing: the run stays on its pre-repair head and the next fix attempt re-enters the same path, finds the remote already at that commit, and completes it
- Whenever a repair revalidates - either because the setting requires it or because continuity cannot be proven - restarts at Review only: Intent and Rebase keep their results, steps already skipped for the run stay skipped, the run id is unchanged, and the durable auto-fix attempt count carries across. Earlier cycles remain in the run's round history; the step's own status shows the latest cycle
- Bounds that CI-fix agent with [`agent_timeout`](/no-mistakes/reference/global-config/#agent_timeout): an expired budget cancels the agent and fails the attempt with a timeout diagnostic rather than leaving the run active indefinitely, and a late successful return after the deadline is not committed
- If the CI-fix agent exhausts that budget, pauses for user approval instead of re-issuing the same request on the next poll. A budget burn is not transient - repeating it costs another full budget - so the remaining auto-fix attempts are left for the user to spend deliberately with a fix response. The finding carries the measured timeout diagnostic and, when the timed-out agent left uncommitted work in the run worktree, that worktree's path. Ordinary (non-timeout) fix failures keep retrying as before
- On GitHub, GitLab, Forgejo, or Azure DevOps merge conflict: asks the agent to rebase onto the latest PR base branch tip and make the smallest correct root-cause fix for the conflicts, using user intent when available
- If both CI failures and a GitHub, GitLab, Forgejo, or Azure DevOps merge conflict are present: fixes both in the same attempt
- If CI failures, merge conflicts, or unresolved review comments are present: fixes them together in the same attempt, consuming one attempt from each applicable budget ([`auto_fix.ci`](/no-mistakes/reference/global-config/#auto_fix) and [`auto_fix.review`](/no-mistakes/reference/global-config/#auto_fix))
- If a fix attempt produces no changes: automatic mode leaves the failure undeduplicated so it can retry until the auto-fix limit, while manual fix mode returns immediately for manual intervention
- Counts each automatic fix attempt durably when it starts, so revalidation or a daemon restart cannot reset the configured limit
- Exits cleanly when the PR is merged, closed, or declined
- If the idle timeout is reached while the PR is still open: pauses for user approval, even when CI checks are currently healthy
- If the idle timeout is reached while CI failures or, on GitHub, GitLab, Forgejo, or Azure DevOps, a merge conflict are still known: pauses for user approval with findings for the remaining issues
- If the idle timeout is reached while GitHub, GitLab, Forgejo, or Azure DevOps PR mergeability is still unresolved: pauses for user approval with a finding describing the unresolved mergeability state
- If CI failures or a GitHub, GitLab, Forgejo, or Azure DevOps merge conflict persist after the auto-fix limit: pauses for user approval with findings listing each failing check and/or the merge conflict
- If CI failures, unresolved review comments, or a GitHub, GitLab, Forgejo, or Azure DevOps merge conflict persist after the auto-fix limit: pauses for user approval with findings listing each failing check, unresolved review comment, and/or the merge conflict

**Default auto-fix limit:** `3` total CI auto-fix attempts.
**Default auto-fix limit:** `3` total CI auto-fix attempts for CI failures and merge conflicts; review comments use [`auto_fix.review`](/no-mistakes/reference/global-config/#auto_fix) (default `0`).

**Default transient rerun budget:** `0` reruns per provider-attributed check per run. GitHub pre-run failure detection is disabled at this value.

Expand Down
3 changes: 2 additions & 1 deletion docs/src/content/docs/reference/repo-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,11 @@ Override auto-fix attempt limits for specific steps. Fields not set here inherit
| `auto_fix.ci` | `int` | Inherits from global (default `3`) |

Set to `0` to disable the follow-up auto-fix loop for a step (findings require manual approval).
For review findings, including unresolved review comments surfaced by the CI step, `0` disables automatic repair; those blocking findings still require manual approval.
The document step attempts documentation fixes during its initial pass, so unresolved documentation findings pause for approval instead of using an automatic follow-up loop.
For empty `commands.lint`, the document step's combined housekeeping pass also attempts safe lint fixes, and the lint step consumes its result; unresolved blocking lint findings pause for approval instead of starting another automatic fix loop.

`auto_fix.ci` covers the CI step's CI failure and merge-conflict auto-fix attempts.
`auto_fix.ci` covers the CI step's CI failure and merge-conflict auto-fix attempts. It does not enable automatic repair of review comments; those use `auto_fix.review`. When both kinds of issue are repaired together, one attempt is consumed from each applicable budget.

Legacy alias: `auto_fix.babysit`.

Expand Down
2 changes: 1 addition & 1 deletion internal/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestOpenCreatesSchema(t *testing.T) {
if !hasColumn(t, d, "step_rounds", "reviewed_head_sha") {
t.Fatal("step_rounds.reviewed_head_sha column missing from fresh schema")
}
for _, column := range []string{"last_activity_at", "last_activity", "agent_pid", "ci_fix_attempts"} {
for _, column := range []string{"last_activity_at", "last_activity", "agent_pid", "ci_fix_attempts", "ci_review_state"} {
if !hasColumn(t, d, "step_results", column) {
t.Fatalf("step_results.%s column missing from fresh schema", column)
}
Expand Down
4 changes: 3 additions & 1 deletion internal/db/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ CREATE TABLE IF NOT EXISTS step_results (
last_activity TEXT,
agent_pid INTEGER,
auto_fix_limit INTEGER,
ci_fix_attempts INTEGER NOT NULL DEFAULT 0
ci_fix_attempts INTEGER NOT NULL DEFAULT 0,
ci_review_state TEXT
);

CREATE TABLE IF NOT EXISTS step_rounds (
Expand Down Expand Up @@ -226,6 +227,7 @@ var migrationStatements = []string{
`ALTER TABLE step_results ADD COLUMN agent_pid INTEGER`,
`ALTER TABLE step_results ADD COLUMN auto_fix_limit INTEGER`,
`ALTER TABLE step_results ADD COLUMN ci_fix_attempts INTEGER NOT NULL DEFAULT 0`,
`ALTER TABLE step_results ADD COLUMN ci_review_state TEXT`,
// Session-fidelity telemetry columns (all nullable so pre-existing rows read
// back as unknown, never a fabricated zero).
`ALTER TABLE agent_invocations ADD COLUMN model_provider TEXT`,
Expand Down
17 changes: 15 additions & 2 deletions internal/db/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type StepResult struct {
AgentPID *int
AutoFixLimit *int
CIFixAttempts int
CIReviewState *string
}

const stepResultColumns = `id, run_id, step_name, step_order, status, exit_code, duration_ms, log_path, findings_json, error, started_at, completed_at, last_activity_at, last_activity, agent_pid, auto_fix_limit`
Expand All @@ -37,6 +38,11 @@ func (d *DB) readableStepResultColumns() string {
} else {
columns += ", 0 AS ci_fix_attempts"
}
if d.hasColumn("step_results", "ci_review_state") {
columns += ", ci_review_state"
} else {
columns += ", NULL AS ci_review_state"
}
return columns
}

Expand Down Expand Up @@ -64,7 +70,7 @@ func (d *DB) GetStepResult(id string) (*StepResult, error) {
s := &StepResult{}
err := d.sql.QueryRow(
`SELECT `+d.readableStepResultColumns()+` FROM step_results WHERE id = ?`, id,
).Scan(&s.ID, &s.RunID, &s.StepName, &s.StepOrder, &s.Status, &s.ExitCode, &s.DurationMS, &s.LogPath, &s.FindingsJSON, &s.Error, &s.StartedAt, &s.CompletedAt, &s.LastActivityAt, &s.LastActivity, &s.AgentPID, &s.AutoFixLimit, &s.CIFixAttempts)
).Scan(&s.ID, &s.RunID, &s.StepName, &s.StepOrder, &s.Status, &s.ExitCode, &s.DurationMS, &s.LogPath, &s.FindingsJSON, &s.Error, &s.StartedAt, &s.CompletedAt, &s.LastActivityAt, &s.LastActivity, &s.AgentPID, &s.AutoFixLimit, &s.CIFixAttempts, &s.CIReviewState)
if err == sql.ErrNoRows {
return nil, nil
}
Expand All @@ -86,7 +92,7 @@ func (d *DB) GetStepsByRun(runID string) ([]*StepResult, error) {
var steps []*StepResult
for rows.Next() {
s := &StepResult{}
if err := rows.Scan(&s.ID, &s.RunID, &s.StepName, &s.StepOrder, &s.Status, &s.ExitCode, &s.DurationMS, &s.LogPath, &s.FindingsJSON, &s.Error, &s.StartedAt, &s.CompletedAt, &s.LastActivityAt, &s.LastActivity, &s.AgentPID, &s.AutoFixLimit, &s.CIFixAttempts); err != nil {
if err := rows.Scan(&s.ID, &s.RunID, &s.StepName, &s.StepOrder, &s.Status, &s.ExitCode, &s.DurationMS, &s.LogPath, &s.FindingsJSON, &s.Error, &s.StartedAt, &s.CompletedAt, &s.LastActivityAt, &s.LastActivity, &s.AgentPID, &s.AutoFixLimit, &s.CIFixAttempts, &s.CIReviewState); err != nil {
return nil, fmt.Errorf("scan step result: %w", err)
}
steps = append(steps, s)
Expand Down Expand Up @@ -198,6 +204,13 @@ func (d *DB) SetCIFixAttempts(id string, attempts int) error {
return nil
}

func (d *DB) SetCIReviewState(id, state string) error {
if _, err := d.sql.Exec(`UPDATE step_results SET ci_review_state = ? WHERE id = ?`, state, id); err != nil {
return fmt.Errorf("set CI review state: %w", err)
}
return nil
}

func autoFixLimitDBValue(autoFixLimit int) any {
if autoFixLimit <= 0 {
return nil
Expand Down
27 changes: 27 additions & 0 deletions internal/db/step_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,33 @@ func TestStepInsertAndGet(t *testing.T) {
}
}

func TestSetCIReviewState(t *testing.T) {
d := openTestDB(t)
repo, err := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
if err != nil {
t.Fatalf("insert repo: %v", err)
}
run, err := d.InsertRun(repo.ID, "feature", "abc", "def")
if err != nil {
t.Fatalf("insert run: %v", err)
}
step, err := d.InsertStepResult(run.ID, types.StepCI)
if err != nil {
t.Fatalf("insert step: %v", err)
}
state := `{"reviewFixAttempts":2,"manualReviewScope":"review-key","manualReviewScopeSet":true}`
if err := d.SetCIReviewState(step.ID, state); err != nil {
t.Fatalf("set CI review state: %v", err)
}
got, err := d.GetStepResult(step.ID)
if err != nil {
t.Fatalf("get step: %v", err)
}
if got.CIReviewState == nil || *got.CIReviewState != state {
t.Fatalf("CI review state = %v, want %q", got.CIReviewState, state)
}
}

func TestStepsByRun(t *testing.T) {
d := openTestDB(t)
repo, _ := d.InsertRepo("/home/user/project", "git@github.com:user/project.git", "main")
Expand Down
Loading
Loading