cc-os/plugins/os-doc-hygiene/openspec/changes/archive/2026-06-24-add-check/tasks.md

112 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 <glob-or-path>] [--category <class|subtype>]`
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 35 static fixture trees under
`examples/golden/classifier/<n>-<name>/` (`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.