## ADDED Requirements

### Requirement: Scanner Produces Scan Metadata, Shortlist, and Per-Path Signals

The scanner SHALL deterministically walk the scoped files under the resolved
project root and emit an intermediate artifact containing: the scan-provenance
fields `project_root` (absolute path to the resolved project root),
`scope_globs` (the glob patterns that were applied), `excluded_dirs` (the
directory names pruned at walk time), and `files_scanned` (count of files
considered before shortlisting); a `shortlist` of project-root-relative
candidate paths; and the per-path objective `signals` supporting each
candidate. The scanner SHALL use no model. The emitted `signals` SHALL be
objective scanner facts only (for example broken references, version skew,
edit-recency versus git churn, location, append-only growth, archive-to-live
ratio, frontmatter markers) and SHALL carry no classification or judgment. The
`check` change consumes this intermediate artifact and folds `project_root`,
`scope_globs`, `excluded_dirs`, and `files_scanned` into the report envelope's
`scan` block.

#### Scenario: Scanner emits scan metadata plus shortlist plus signals

- **WHEN** the scanner runs over a project tree
- **THEN** it emits an intermediate artifact with `project_root`, `scope_globs`, `excluded_dirs`, and `files_scanned` (scan provenance), a `shortlist` of candidate paths, and the per-path objective `signals`, computed with no model

#### Scenario: Scan metadata matches what was actually scanned

- **WHEN** the scanner walks a project rooted at `/home/user/myproject` using globs `["**/*.md"]`, pruning `["build", "vendor", ".dochygiene"]`, and considers 42 files before shortlisting
- **THEN** the intermediate artifact contains `project_root` = `/home/user/myproject`, `scope_globs` = `["**/*.md"]`, `excluded_dirs` = `["build", "vendor", ".dochygiene"]`, and `files_scanned` = `42`

#### Scenario: Signals are objective facts only

- **WHEN** the scanner attaches signals to a candidate path
- **THEN** each signal is an objective fact (such as a broken reference or version skew) and contains no stale/bloat classification

### Requirement: Scanner Emits an Intermediate Artifact, Not a Report

The scanner SHALL NOT produce the machine report, `entries`, `category`, `op`,
`op_type`, `safety_tier`, `exact_edit`, or `token_estimate`. Those are produced by
the AI `check` pass. The scanner's output SHALL be consumed by the `check` change,
which folds `project_root`, `scope_globs`, `excluded_dirs`, and `files_scanned`
into `report.scan`, and folds `shortlist` and `entries[].signals` from the
intermediate artifact into the corresponding report fields.

#### Scenario: Scanner does not classify

- **WHEN** the scanner finishes a run
- **THEN** its output contains no `entries`, no `category`, no `op`, and no `token_estimate` — only the scan metadata fields, the shortlist, and per-path signals

#### Scenario: Report schema is consumed, not produced here

- **WHEN** the `check` change builds the machine report
- **THEN** it reads the scanner's intermediate artifact and supplies `report.scan` (from the scan metadata fields), `report.shortlist`, and `entries[].signals` from it, without the scanner having written a report

### Requirement: Frozen, Ignored, and Append-Only Files Are Excluded

The scanner SHALL exclude from the shortlist any file marked `hygiene: frozen` in
its frontmatter, any file matched by a `.dochygiene-ignore` pattern, and any file
detected as an append-only log. An excluded file SHALL never appear in the
shortlist or carry signals in the output.

#### Scenario: Frozen frontmatter is excluded

- **WHEN** a scanned file has `hygiene: frozen` in its YAML frontmatter
- **THEN** the file is absent from the shortlist

#### Scenario: Ignore-pattern match is excluded

- **WHEN** a file's path matches a pattern in `.dochygiene-ignore`
- **THEN** the file is absent from the shortlist

#### Scenario: Append-only log is excluded

- **WHEN** a file is deterministically detected as an append-only log
- **THEN** the file is absent from the shortlist

### Requirement: Scanner Excludes Configured Directories and Self-Excludes

The scanner SHALL prune the configured `scan.excluded_dirs` (`build`, `vendor`,
`archive`, `graphify-out`, `.dochygiene`) at the directory level so those trees
are never descended, and SHALL self-exclude its own `.dochygiene/` state directory
regardless of configuration. Directory pruning SHALL precede signal computation so
excluded files cost no work.

#### Scenario: Excluded directory is not descended

- **WHEN** a path component of a file is one of the excluded dirs (for example `vendor/`)
- **THEN** that subtree is pruned and none of its files appear in the shortlist

#### Scenario: State directory is always self-excluded

- **WHEN** the scanner walks a project that contains a `.dochygiene/` directory
- **THEN** `.dochygiene/` and its contents are never scanned and never shortlisted, regardless of configuration

### Requirement: Exclusion Precedes Signal Computation

The exclusion pipeline SHALL be applied before signals are computed for a file, so
that a file matching any exclusion (excluded dir, ignore pattern, frozen
frontmatter, append-only) is dropped without computing or emitting signals for it.

#### Scenario: An excluded file produces no signals

- **WHEN** a file matches any exclusion rule
- **THEN** the scanner computes no signals for it and emits neither its path nor signals
