8.0 KiB
Spec: doc-clean (delta)
MODIFIED Requirements
Requirement: Safety-Tier Gating Before Any Mutation
The clean skill SHALL partition report entries by safety tier (read from the
report — never recomputed) into auto entries (applied without prompt) and
confirm entries (escalated before any mutation). It SHALL present all
confirm-tier entries as a single batch-confirm list showing path, category,
op, token count, and rationale with per-entry opt-out, visually
distinguishing irreversible delete-range, delete, and
extract-then-delete entries from reversible entries. The approved set
SHALL be all auto entries plus any user-approved confirm entries. The
gate SHALL run identically under sweep — the /os-doc-hygiene:sweep
convenience path SHALL NOT bypass invariant #7. Regardless of the tier
recorded in the report, any delete or extract-then-delete entry SHALL be
re-verified at apply time per the lifecycle-deletion tier matrix (tracked
- clean required for auto) before being applied without a prompt.
Scenario: auto entries apply without prompt
- WHEN the report contains only auto-tier entries (move-to-archive, insert-frontmatter, replace-text, dedupe)
- THEN the clean skill applies them without presenting a confirm prompt
Scenario: confirm entries escalate before any mutation
- WHEN the report contains confirm-tier entries (delete-range, delete, extract-then-delete, or any generative op)
- THEN the clean skill presents a batch-confirm list before any file is modified, and applies only user-approved entries
Scenario: per-entry opt-out is respected
- WHEN the user approves some confirm entries and opts out of others
- THEN the skill applies the approved entries and skips the opted-out entries
Scenario: sweep does not bypass the gate
- WHEN the user runs /os-doc-hygiene:sweep and the report contains confirm-tier entries
- THEN the confirm gate runs identically to a standalone /os-doc-hygiene:clean
Scenario: A report-tier auto delete is downgraded if runtime state has changed
- WHEN a
deleteentry was tieredautoin the report but the applier's runtime check finds the file is now dirty or untracked - THEN the applier does not apply it silently; it is skipped and reported for re-analysis, never trusted from the cached tier
Requirement: Git-Safe Single Commit
The clean skill SHALL produce exactly one git commit per run. Before any
mutation it SHALL resolve the project root via StateStore, run
git status --porcelain, and if the tree is dirty, SHALL automatically
create a WIP checkpoint commit of the user's work before proceeding, so the
cleanup commit remains exactly one. The cleanup commit SHALL be created via
git-context commit-apply --message-stdin with a generated message
summarizing auto/confirmed/skipped counts and op breakdown, including
lifecycle delete/extract-then-delete counts when present. Staging SHALL be
precise: for non-move, non-delete ops the skill calls git add <staged_paths> from the applier result; for move-to-archive the applier
calls git mv (staging both sides) and the skill SHALL NOT git add the
destination path again; for delete and the delete half of
extract-then-delete the applier calls git rm (staging the removal
itself) and the skill SHALL NOT separately stage the removed path. The skill
SHALL NEVER use git add -A or git add .. If a hard failure occurs
(applier exit 2, git mv/git rm fail, or write error), the skill SHALL
roll back via git restore/reset to the pre-run baseline and abort with a
structured error. Partial success (some file batches guard-skipped) SHALL
NOT trigger rollback — the skill SHALL commit what applied and report
skipped files. Untracked candidate docs SHALL be skipped and reported
(tracked-files-only) except where a lifecycle rule explicitly escalates an
untracked delete to confirm and the user approves it. last_clean SHALL be
stamped to the commit instant, not the run-start instant.
Scenario: Clean tree produces exactly one commit
- WHEN the user runs /os-doc-hygiene:clean with a clean git tree
- THEN the run produces exactly one git commit containing all applied edits, including any lifecycle deletes
Scenario: Dirty tree gets a WIP checkpoint then one cleanup commit
- WHEN the user runs /os-doc-hygiene:clean with unstaged changes in the working tree
- THEN the skill auto-creates a WIP checkpoint commit of the user's work, then produces exactly one cleanup commit — two commits total, cleanup still exactly one
Scenario: All-skipped produces zero commits
- WHEN all entries are guard-skipped (every file changed since check)
- THEN the skill produces zero commits and reports all files as skipped with re-analysis recommended
Scenario: Hard failure triggers rollback
- WHEN a write error, applier exit 2, or a
git rmfailure occurs mid-run - THEN the skill rolls back to the pre-run baseline and aborts with a structured error; no partial commit is created
Scenario: Partial success commits what applied
- WHEN some file batches are guard-skipped (applier exit 1) and others succeed
- THEN the skill commits the applied edits and reports the skipped files, without rolling back the applied changes
Scenario: move-to-archive is not double-staged
- WHEN the applier stages a move-to-archive via git mv (both source and dest)
- THEN the skill does not call git add on the destination path again
Scenario: A lifecycle delete is not double-staged
- WHEN the applier stages a
deleteviagit rm - THEN the skill does not separately call
git addor any other staging command on the removed path
ADDED Requirements
Requirement: Applier Applies Delete and Extract-Then-Delete Under the Tier Matrix
The patch applier SHALL support two new op kinds, delete and
extract-then-delete. For both, immediately before applying, it SHALL
re-run git ls-files <path> and a dirty check against that specific path —
never trusting the cached report tier or rule claim — and SHALL apply the
tier matrix from the lifecycle-deletion spec to decide whether the entry
may proceed as auto or must be treated as confirm (already gated
upstream by the clean skill). delete SHALL perform a git rm (recursive
for a directory-rule aggregate entry) staged into the run's single hygiene
commit. extract-then-delete SHALL first complete its generative extraction
step (repo-durable via the existing live-read Sonnet distillation path
writing into an ADR/CLAUDE.md/docs target, or cross-repo via
/os-vault:write) and SHALL only perform the git rm once extraction has
succeeded; both steps SHALL land in the same single hygiene commit, or, on
extraction failure, neither SHALL be applied for that entry (skip, not a
run-level hard failure, unless the failure matches an existing hard-failure
trigger).
Scenario: delete performs a true git rm at apply time
- WHEN the applier applies a
deleteentry - THEN it re-verifies tracked/clean status via
git ls-filesand a dirty check, then performs agit rmstaged into the single hygiene commit
Scenario: extract-then-delete only deletes after extraction succeeds
- WHEN the applier applies an
extract-then-deleteentry - THEN it completes the extraction write (ADR/CLAUDE.md/docs or vault) first, and performs the
git rmonly after that write succeeds
Scenario: A failed extraction skips the delete for that entry
- WHEN the extraction step of an
extract-then-deleteentry fails - THEN the delete is not applied for that entry, the entry is reported as skipped, and the run is not treated as a hard failure unless the failure matches an existing hard-failure trigger (applier exit 2, write error)
Scenario: Directory-rule aggregate delete removes the whole directory
- WHEN the applier applies a
deleteentry whose path is a directory-rule aggregate entry - THEN it performs a recursive
git rmremoving the entire matched directory in one operation staged into the single hygiene commit