# Tasks: Add Check > **Execution shape:** Task 1 is a **human-gate** (already discharged — the > `report_builder.py` finalize pass is approved). Group 2 (`report_builder.py` + > tests) and Group 3 (`commands/hygiene.md`) are **independent and run in > parallel**. Group 4 (the `hygiene-check` skill) is **sequential after Groups 2 > and 3**. Group 5 (classifier goldens + hermetic harness) is **sequential after > Groups 2 and 4** and is **human-gated** per the META-RULE. Group 6 (CONTEXT.md) > runs last. Model routing is annotated per group. ## 1. Human-gate — approve the deterministic finalize pass (DONE) - [x] 1.1 Approve `report_builder.py` as a standalone, model-free finalize pass interposed between model classification and `StateStore.write_report`, owning the four fields the model must not author (`expected_sha256`, `safety_tier`, `is_destructive`/`is_reversible` for deterministic ops, `raw_tokens`). ## 2. `report_builder.py` + tests — parallel with Group 3 (model: Sonnet) - [ ] 2.1 Implement `scripts/report_builder.py` as a standalone, model-free assembler. Input: the scanner artifact + the model's slim per-file classification proposals. Output: a full schema-valid machine report + a deterministic human-report skeleton. Use an injected clock/filesystem. - [ ] 2.2 Compute `exact_edit.expected_sha256` over each file's **current bytes** for anchor-bearing kinds only; note that `insert-frontmatter` (`has_anchor = False`) carries no `expected_sha256` (deferred hole for clean). - [ ] 2.3 Set `(is_destructive, is_reversible)` from `KIND_TABLE[kind]` and compute `safety_tier = derive_safety_tier(op_type, is_destructive, is_reversible)`, both **imported** from `validate_report.py` (single source of truth — invariant #10; no re-implementation). - [ ] 2.4 Extract the span (anchor range / `reducible_range` / whole file for `move-to-archive`) and source `token_estimate` via `token_estimator.default_estimator().estimate_for_report(span_text)` — v1 `raw_tokens` only, weighting `null` (invariant #6). - [ ] 2.5 Assemble the envelope: `schema_version` `"1.0"`, `tool_version` read from `plugin.json` (flag a mismatch with `valid_report.json`), per-entry `generated_at` = that file's hash instant, envelope `generated_at` = the run instant. Emit the deterministic human-report skeleton (mechanical parts only). - [ ] 2.6 Reject malformed proposal JSON before computing any field. - [ ] 2.7 **Tests:** assert the sha256, the derived `(is_destructive, is_reversible, safety_tier)`, and `raw_tokens` for each kind; assert the assembled report round-trips through `validate_report.py` (exit 0); assert the generative path counts `raw_tokens` over the non-persisted `reducible_range`; injected clock/fs. ## 3. `commands/hygiene.md` — parallel with Group 2 (model: Haiku) - [ ] 3.1 Author a single `commands/hygiene.md` with minimal frontmatter (`name: hygiene`; description naming `/hygiene check` and `/hygiene status`) that dispatches on `$ARGUMENTS`. - [ ] 3.2 Route `check [--scope ] [--category ]` → invoke the `hygiene-check` skill (pass the flags through). - [ ] 3.3 Implement `status` **inline** (a few `python3` calls): read `get_last_check` / `get_last_clean` / `get_last_reminded` and whether a report exists. Read-only — no scan, no model. - [ ] 3.4 Reserve `clean` / `sweep` with a "not yet implemented (Phase 4)" message; print usage + current status for no/unknown args. ## 4. `skills/hygiene-check/SKILL.md` — sequential after Groups 2, 3 (model: Sonnet) - [ ] 4.1 Author `skills/hygiene-check/SKILL.md` with frontmatter mirroring the `commit` skill. The subagent points at a **workflow doc**, not SKILL.md itself, to avoid recursion (per the `commit`-skill precedent). - [ ] 4.2 Implement the deterministic steps: scan (`scanner.py`, `--scope` → `--globs`/path filter), select signal-bearing candidates (zero-signal files presumptively cleared, not read by the model), finalize (`report_builder.py`), validate **on a scratch path** (validate-before-rollover, invariant #4), write (`write_report`), stamp (`set_last_check` with the same run instant). - [ ] 4.3 Write the **Sonnet classification subagent prompt**: per signal-bearing file, return a slim judgment-only proposal (`category` from the closed enum, `signals` verbatim + optional `detail` gloss, `op`, `op_type`, the `exact_edit` **skeleton** for deterministic or a non-persisted `reducible_range` for generative, `confidence`). The model supplies **no** `expected_sha256` / `is_destructive` / `is_reversible` / `safety_tier`. - [ ] 4.4 Encode the decision rules (subtype → kind → tier) and the Opus-escalation rule (low confidence on stale-vs-bloat or destructive-vs-generative). - [ ] 4.5 Encode failure handling: validation fail (exit 1) → do not write, map violations to entries, re-prompt or drop and re-validate; usage error (exit 2) → stop; empty shortlist → write empty-`entries` report + stamp; malformed proposal → re-prompt. Record `--scope` / `--category` in the report header. ## 5. Classifier goldens + hermetic harness — after Groups 2, 4; HUMAN-GATED (model: Sonnet) - [ ] 5.1 Create 3–5 static fixture trees under `examples/golden/classifier/-/` (`input/` with stable sha256s, `expected.json`, optional `notes.md`), each mapping a subtype to a **distinct** `exact_edit.kind`: `orphaned`→`delete-range`/`confirm`, `superseded`→`move-to-archive`/`auto`, `completed-in-place`→`insert-frontmatter`/`auto`, `duplicated`→`dedupe`/`auto`, `distill`→generative/`confirm`. - [ ] 5.2 Implement `tests/test_classifier_golden.py` **hermetically** (no live model call): (1) `scanner.py` on `input/` emits the expected signals on the right paths; (2) `validate_report.py` on each `expected.json` → exit 0; (3) stable-field match against a captured/committed check output (`category.class`, `category.subtype`, `op_type`, derived `safety_tier`, `exact_edit.kind`). Op-prose and exact anchor line numbers are advisory (flag, do not hard-fail). - [ ] 5.3 Document the **separate** live model-classification regression harness (manually/agent-invoked, NOT part of the unit suite). - [ ] 5.4 Update `examples/golden/CONTEXT.md` to distinguish classifier goldens from the schema-shape fixtures. ## 6. CONTEXT.md updates — last (model: Haiku) - [ ] 6.1 Author `CONTEXT.md` for `commands/` and `skills/` (progressive disclosure). - [ ] 6.2 Update `scripts/CONTEXT.md` to add `report_builder.py` (its role as the deterministic finalize pass and the symbols it imports). ## 7. Validation - [ ] 7.1 Run `openspec validate add-check --strict` and confirm it passes.