# What Happens When Findings Have Empty or Missing Action Classifications in no-mistakes

> Discover what happens when findings have empty or missing action classifications in no-mistakes. Learn how the system defaults to ask-user for human review instead of automatic fixes.

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

---

**When a finding in the no-mistakes pipeline has an empty or missing `action` field, the system defaults to `"ask-user"`, forcing the run to pause for human review rather than applying automatic fixes or silently ignoring the issue.**

The **no-mistakes** repository implements a security-conscious CI/CD engine where automated reviews, tests, and linting results are modeled as `Finding` objects. Each finding carries an `action` classification that dictates whether the daemon should auto-apply fixes, skip the issue, or request human guidance. Understanding how the system handles empty or missing action classifications is essential for predicting pipeline behavior when upstream integrations return incomplete data or omit the field entirely.

## The Default Action Mechanism

The no-mistakes codebase treats an unset `action` string as a signal to halt automation and request human input. This behavior is implemented through a combination of legacy JSON unmarshalling logic and a centralized default-action helper.

### JSON Unmarshalling Logic

During deserialization, the `UnmarshalJSON` method in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go) handles the legacy `requires_human_review` boolean flag while setting up the action field. If the incoming JSON lacks an `action` value (leaving `f.Action` as an empty string) and the legacy flag is absent, the struct field remains empty. This empty state is later interpreted by the effective-action helper.

```go
// internal/types/findings.go:40-46
if f.Action == "" && wire.RequiresHumanReview != nil {
    if *wire.RequiresHumanReview {
        f.Action = ActionAskUser
    } else {
        f.Action = ActionAutoFix
    }
}

```

### The actionOrDefault Helper Method

The single source of truth for interpreting a finding’s action is the `actionOrDefault` method. This helper explicitly returns `ActionAskUser` when the underlying field is empty, ensuring consistent behavior across all pipeline steps.

```go
// internal/types/findings.go:58-62
func (f Finding) actionOrDefault() string {
    if f.Action == "" {
        return ActionAskUser   // default
    }
    return f.Action
}

```

## Impact on Pipeline Operations

All higher-level pipeline logic relies on `actionOrDefault()` to determine how to process findings. An empty or missing action classification triggers specific behaviors in three key areas.

### Detection of User-Review Requirements

The `HasAskUserFindings` function iterates over `findings.Items` and treats any empty or missing action as `"ask-user"` according to the effective-action helper. When this function returns true, the pipeline step must pause and wait for human input.

```go
// internal/types/findings.go:31-38
if item.actionOrDefault() == ActionAskUser { … }

```

### Auto-Fix Filtering

The `AutoFixableFindings` function filters a collection to return only items that can be automatically resolved. Because `actionOrDefault()` returns `"ask-user"` for empty actions, findings with missing classifications are explicitly excluded from the auto-fix set.

```go
// internal/types/findings.go:67-75
// Includes finding only when actionOrDefault() == ActionAutoFix

```

### Actionable Findings Classification

The `HasActionableFindings` helper determines whether a force-push or deployment should proceed. It considers a finding actionable if its effective action is anything other than `"no-op"`. Since the default is `"ask-user"`, a missing action makes the finding actionable, meaning the run will pause rather than be silently ignored.

```go
// internal/types/findings.go:45-55
// Considers item actionable if actionOrDefault() != ActionNoOp

```

## Security Design Philosophy

This default-to-ask-user strategy implements a **fail-closed** security model. By forcing human review when classifications are ambiguous, the system prevents potential security findings from being auto-fixed without explicit intent. This aligns with the repository’s design principle: *"When in doubt, default to ask-user."*

## Practical Code Examples

When a third-party scanner emits a finding without an action classification, the no-mistakes pipeline treats it as requiring human review.

**Example payload with missing action:**

```json
{
    "id": "f1",
    "severity": "high",
    "description": "Use of insecure random number generator",
    "source": "agent"
}

```

**Processing the finding in Go:**

```go
var f types.Finding
json.Unmarshal([]byte(payload), &f)

// f.Action == ""

if f.actionOrDefault() == types.ActionAskUser {
    // Execution pauses here for human guidance
}

```

**Filtering for auto-fixable items:**

```go
autoFixes := types.AutoFixableFindings(allFindings)
// autoFixes will NOT contain the finding above because
// it defaults to ask-user, not auto-fix

```

## Summary

- The **no-mistakes** pipeline defaults empty or missing `action` fields to `"ask-user"` via the `actionOrDefault()` helper in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go).
- The `UnmarshalJSON` method handles legacy flags but leaves the action empty when neither the field nor legacy metadata is present.
- Missing actions exclude findings from `AutoFixableFindings` collections, preventing automatic application.
- Empty actions trigger `HasAskUserFindings`, forcing the pipeline to pause for human review.
- This design implements a fail-closed security model, ensuring unclassified findings cannot bypass human oversight.

## Frequently Asked Questions

### What are the valid action classifications in no-mistakes?

The system recognizes three action strings: `"no-op"` (informational, requires no action), `"auto-fix"` (the daemon may apply the change automatically), and `"ask-user"` (the run must pause for human guidance). These constants are defined in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go).

### Can I configure the default behavior to use "auto-fix" instead of "ask-user"?

No. The default behavior is hardcoded in the `actionOrDefault` method. Changing the default would require modifying the source code in [`internal/types/findings.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/types/findings.go), as the fail-closed design intentionally prevents unclassified findings from being automatically applied.

### How does the legacy requires_human_review flag interact with missing actions?

If the JSON payload includes the legacy `requires_human_review` boolean and the `action` field is empty, the `UnmarshalJSON` method maps the boolean to the appropriate action (`"ask-user"` for true, `"auto-fix"` for false). If both the action field and the legacy flag are missing, `actionOrDefault()` returns `"ask-user"`.

### Will an empty action classification stop a force-push operation?

Yes. The [`forcepush.go`](https://github.com/kunchenguid/no-mistakes/blob/main/forcepush.go) step relies on `HasActionableFindings`, which returns true for any finding where `actionOrDefault()` is not `"no-op"`. Since empty actions default to `"ask-user"`, they are considered actionable and will block the force-push until human confirmation is received.