8.7 KiB
8.7 KiB
Tasks: Add Clean
Execution shape: T1 and T2 are already DONE (patch_applier.py + 263 tests pass). T3 (
workflows/distill.md) has no upstream dependency among the remaining tasks and can start immediately. T4 (hygiene-cleanSKILL.md, git-safety inline) is sequential after T3. T5 (integration tests) is sequential after T4. T6 (commands/hygiene.mdupdate) and T7 (CONTEXT.md + CLAUDE.md) are independent of T3–T5 and can run in parallel with any group. Model routing is annotated per task.
1. patch_applier.py — DONE (model: Sonnet)
- 1.1 Implement
scripts/patch_applier.pyas a standalone, model-free applier.PatchApplier(project_root, fs, git)withapply_indexed([(orig_index, entry)]) → {applied, skipped, failed, staged_paths}. CLI:python patch_applier.py --report <path> --apply-indices 0,2,3. Exit 0 all / 1 partial / 2 usage. - 1.2 Implement per-file transaction: read bytes once, verify sha256 for every
anchored entry, skip whole file on mismatch (
content-changed-since-check), apply anchored edits descending byanchor.start_line, applyinsert-frontmatterlast, write once, stage once. - 1.3 Implement
insert-frontmatterre-derivation at apply time: re-read file, parse frontmatter; key+target value → idempotent no-op; key+conflict →frontmatter-key-conflictskip; key absent → insert (create---block if needed) as last in-memory step. - 1.4 Implement incompatible-ops detection: per file, skip whole file
(
incompatible-ops-on-file) ifmove-to-archiveco-occurs with any other op, or if anchor ranges overlap. Never compose in v1. - 1.5 Implement all KIND_TABLE kinds:
delete-range,move-to-archive(git mv, mkdir dest,auto),insert-frontmatter(auto),replace-text(first occurrence in span,auto),dedupe(auto).(is_destructive, is_reversible)from KIND_TABLE, not entry. - 1.6 Handle edge cases:
move-to-archivesource-gone+dest-present → idempotent success;replace-text/insert-frontmatteralready applied → no-op success; non-UTF-8 file →non-utf8-contentskip; generative/unknown kind → rejected/skip.
2. patch_applier.py tests — DONE (model: Sonnet)
- 2.1 Write unit tests for per-file transaction: sha256 mismatch skips entire
batch; clean match applies in descending-anchor order;
insert-frontmatterapplied last; write-once / stage-once assertions. - 2.2 Write unit tests for
insert-frontmatterre-derivation: idempotent no-op, key-conflict skip, key-absent insert (with and without existing---block). - 2.3 Write unit tests for incompatible-ops detection:
move-to-archive+other → skip; overlapping anchors → skip; non-conflicting entries → proceed. - 2.4 Write unit tests for every KIND_TABLE kind: delete-range, move-to-archive (git mv both sides, mkdir dest), replace-text (first occ in span), dedupe, insert-frontmatter. Assert exit codes (0/1/2).
- 2.5 Confirm 263 tests pass:
pytest tests/green.
3. workflows/distill.md — generative Sonnet workflow (model: Sonnet)
- 3.1 Author
workflows/distill.mdas the Sonnet generative workflow (LOOP-GUARD: the skill points the subagent at this workflow doc, not SKILL.md, to avoid recursion). Document the LOOP-GUARD pattern in the workflow header. - 3.2 Specify the subagent inputs: live file contents (read at dispatch time, not
from report cache), the report entry (
op,category,signals,detail). - 3.3 Specify the output contract:
distill→ condensed prose replacing the span;split→ new-primary prose + archived-section to append or move; skill writes and stages the result. - 3.4 Specify failure handling: if Sonnet returns malformed output, log and skip the entry (do not abort the run).
4. skills/hygiene-clean/SKILL.md (model: Sonnet)
- 4.1 Author
skills/hygiene-clean/SKILL.mdwith frontmatter mirroring thehygiene-checkskill style. Precondition:CLAUDE_PLUGIN_ROOTis set; if not, halt with a clear error. - 4.2 Implement step 1: load report via
StateStore.read_report; if none, tell user to run/hygiene checkand stop. - 4.3 Implement step 2: re-validate loaded report via
validate_report.py; if invalid, stop. - 4.4 Implement step 3: apply scope/category filter to entries (entry-stage, same as check).
- 4.5 Implement step 4: partition entries into auto+deterministic,
confirm+deterministic (
delete-range), and generative (alwaysconfirm). - 4.6 Implement step 5 (GATE FIRST): present batch-confirm list for confirm-tier
entries — path · category · op · tokens · why; per-entry opt-out; visually
distinguish irreversible
delete-rangefrom reversible auto ops. Approved set = all auto + approved confirm. - 4.7 Implement step 6: git preflight — resolve project root;
git status --porcelain; clean → baseline = HEAD; dirty → auto-create WIP checkpoint commit (user work only), baseline = that checkpoint. - 4.8 Implement step 7: apply deterministic approved entries via
python patch_applier.py --report <path> --apply-indices <list>; capture JSON result ({applied, skipped, failed, staged_paths}). - 4.9 Implement step 8: for each approved generative entry — confirm file exists;
read live file contents; dispatch Sonnet subagent →
workflows/distill.md(LOOP-GUARD); receive new content; write + stage. - 4.10 Implement step 9: staging —
git add <staged_paths>for non-move ops; DO NOTgit addmove-to-archivedest (applier already staged viagit mv). NEVERgit add -Aorgit add .. - 4.11 Implement step 10: single commit via
git-context commit-apply --message-stdinwith generated message:docs: hygiene cleanup (N edits across M files)\n\nAuto: ...\nConfirmed: ...\nSkipped (re-analysis recommended): ...No Co-Authored-By, no AI attribution, no emoji, no trailers. - 4.12 Implement step 11: stamp
last_cleanto commit instant viaStateStore.set_last_clean(commit_instant). - 4.13 Implement step 12: surface summary — applied / skipped (with re-analysis
note) / confirmed counts, commit SHA, note about checking for new orphans
after
move-to-archive. - 4.14 Implement failure handling: guard mismatch → skip-file-report-continue;
applier exit 2 /
git mvfail / write error →git restore/resetto baseline, abort with structured error; partial success (applier exit 1) → NOT rollback, commit what applied; zero in-scope → no-op report, no commit.
5. Integration tests (model: Sonnet)
- 5.1 Implement
tests/test_clean_integration.pyusing a fixture git repo. Test invariant #5 GAPs: (a) dirty-tree → WIP checkpoint + exactly one cleanup commit (two total); (b) clean-tree → exactly one cleanup commit; (c) all-guard-skipped → zero commits, no rollback noise. - 5.2 Test invariant #7 sweep-gating GAP: when entries include
confirm-tier ops and user is running under/hygiene sweep, the confirm gate still fires identically (not bypassed). - 5.3 Test
move-to-archiveprecise staging: applier stages both sides viagit mv; skill does not callgit addon the dest;git diff --cachedshows the rename cleanly. - 5.4 Test rollback path: simulate applier exit 2 mid-run; assert tree is restored to baseline and no partial commit exists.
- 5.5 Confirm all new integration tests pass alongside the 263 existing unit tests.
6. commands/hygiene.md — clean/sweep routing (model: Haiku)
- 6.1 Replace the "not yet implemented (Phase 4)" stubs for
cleanandsweepincommands/hygiene.mdwith live routing to thehygiene-cleanskill, passing--scopeand--categoryflags through. - 6.2 Wire
/hygiene sweepas command-level check-then-clean sequencing: invokehygiene-checkskill, thenhygiene-cleanskill, passing shared flags to both. No third skill; no double-commit.
7. CONTEXT.md updates and CLAUDE.md fix (model: Haiku)
- 7.1 Update
scripts/CONTEXT.mdto addpatch_applier.py— its role as the deterministic in-memory applier, the transaction model, and its exit codes. - 7.2 Author
skills/hygiene-clean/CONTEXT.md(progressive disclosure index for the clean skill directory). - 7.3 Update
CLAUDE.mdbuild-order step 4 note: mark the deferredinsert-frontmatterhole as RESOLVED — the applier re-derives frontmatter freshness at apply time (idempotent key-absence check) instead of trusting a cached hash.