# Change: Add Report Schema ## Why The machine report schema is the linchpin of doc-hygiene: it is the contract that the `check` skill produces and that the `clean` skill, `sweep`, and the token estimator all consume. Per the build order, it gates everything — no component can be built correctly until the report's shape is fixed. The PRD and CLAUDE.md state it is "designed and frozen first." This change specifies that schema as a frozen contract before any code exists, so that the deterministic core and the AI layers are built against a single, stable structure rather than re-deriving it. It is spec-authoring only: no scripts and no schema code are produced here. ## What Changes - Define the **top-level machine report** structure: schema version, scan metadata (scope, files scanned, generated-at timestamp, tool version), the candidate **shortlist**, and a per-file **entries** list. - Define the **per-file report entry** fields: `path`, `category` (with the fixed stale/bloat sub-type taxonomy), `signals`, recommended `op`, `op_type` (`deterministic` | `generative`), the op characterization booleans `is_destructive` and `is_reversible`, a **derived** `safety_tier` (`auto` | `confirm`), an optional `exact_edit` (present iff `op_type` is `deterministic`), and a per-entry `token_estimate`. - Fix the **category taxonomy** as a closed enum: stale = `contradicted` | `orphaned` | `superseded` | `provisional` | `completed-in-place` | `duplicated`; bloat = `distill` | `split` | `freeze`. - Make **`op_type` a property of the chosen `op`** (not a free field, not a subtype lookup): `op_type` must be consistent with `op`, with `exact_edit` present iff `op_type` is `deterministic`, validated deterministically. - Make **`safety_tier` derived deterministically** per invariant #7: the model proposes `op`, `op_type`, `is_destructive`, and `is_reversible`; a script function `safety_tier(op_type, is_destructive, is_reversible)` computes the tier (generative ⟹ confirm; destructive or irreversible ⟹ confirm; only deterministic + reversible + objective ⟹ auto). The model cannot emit `auto` for a generative or destructive op. - Scope the **`token_estimate`** to match the PRD build order: in v1 only `raw_tokens` (deterministic local-tokenizer count, no API call) is required; `injection_frequency` and `weighted_tokens` are optional/nullable v1 fields whose population (injection-frequency weighting + bottom-up rollup) is the v2 bonus. The schema shape is fixed now so the contract never changes. - Freeze the **`exact_edit.kind`** closed enum: one `kind` per deterministic op family the PRD names (`delete-range`, `move-to-archive`, `insert-frontmatter` for freeze-stamp, `replace-text` for known-target link fix, `dedupe` for exact-dup removal), each with its required sub-fields and inherent `(is_destructive, is_reversible)` characterization that feeds the `safety_tier` derivation. - Declare the schema a **frozen contract** enforced by `invariants.md` (which now exists and carries the schema-freeze and `safety_tier` derivation invariants): changing any field, enum value, or semantic requires updating `invariants.md` with explicit human approval. - Provide schema-shape verification: a **schema-validator script** plus two hand-authored **schema fixtures** under `examples/golden/` (one valid machine report, one invalid) proving the validator accepts/rejects correctly. These are schema-shape fixtures, **not** classifier golden examples — the latter are deferred until the `check` change exists (the classifier that would produce them does not exist yet, so hand-authoring them now risks diverging from real classifier output). ## Impact - Affected specs: creates a new `report-schema` capability. - Affected code: none yet. This is the contract every later component (scanner, `check` skill, `clean` skill / patch-applier, token estimator, `sweep`) will consume; those are out of scope here. The only artifacts this change produces beyond the spec are the schema-validator script and the two `examples/golden/` schema fixtures used to verify the schema shape. - Human-readable report ownership: this change specifies only the **machine** report. The human-readable `.md` report SHAPE is a sibling user-facing contract owned by the upcoming `check` change. It is load-bearing for the confirm-tier escalation UX (it is what the user reads when approving `confirm` ops), so it must be treated as a contract in its own right — out of scope here, but its owner is named so it is not left ownerless. - Deferred: **classifier golden examples** are deferred to after the `check` change (the classifier that produces them does not exist yet). This change ships only schema-shape fixtures, which are distinct. - Dependencies: none. This change is the first in the build order and unblocks the deterministic core and the `check` skill.