# How no-mistakes Ensures Non-Blocking Pipelines: A Deep Dive into the Executor Logic

> Discover how no-mistakes guarantees non-blocking pipelines. Learn about its executor logic for automatic continuation and efficient handling of approval steps.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: deep-dive
- Published: 2026-06-28

---

**The `no-mistakes` pipeline executor guarantees non-blocking execution by automatically continuing past steps that generate info-only findings, while parking only individual runs that require explicit human approval via a pollable database flag that does not impede other pipeline executions.**

In the `kunchenguid/no-mistakes` repository, pipelines execute sequences of steps—such as lint, test, and CI operations—that may produce **findings** of varying severity. Understanding how the system distinguishes between blocking and non-blocking execution paths is essential for teams running automated workflows. The implementation centers on the executor loop in [`internal/pipeline/executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go), which evaluates step outcomes to determine whether the pipeline should proceed or pause.

## The Core Non-Blocking Logic in the Executor

The executor’s primary responsibility is to evaluate each step’s outcome and decide whether to continue execution or wait for human intervention. This decision happens in a tight loop that checks specific flags indicating the severity and nature of findings.

### Distinguishing Between Blocking and Non-Blocking Findings

After a step completes, the executor evaluates whether the findings require the pipeline to stop. According to the source code in [`internal/pipeline/executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go) (lines 43-48), the logic follows this pattern:

```go
if !outcome.NeedsApproval && !hasAskUserFindingsJSON(outcome.Findings) {
    // Any remaining info-only or non‑blocking findings are acceptable
    // and don't block the pipeline.
    skipRemaining = outcome.SkipRemaining
    stepSkipped   = outcome.Skipped
    break
}

```

This conditional block ensures that **info-only and non-blocking findings never stop the pipeline**. The evaluation depends on two critical checks:

- **`outcome.NeedsApproval`**: Returns `true` only when findings exist that mandate human review, such as those with "error" or "warning" severity.
- **`hasAskUserFindingsJSON(outcome.Findings)`**: Detects whether any findings request a user decision through the "ask-user" gate mechanism.

When both return `false`, the executor immediately proceeds to the next step, even if the previous step reported style warnings or informational messages.

### The Approval Gate Check

When a step does require approval, the system transitions into an observable parking state rather than a hard block. The executor updates the database to mark the run as awaiting agent interaction (lines 76-82 of [`executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/executor.go)):

```go
if dbErr := e.db.SetRunAwaitingAgent(run.ID); dbErr != nil { 
    // error handling
}

```

This creates a pollable flag in the `runs` table—specifically the `awaiting_agent_since` field defined in [`internal/db/schema.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/schema.go)—that indicates the run is paused. Crucially, this pause applies only to the current run; the executor continues scheduling and executing other pipelines without impediment.

## Auto-Fix Execution Before Blocking Checks

Before the executor evaluates whether to block, it attempts to resolve findings automatically. The auto-fix logic runs prior to the blocking check, ensuring that machine-correctable issues do not trigger unnecessary human intervention.

As implemented in lines 13-41 of [`internal/pipeline/executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go):

```go
if outcome.AutoFixable && autoFixLimit > 0 && autoFixAttempts < autoFixLimit {
    // auto‑fix logic …
}

```

This preemptive resolution means that **auto-fixable findings—including those with "info" severity—are corrected automatically**. If an auto-fix succeeds, the step may be re-executed, but the pipeline never enters a blocking state waiting for human input. Only findings that survive the auto-fix process and still require approval will trigger the parking mechanism.

## Observable Parking Without Pipeline Congestion

The architecture separates the concept of "parking" a run from "blocking" the pipeline scheduler. This distinction ensures system resources remain available for concurrent executions.

### The Database Schema and await_agent_since

The persistence layer supports this non-blocking guarantee through the schema defined in [`internal/db/schema.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/schema.go). The `runs` table includes the `awaiting_agent_since` timestamp field, which serves as a visibility aid rather than a lock.

When a gate is entered, the executor sets this flag (lines 76-82), and it is cleared immediately after the user responds (lines 90-96 of [`executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/executor.go)). Because the flag is transient and run-specific, other components never perceive the system as blocked; they simply observe that particular run is in a parked state awaiting input.

### Step Ordering and Skip Remaining Logic

The executor also optimizes flow through step ordering. After a step completes without needing approval, the executor may skip remaining steps when the outcome signals `SkipRemaining`. This is safe because, as noted in the source comments, only non-blocking findings can trigger that path.

The IPC protocol in [`internal/ipc/protocol.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/ipc/protocol.go) exposes the `AwaitingAgent` and `AwaitingAgentSince` fields, allowing external observers to poll status without interfering with execution. The CLI renders this state in [`internal/cli/axi_render.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/axi_render.go) (line 271), presenting the information to users running `axi status` commands.

## Code Examples and CLI Output

When running a pipeline that produces only info-only findings—such as a lint step reporting style warnings—the executor completes without entering the parking state:

```bash
$ no-mistakes run ./my-repo

# output (excerpt)

status: running

# No awaiting_agent field appears, confirming automatic continuation

```

Contrast this with a run that encounters a blocking gate:

```bash
$ no-mistakes axi status --run 12345
run:
  id: 12345
  status: running
  awaiting_agent: parked 1m12s

```

This transient `awaiting_agent` flag appears only when a gate is hit, as verified by the end-to-end tests in [`internal/e2e/axi_journey_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/e2e/axi_journey_test.go). Once the user responds with `no-mistakes axi respond approve`, the flag clears and the pipeline resumes.

## Summary

- **Automatic continuation**: The executor in [`internal/pipeline/executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go) (lines 43-48) proceeds past steps that lack `NeedsApproval` flags or "ask-user" findings, ensuring info-only reports never block execution.
- **Preemptive auto-fix**: Auto-fixable findings are resolved before blocking checks occur (lines 13-41), preventing unnecessary human intervention.
- **Observable parking**: Runs requiring approval are marked with `awaiting_agent_since` in the database schema, creating a pollable state that pauses only the specific run without congesting the pipeline scheduler.
- **Transient states**: The `awaiting_agent` flag is set when gates are entered (lines 76-82) and cleared immediately after response (lines 90-96), ensuring other runs continue uninterrupted.

## Frequently Asked Questions

### What determines whether a finding blocks the pipeline or allows automatic continuation?

A finding blocks the pipeline only if `outcome.NeedsApproval` is `true` or if `hasAskUserFindingsJSON(outcome.Findings)` detects a user decision gate. Info-only and non-blocking findings fail both checks, causing the executor to proceed immediately to the next step without human intervention.

### How does the system handle auto-fixable findings without blocking?

Before checking whether to pause execution, the executor evaluates `outcome.AutoFixable` against the `autoFixLimit` (lines 13-41 of [`executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/executor.go)). If conditions allow, it automatically applies fixes and may re-execute the step. The pipeline only blocks if findings remain after auto-fix attempts exceed the configured limit.

### What is the difference between a "parked" run and a "blocked" pipeline in no-mistakes?

A "parked" run has the `awaiting_agent_since` flag set in the `runs` table (defined in [`internal/db/schema.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/schema.go)), indicating it awaits human response. This is purely an observable state visible via `axi status`. A "blocked" pipeline would prevent other executions from scheduling, which does not occur—the executor continues processing other runs while only the specific run marked with `awaiting_agent_since` pauses until the user replies.