---
title: izri/scope
description: Does the diff match what the pull request says it does — and did it touch paths it shouldn't?
order: 20
---

# `izri/scope`

Scope answers: **does this diff do what the PR claims, and only that?**

It is the signal that catches the change nobody asked for — the refactor smuggled into a bugfix, the config edit that rode along with a feature, the migration that appeared in a docs PR. Agent-written PRs drift this way constantly, because an agent asked to fix one thing will happily fix four.

## What it compares

Two things:

- **Declared intent** — the PR title, labels, and body. Conventional-commit prefixes are parsed for the declared type.
- **Actual diff** — which files changed, which categories and modules they belong to, and how much changed.

The comparison runs in two layers.

### The rule layer (always on)

Deterministic, fast, free on every plan, no LLM. It produces:

- **Path categorization** — mapping changed files onto your project's module and category vocabulary.
- **Type-vs-files alignment** — does a `fix:` PR look like a fix?
- **Sensitive-path detection** — did this touch something you flagged?
- **Scale anomalies** — is this far bigger or smaller than the stated intent implies?

### The semantic layer (opt-in)

An LLM comparison of stated intent against intent derived from the diff. It catches drift the rule layer can't see — a PR that says "update copy" and rewrites an auth flow, where both are "small changes to two files."

It costs AI tokens and is gated by plan. Enable per-invocation:

```bash
izri check-scope --semantic
```

The rule layer runs either way, so scope never depends on an LLM being available.

## The alignment score

0–100, how well the diff matches its declared intent. It feeds the umbrella composite at weight **0.24**.

The score is a soft signal. A low alignment score alone doesn't block a merge — it drags the composite, and the merge blocks only if the composite lands under 70.

## Findings

| Category | Severity | Meaning |
| --- | --- | --- |
| `pr_type_forbidden_category` | `error` | The diff changed a category the declared PR type forbids. **Hard rule — fails the umbrella outright.** |
| `pr_type_mismatch` | `warn` | The diff doesn't look like what the PR type claims. |
| `test_removal` | `warn` | Tests were deleted. Sometimes correct, always worth seeing. |
| `scale_anomaly` | `warn` / `info` | The change is much larger or smaller than the stated intent implies. |
| `structural_drift` | `info` | Module boundaries moved. |
| `sensitive_path` | `info` | A path marked sensitive in your config was touched. |

**Only `pr_type_forbidden_category` blocks on its own.** In particular `sensitive_path` is `info` by design: a hint that a human should look, not an assertion that something is wrong. If your team wants a sensitive path to be a hard gate, express that as a forbidden category for the PR type rather than expecting the hint to block.

## Configuration

Scope reads `.izri/scope.yml` from your PR head — checked in, code-reviewable, and versioned with the code it governs. Resolution precedence and the full schema are in [the scope.yml reference](/docs/configure/scope-yml).

## Running it locally

```bash
izri check-scope
izri check-scope --base origin/develop
izri check-scope --json
```

Deterministic and fast, so it's cheap to run before pushing. See [the CLI reference](/docs/install/cli).

## Related

- [Signals overview](/docs/signals/overview) — how scope aggregates with the others.
- [`.izri/scope.yml`](/docs/configure/scope-yml) — the config that drives it.
