# How the Pipeline Executor Manages Approval and Review Findings in no-mistakes

> Learn how the pipeline executor manages approval gates and review findings in no-mistakes by blocking execution and processing actions like Approve, Skip, Abort, or Fix.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-13

---

**The pipeline executor handles approval gates and review findings by blocking execution on a buffered channel until receiving a structured response, then processing one of four actions (Approve, Skip, Abort, or Fix) while persisting user overrides to database round tables for crash recovery.**

The `no-mistakes` repository implements a robust pipeline execution framework that requires human intervention at critical junctures. When a step encounters an approval gate or review findings that need correction, the **pipeline executor** orchestrates the interaction between automated agents and human reviewers through a carefully designed state management system.

## The Approval Workflow Architecture

### Marking the Run as Waiting

When a step requires human input, the executor prepares the runtime state before blocking. In [`internal/pipeline/executor.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/pipeline/executor.go) (lines 40-45), the implementation locks the executor mutex, sets `e.waiting = true`, records the step name in `e.waitingStep`, and emits a step-completed event to notify the UI/CLI of the current findings.

```go
e.mu.Lock()
e.waiting = true
e.waitingStep = gate.step.Name()
e.mu.Unlock()
response, err := e.waitForApproval(ctx, gate.step.Name())

```

### Blocking for User Input

The `waitForApproval` function (lines 52-71) blocks on the buffered channel `e.approvalCh`. This channel receives an `approvalResponse` struct containing the chosen action, selected finding IDs, user instructions, and any additional findings. If the context cancels (e.g., daemon shutdown), the function returns the cancellation cause immediately, allowing for graceful shutdown handling.

### Processing Four Possible Actions

Upon receiving a response, the executor distinguishes between four actions at lines 82-112:

- **Approve** – Marks the step as `StepStatusCompleted` and continues execution with remaining steps.
- **Skip** – Marks the step as `StepStatusSkipped` and proceeds to subsequent steps without executing the current one.
- **Abort** – Fails the step with reason "aborted by user" and terminates the pipeline run.
- **Fix** – Invokes the most complex remediation path, triggering the user override workflow.

## Handling Fix Requests and User Overrides

### Filtering and Merging Findings

For Fix actions, the executor processes user selections through a multi-step transformation. First, `filterFindingsJSON` isolates the subset of findings selected by the user via `response.findingIDs`. Then, `mergeUserOverridesJSON` combines these filtered findings with user instructions and any `response.addedFindings` provided by the reviewer.

```go
selected := filterFindingsJSON(gate.findings, response.findingIDs)
merged   := mergeUserOverridesJSON(selected, response.instructions, response.addedFindings)

```

### Persisting to Database Rounds

The merged JSON payload is persisted through [`internal/db/agent_session.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/agent_session.go) using `SetStepRoundUserFindings` and `SetStepRoundSelection`. The executor updates the step status to `StepStatusFixing` via `UpdateStepStatus`, then re-executes the step with `stepExecutionState.fixing = true` and the merged findings passed as `previousFindings`.

```go
if dbErr := e.db.SetStepRoundUserFindings(gate.lastRoundID, &merged); dbErr != nil {
    // log warning
}
e.db.UpdateStepStatus(gate.stepResult.ID, types.StepStatusFixing)

```

## Recovery and Durability Guarantees

### Reconstructing Gate State After Crashes

The `recoveredGate` struct (lines 53-84) ensures durability across daemon restarts. When recovering a crashed run, `ValidateRecoveredRun` reconstructs the gate state, validates that the last round's findings match the step's findings in `db.StepResult.FindingsJSON`, and restores the approval context. This guarantees that user-provided overrides survive process restarts without data loss, maintaining the integrity of the approval workflow even after unexpected failures.

## Telemetry and Auditability

For every approval response, the executor records telemetry through [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go), tracking action types, the number of selected findings, and the handling agent. Auto-fix attempts are counted per round via `autoFixAttempts` and stored in the `recoveredGate` struct for diagnostic purposes, creating a complete audit trail of human decisions within the pipeline execution.

## Summary

- The executor uses **state flags** (`waiting`, `waitingStep`) and a **buffered channel** (`approvalCh`) to serialize user actions and block execution during approval gates.
- **Four distinct actions** (Approve, Skip, Abort, Fix) determine whether the pipeline continues, skips, fails, or enters remediation mode.
- Fix requests trigger **finding filtering** and **JSON merging** to incorporate user instructions and additional findings into the execution context.
- Database **round tables** persist user selections and overrides, enabling reliable recovery after daemon crashes through `ValidateRecoveredRun`.
- Comprehensive **telemetry** tracks every approval decision for auditability and debugging.

## Frequently Asked Questions

### How does the pipeline executor know when to pause for human approval?

The executor checks step definitions and current findings to determine if an approval gate is required. When triggered, it sets `e.waiting = true` and `e.waitingStep` to the current step name, then blocks on `waitForApproval` until the UI/CLI sends a response via `RespondWithOverrides`. This channel-based communication ensures thread-safe coordination between the executor and external interfaces.

### What happens if the daemon crashes while waiting for approval?

The `recoveredGate` mechanism reconstructs the approval state from database records upon restart. It validates that the last round's findings match the stored step findings and restores the approval context, ensuring no user input is lost and the pipeline can resume safely from the exact point of interruption.

### How are user corrections applied when selecting the Fix action?

The executor calls `filterFindingsJSON` to isolate selected findings, then `mergeUserOverridesJSON` to combine user instructions and added findings. This merged payload is persisted via `SetStepRoundUserFindings`, and the step re-executes with `stepExecutionState.fixing = true` and the updated findings passed as `previousFindings`, allowing the agent to act on the specific corrections requested.

### Where are approval decisions logged for auditing?

The executor records telemetry data in [`internal/telemetry/telemetry.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/telemetry/telemetry.go), capturing the action type, number of selected findings, handling agent, and auto-fix attempt counts. This data is stored alongside the round records in [`internal/db/agent_session.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/agent_session.go), creating a complete audit trail of human decisions within the pipeline execution.