# How the Destructive Daemon Lifecycle Guard Prevents Stopping the Daemon During Active Runs

> Learn how the destructive daemon lifecycle guard in kunchenguid/no-mistakes prevents daemon stops during active runs by checking pending pipeline jobs and requiring a force flag for overrides.

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

---

**The destructive daemon lifecycle guard prevents accidental daemon shutdowns by querying the local SQLite database for pending or running pipeline runs and refusing the `daemon stop` or `daemon restart` commands unless the operator explicitly overrides the protection with the `--force` flag.**

The `no-mistakes` repository implements a safety mechanism to protect long-running pipeline executions from abrupt termination. When administrators attempt to stop or restart the daemon, the **destructive daemon lifecycle guard** intervenes to check for active work, ensuring that in-flight pipelines are not abandoned and state corruption is avoided.

## How the Guard Detects Active Pipeline Runs

The guard’s protection begins with an atomic check against the daemon’s state database. Before any shutdown logic executes, the system verifies whether the daemon is currently coordinating pipeline executions.

### Querying the SQLite Database

The guard calls `lifecycle.ActiveRuns(p)` defined in [`internal/lifecycle/guard.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/lifecycle/guard.go), which opens the local SQLite database via `p.DB()` from [`internal/paths/paths.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/paths/paths.go). It executes a query against the `runs` table to retrieve any rows where the status is **pending** or **running**.

This database-driven approach ensures the guard always checks the ground truth of daemon state, regardless of process signals or memory cache inconsistencies.

### Run Status Evaluation

The `ActiveRuns` function returns a slice of active run records. The guard then evaluates this slice to determine if a destructive lifecycle change is safe:

- **Empty result**: No active runs exist, allowing immediate shutdown
- **Non-empty result**: Active pipelines are in progress, triggering the protective refusal logic

## Decision Logic and User Interaction

The `guardDestructiveDaemonLifecycle` function implements a three-tier decision tree that balances safety with operational flexibility.

### Safe Shutdown Path

When no active runs exist, the guard returns `nil` immediately, allowing the CLI command to proceed to `daemonStopFn` or `daemonStartFn`:

```bash
$ no-mistakes daemon stop
  ✓ daemon stopped

```

### The Force Override Mechanism

If active runs exist, the guard checks for the `--force` flag:

**Without `--force`**, the guard returns an error containing a refusal message and a formatted list of active runs (`lifecycle.RunList`), causing the command to abort before any shutdown occurs:

```bash
$ no-mistakes daemon stop
Error: refusing daemon stop because 2 active pipeline runs are in progress;
feature-a  aaa111  main  a1b2c3d4
feature-b  bbb222  main  d4c3b2a1

```

**With `--force`**, the guard prints a warning message detailing the active runs but returns `nil`, permitting the operation to proceed:

```bash
$ no-mistakes daemon stop --force
FORCE: daemon stop will stop/restart the daemon while 2 active pipeline runs are in progress
active pipeline runs:
  feature-a  aaa111  main  a1b2c3d4
  feature-b  bbb222  main  d4c3b2a1
  ✓ daemon stopped

```

## Integration with CLI Commands

The guard is invoked from `newDaemonStopCmd` and `newDaemonRestartCmd` in [`internal/cli/daemon_cmd.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/daemon_cmd.go). These command constructors wrap the actual shutdown functions (`daemonStopFn` and `daemonStartFn`) with the protective check.

If `guardDestructiveDaemonLifecycle` returns an error, the CLI propagates that error immediately and never reaches the underlying shutdown logic. This architectural pattern ensures that the guard acts as an impenetrable gatekeeper—there is no code path that allows daemon termination without first passing the active-run verification.

```go
func stopDaemon(p *paths.Paths, force bool) error {
    // Guard prevents accidental shutdown during active runs.
    if err := guardDestructiveDaemonLifecycle(p, os.Stderr, "daemon stop", force); err != nil {
        return err
    }
    return daemonStopFn(p) // actual shutdown only executes after guard passes
}

```

## Audit Logging and Compliance

Regardless of whether the guard permits or denies the operation, the command logs the invocation via `logLifecycleInvocation`. When `--force` is used, the system records the override in `<NM_HOME>/logs/cli.log` along with caller attribution including PID, PPID, and parent command line.

The test suite in [`internal/cli/daemon_lifecycle_test.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/daemon_lifecycle_test.go) verifies this behavior, ensuring that:
- The guard refuses stopping when active runs exist
- The `--force` flag correctly overrides the protection
- Audit trails capture force-override events with proper caller attribution

## Summary

- The **destructive daemon lifecycle guard** queries the SQLite `runs` table via [`internal/lifecycle/guard.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/lifecycle/guard.go) to detect pending or active pipeline executions.
- Without active runs, `daemon stop` and `daemon restart` commands execute immediately.
- When active runs exist, the guard returns an error and aborts the command unless `--force` is specified.
- The guard is integrated into [`internal/cli/daemon_cmd.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/cli/daemon_cmd.go) before any shutdown function calls, ensuring zero bypass paths.
- All lifecycle events are audited to `<NM_HOME>/logs/cli.log` with caller attribution for compliance and forensics.

## Frequently Asked Questions

### What happens if I try to stop the daemon while a pipeline is running?

The CLI outputs an error message listing the active runs and aborts the command. The daemon continues running, and no shutdown logic executes. You must either wait for the pipelines to complete or use the `--force` flag to override the protection.

### How do I force the daemon to stop despite active runs?

Append the `--force` flag to your command: `no-mistakes daemon stop --force` or `no-mistakes daemon restart --force`. The guard will print a warning showing the active runs and proceed with the shutdown. This action is logged with full caller attribution including PID and command line for audit purposes.

### Where does the guard check for active runs?

The guard checks the local SQLite database via [`internal/lifecycle/guard.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/lifecycle/guard.go), specifically the `ActiveRuns` function. It reads from the `runs` table (defined in [`internal/db/run.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/db/run.go)) to identify rows with status *pending* or *running*.

### Is there a way to see which runs are blocking the shutdown?

Yes. When the guard refuses a shutdown, it prints a formatted list of active runs showing the feature name, run ID, branch, and commit hash. When using `--force`, this same list appears in the warning message before the daemon stops.