# How the Intent Validation System in no-mistakes Prevents Scope Creep

> Discover how no-mistakes' intent validation system prevents scope creep by matching LLM agent transcripts to Git diffs. Learn about its four-stage pipeline and strict guardrails.

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

---

**The intent validation system in `no-mistakes` extracts developer intent from LLM agent transcripts and validates it against Git diffs through a four-stage pipeline with strict guardrails that reject low-coverage, stale, or single-file matches.**

The `no-mistakes` repository provides a tool that bridges the gap between AI-assisted coding sessions and version control by ensuring that only relevant, high-confidence intent gets attached to code changes. Its **intent validation system** analyzes transcripts from agents like Claude, Codex, and Pi to determine whether a conversation truly reflects the work being committed. This validation pipeline lives in the `internal/intent` package and enforces strict criteria to prevent unrelated files from being accidentally included in an intent's scope.

## The Four-Stage Validation Pipeline

The validation process orchestrated in [`internal/intent/intent.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/intent.go) consists of four distinct stages that progressively filter agent sessions until only the most relevant candidate remains.

### Discovery

The pipeline begins with the **Discovery** phase, where each enabled agent reader (implemented in files like [`internal/intent/reader_claude.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/reader_claude.go) and [`internal/intent/reader_pi.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/reader_pi.go)) scans its worktree for sessions that fall within the time window defined by the base and head commit timestamps. The `DiscoverOpts` struct configures this search window, allowing the system to locate only contemporary sessions that could plausibly relate to the current changes. According to the source code at [`internal/intent/intent.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/intent.go) lines 79-86, this phase establishes the candidate pool for subsequent validation.

### Loading

Once candidate sessions are identified, the **Loading** phase retrieves the full message bodies so that file mentions can be examined in detail. This step ensures that the system has complete context for scoring rather than relying on session metadata alone. The implementation in [`internal/intent/intent.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/intent.go) (around line 87) handles the retrieval of these conversation logs from various agent readers.

### Matching and Scoring

The core validation logic resides in [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go), specifically in the `score` function (lines 30-57). This phase calculates the fraction of diff files that appear in each session's messages, producing a numeric `score` representing coverage overlap. For example, if a session mentions two of the four files changed in a diff, it receives a score of 0.5. This quantitative measure forms the basis for the subsequent acceptance decision.

### Acceptance and Disambiguation

The final stage applies a series of strict guardrails through the `acceptMatchCandidate` function in [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go) (lines 45-64). Only candidates passing all checks are ranked by confidence (raw score plus a recency boost) and potentially processed by a disambiguator if multiple candidates remain plausible. Validated intents are then memoized in an intent cache ([`internal/intent/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/cache.go)) to avoid re-summarizing transcripts on subsequent runs.

## Guardrails That Prevent Scope Creep

The `acceptMatchCandidate` function implements five precise guardrails that collectively prevent scope creep by rejecting intent attachment when coverage is insufficient, stale, or coincidental:

- **No overlap rejection**: When `overlapCount == 0`, the function returns `false` with reason `"no_overlap"`. This prevents attaching intent when the agent session never mentioned any changed file.

- **Multi-file sanity check**: For multi-file diffs where `diffCount > 1`, the system requires `overlapCount >= 2`. If a session touches only one file when many changed, it returns `false` with `"single_overlap_multi_file_diff"`, avoiding the broadening of intent to unrelated files.

- **Threshold enforcement**: The system rejects candidates with `score < threshold`. For multi-file diffs, the threshold automatically raises to 0.5 if the default is lower, ensuring at least half of the changed files are covered before intent attachment.

- **Stale partial protection**: Sessions older than 24 hours with `score < 0.8` are rejected with `"stale_partial"`. This blocks outdated sessions that cover only a fraction of the diff from influencing the current commit's intent.

- **Recency boost application**: While recent sessions receive a small confidence bump via `recencyBoost`, this never lowers the required threshold. This preference for recent activity prevents stale sessions from winning on coverage alone.

Together, these rules ensure that an intent attaches **only** when a session mentions a significant portion of changed files, maintains recency, and respects minimum overlap thresholds.

## Implementation Example

The following example demonstrates how to invoke the intent extraction pipeline with custom guardrails:

```go
// Example: performing intent extraction inside a CLI command.
ctx := context.Background()
params := intent.ExtractParams{
    OriginCWD:   cwd,
    DiffFiles:   []string{"pkg/foo/bar.go", "cmd/cli/main.go"},
    BaseTime:    baseCommitTime,
    HeadTime:    headCommitTime,
    SlackDays:   3,
    Threshold:   0.6,               // custom threshold, higher than default for safety
    Readers:     []intent.Reader{intent.NewRovoDevReader(), intent.NewClaudeReader()},
    Cache:       intent.NewMemCache(),
    Summarizer:  intent.NewOpenAISummarizer(),
    Disambiguator: intent.NewSimpleDisambiguator(),
    Logf:        log.Printf,
}
res, err := intent.Extract(ctx, params)
if err != nil && err != intent.ErrNoMatch {
    // handle unexpected failure
}
if err == intent.ErrNoMatch {
    fmt.Println("No intent could be attached to this change")
} else {
    fmt.Printf("Attached intent (score %.2f): %s\n", res.Score, res.Summary)
}

```

The guardrails execute within the matching logic as shown in this excerpt from [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go):

```go
// The acceptance guardrails in action (excerpt from matcher.go)
func acceptMatchCandidate(score float64, overlapCount, diffCount int,
    lastActivity time.Time, opts matchOptions) (bool, string, float64) {

    if diffCount == 0 || overlapCount == 0 {
        return false, "no_overlap", score           // ← prevents scope creep
    }
    // Enforce a higher threshold for multi‑file diffs.
    threshold := opts.Threshold
    if diffCount > 1 && threshold < 0.5 {
        threshold = 0.5
    }
    // Reject a session that only touches one file when many files changed.
    if diffCount > 1 && overlapCount < 2 {
        return false, "single_overlap_multi_file_diff", score
    }
    if score < threshold {
        return false, "below_threshold", score
    }
    // Reject stale sessions that cover only a tiny part of the diff.
    if !opts.HeadTime.IsZero() && lastActivity.Before(opts.HeadTime.Add(-24*time.Hour)) && score < 0.8 {
        return false, "stale_partial", confidence
    }
    // Passed all guards → accept.
    confidence := score + recencyBoost(opts.HeadTime, lastActivity)
    return true, "matched", confidence
}

```

## Summary

- The **intent validation system** in `no-mistakes` operates through a four-stage pipeline: Discovery, Loading, Matching, and Acceptance.
- The `acceptMatchCandidate` function in [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go) enforces five guardrails that reject low-coverage, stale, or single-file matches.
- Multi-file diffs automatically trigger a higher threshold (0.5) and require overlaps with at least two files to prevent scope creep.
- The system caches validated intents via the `Cache` interface ([`internal/intent/cache.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/cache.go)) and generates summaries using the `Summarizer` ([`internal/intent/summarizer.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/summarizer.go)).
- Only sessions with sufficient recent coverage receive attached intent, ensuring that commit messages accurately reflect the actual development work.

## Frequently Asked Questions

### What is the intent validation system in no-mistakes?

The intent validation system is a Go package located in `internal/intent` that extracts developer intent from LLM agent transcripts (Claude, Codex, Pi, etc.) and validates it against the current Git diff. It ensures that only agent sessions with significant file coverage and recency influence commit intent, preventing unrelated changes from being accidentally grouped together.

### How does no-mistakes prevent scope creep?

The system prevents scope creep through the `acceptMatchCandidate` guardrails in [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go). These rules reject sessions that lack overlap with changed files, cover only one file in multi-file changes, fall below coverage thresholds, or represent stale activity older than 24 hours with less than 80% coverage. By requiring multiple validation criteria, the system ensures intent attaches only to genuinely related changes.

### What threshold does the system use for multi-file changes?

For multi-file diffs where `diffCount > 1`, the system automatically raises the acceptance threshold to 0.5 if the configured threshold is lower. This ensures that at least 50% of changed files must be mentioned in the agent session before intent can be attached, preventing single-file coincidences from defining multi-file commit intent.

### Where is the matching logic implemented?

The core matching and scoring logic resides in [`internal/intent/matcher.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/matcher.go). The `score` function (lines 30-57) calculates file overlap percentages, while `acceptMatchCandidate` (lines 45-64) implements the guardrails that prevent scope creep. The orchestration logic connecting these components exists in [`internal/intent/intent.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/intent/intent.go).