Scope analysis & configuration
The izri/scope signal compares a PR's changed files against a
declarative scope config — the team vocabulary of what counts as
a module, a category of work, and a sensitive area. The analyzer
turns the file diff plus the intent (PR title + body) into an
alignment score, a bucketed view of changed files, and per-rule
findings.
Two sources of scope config
Scope config can live in two places:
- Dashboard —
project_scope_configsrows seeded by the LLM/derive-scopejob on project connect, edited later from/organizations/<slug>/projects/<id>/scope. Versioned. - In repo —
.izri/scope.ymlat the PR head, checked into the customer's repository and code-review-able.
In-repo wins when valid. The file at the PR head SHA reflects what the team is intentionally shipping with this delta; the dashboard config can lag (someone forgot to update it) but the checked-in file can't. If the in-repo file is missing or fails validation we fall back to the dashboard config, and if neither is available the analyzer uses baked-in defaults.
The active source for a given delta is surfaced as a small badge on
the scope card of the delta report — Using .izri/scope.yml when
the in-repo file took precedence.
File location
<repo-root>/.izri/scope.yml
Place exactly at .izri/scope.yml. Other paths and other extensions
(.yaml, .json) are not recognized.
Schema
The file is validated against the same Zod schema that gates
dashboard configs (packages/trpc/src/types/scopeCheck.ts :: ScopeConfigSchema). All three top-level arrays are required, even
when empty.
# Logical modules in your codebase. The analyzer uses these to group
# changed files into "what part of the system did this PR touch?".
# `paths` are globs — minimatch syntax.
modules:
- name: auth
paths:
- "packages/auth/**"
- name: web
paths:
- "apps/web/**"
# Categories of work the PR intent should resolve to (parsed from the
# PR title + body). Each category can optionally require a stated
# intent or a test change. `expects` and `forbids` are advisory hints
# the analyzer surfaces in its rationale.
categories:
- label: feature
requires_intent_statement: true
- label: bugfix
requires_test_change: true
- label: docs
# Paths whose modification produces a soft `sensitive_path` finding.
# Use for areas where review attention matters more than usual —
# auth, billing, migrations. Sensitive findings are informational by
# default (they don't block the umbrella).
sensitive:
- name: env_files
paths:
- ".env*"
- name: db_migrations
paths:
- "packages/database/migrations/**"
Override semantics
| Situation | Source recorded | Behaviour |
|---|---|---|
.izri/scope.yml parses + passes schema validation |
in_repo |
The in-repo config is used. Dashboard config is ignored for this delta. |
.izri/scope.yml missing |
dashboard |
Dashboard config used. Falls through to defaults if no dashboard config exists. |
.izri/scope.yml malformed YAML or schema mismatch |
dashboard |
Dashboard config used (or defaults). One info-severity scope finding is emitted naming the file and the failure. |
| Neither in-repo nor dashboard config | defaults |
Analyzer falls back to baked-in defaults — useful findings on day one for first-time projects. |
A malformed in-repo file is never fatal. The analyzer always produces a verdict; the misconfiguration shows up as an info finding on the scope card so a reviewer can see what happened without the PR being blocked.
Where the source is recorded
The resolved source is persisted in two places:
scope_checks.scope_config_source— source of truth, per analysis.delta_reports.scope_config_source— denormalized cache of the latest scope_check's source, so dashboard / API reads don't need a join.
Both columns take one of 'dashboard', 'in_repo', 'defaults'.
Rows written before the column was added are nullable.
Why in-repo wins
The reverse default ("dashboard wins, in-repo file is a hint") would mean a customer who checks in a config file might see the analyzer disagree with what's actually in their repo, with no clear signal which one ran. Inverting later (in-repo wins → dashboard wins) would silently change behaviour for every project that already relies on it. In-repo as the override is the safer default to ship first: the file someone reviewed with the PR is the one that drives the analysis.
See issue #234.