# How the no‑mistakes Database Tracks Run States: pending, running, parked, and awaiting‑agent

> Discover how the no-mistakes database tracks run states pending running parked and awaiting agent using status awaiting_agent_since and parked_ms for precise observability and crash recovery.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: internals
- Published: 2026-07-17

---

**The no‑mistakes pipeline engine tracks run states through three coordinated columns in the `runs` table—`status` for high‑level lifecycle phases, `awaiting_agent_since` for gate‑blocked agents, and `parked_ms` for accumulated wait time—enabling precise observability and crash recovery.**

The **kunchenguid/no‑mistakes** repository implements a durable pipeline runner that persists every execution state to SQLite. Understanding how its database layer tracks transitions between **pending**, **running**, **parked**, and **awaiting‑agent** states requires examining the `Run` struct in [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) and the specialized mutation helpers that maintain consistency during gate checks and daemon restarts.

## Core Database Schema for Run State Tracking

The `runs` table schema centers on the `Run` struct, which uses three distinct fields to separate lifecycle status from observational metadata.

### The status Column for Lifecycle States

The `status` field stores the high‑level execution phase as a `types.RunStatus` enum. Valid values include **pending**, **running**, **completed**, **failed**, and **cancelled**. According to the source code in [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go), the `InsertRun` function initializes every new row with `status = types.RunPending`【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L73-L86】. When a pipeline finishes—regardless of outcome—`UpdateRunStatus` atomically transitions the run to its terminal state and clears the `push_active` flag【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L200-L207】.

### The awaiting_agent_since Timestamp for Gate Blocking

When a step enters an **awaiting‑agent** gate (such as `awaiting_approval` or `fix_review`), the executor calls `SetRunAwaitingAgent`, which stamps the current Unix milliseconds into the nullable `awaiting_agent_since` column【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L41-L46】. A non‑nil value signals that the run is **parked**, halting further execution until the driving agent responds. This marker is purely observational; gate resolution logic operates independently.

### The parked_ms Counter for Telemetry

To support performance analysis, the database maintains `parked_ms`, an accumulated wall‑clock duration (in milliseconds) spent waiting on gates. The `AddRunParkedDuration` helper adds a delta to this counter only if the value is greater than zero【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L66-L73】. When an agent finally responds, `CompleteRunAwaitingAgent` both clears the `awaiting_agent_since` marker and commits the final interval to `parked_ms`【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L79-L87】.

## Run State Transition Lifecycle

The no‑mistakes engine transitions runs through a deterministic sequence that separates creation, execution, gated waits, and completion.

1. **Creation.** When a webhook push triggers a pipeline, `InsertRun` persists a row with `status = RunPending` and zeroed parked metrics.

2. **Execution Start.** The daemon worker picks up the run and calls `UpdateRunStatus(run.ID, types.RunRunning)`, marking it active.

3. **Gate Entry.** Upon encountering a gate requiring LLM intervention, the executor invokes `SetRunAwaitingAgent(run.ID)`. The non‑nil `awaiting_agent_since` timestamp now indicates the run is **parked** and **awaiting‑agent** input.

4. **Agent Response.** After the agent replies, `ClearRunAwaitingAgent` (or `CompleteRunAwaitingAgent`) removes the marker, allowing the pipeline to resume.

5. **Completion.** Once all steps finish, `UpdateRunStatus` moves the run to `RunCompleted`, `RunFailed`, or `RunCancelled`, preserving the final `parked_ms` value for telemetry.

## Crash Recovery via RecoverStaleRuns

If the daemon crashes, the `RecoverStaleRuns` routine—invoked at startup in [`internal/daemon/manager.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/daemon/manager.go)—identifies runs that were still **pending** or **running** and performs three atomic actions: marks them as **failed**, clears any dangling `awaiting_agent_since` marker, and adds elapsed parked time to `parked_ms` so metrics are not lost【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L93-L107】.

## Practical Code Examples

The following patterns from [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) demonstrate how to manipulate run states in application code:

```go
// Create a new run (status = pending)
run, err := db.InsertRun(repoID, branch, headSHA, baseSHA)

// Mark the run as running
err = db.UpdateRunStatus(run.ID, types.RunRunning)

// When a step hits a gate that needs an LLM:
err = db.SetRunAwaitingAgent(run.ID)

// After the LLM finishes the step:
err = db.ClearRunAwaitingAgent(run.ID)

// Optionally add extra parked time (e.g. after a timeout)
err = db.AddRunParkedDuration(run.ID, extraMS)

// At the end of the pipeline, set final status
err = db.UpdateRunStatus(run.ID, types.RunCompleted)

```

## Summary

- The **no‑mistakes** database tracks run states using three coordinated fields in [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go): `status` for lifecycle phases, `awaiting_agent_since` for gate blockage, and `parked_ms` for wait telemetry.
- **Pending** and **running** states are managed through `InsertRun` and `UpdateRunStatus`, while **parked** and **awaiting‑agent** conditions rely on `SetRunAwaitingAgent` and `ClearRunAwaitingAgent`.
- The `RecoverStaleRuns` function ensures crash safety by failing incomplete runs and preserving parked duration metrics.
- All state mutations are atomic and designed to support concurrent pipeline execution without race conditions.

## Frequently Asked Questions

### What is the difference between the parked and awaiting_agent_since fields?

The `awaiting_agent_since` column stores a timestamp indicating when a run entered a gate requiring agent approval, signaling that the run is currently **awaiting‑agent** input. The `parked_ms` column accumulates the total milliseconds spent in such gates across the entire run lifecycle, providing historical telemetry regardless of current state.

### How does no‑mistakes recover runs after a daemon crash?

During startup, the daemon invokes `RecoverStaleRuns`, which queries for runs with `status = RunPending` or `status = RunRunning`, marks them as **failed**, clears any remaining `awaiting_agent_since` values, and adds elapsed parked time to `parked_ms` to prevent metric loss【/cache/repos/github.com/kunchenguid/no-mistakes/main/internal/db/run.go#L93-L107】.

### Can a run status move directly from pending to completed?

Yes. If a pipeline encounters an immediate terminal condition (such as a configuration error) before execution begins, `UpdateRunStatus` can transition the run from **pending** directly to **completed**, **failed**, or **cancelled** without ever entering the **running** state.

### Where are the RunStatus constants defined?

The `RunStatus` type and its constants—`RunPending`, `RunRunning`, `RunCompleted`, `RunFailed`, and `RunCancelled`—are declared in the types package (conventionally [`internal/types/status.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/status.go)) and imported by [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go) to enforce compile‑time safety on status transitions.