cc-os/plugins/os-doc-hygiene/openspec/changes/calibrate-assessment-inventory/specs/doc-clean/spec.md

67 lines
4.1 KiB
Markdown
Raw Normal View History

# Delta: doc-clean (calibrate-assessment-inventory)
## MODIFIED 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). When the extraction destination is the vault (the content
physically leaves the repo), the op SHALL additionally append a pointer
entry to the deleted file's per-directory `extracted.md` index (creating the
file if absent), in the same atomic sequence — distill → `/os-vault:write`
append the pointer line → `git rm` — all staged into the same single hygiene
commit, so there is no window where the doc is gone but undiscoverable. The
pointer entry SHALL name the vault note, state why a future reader would
follow it, and record the source filename and date. Repo-durable extraction
targets (ADR, CLAUDE.md, docs) SHALL NOT produce an index entry — they are
already discoverable in-repo.
#### Scenario: delete performs a true git rm at apply time
- **WHEN** the applier applies a `delete` entry
- **THEN** it re-verifies tracked/clean status via `git ls-files` and a dirty check, then performs a `git rm` staged into the single hygiene commit
#### Scenario: extract-then-delete only deletes after extraction succeeds
- **WHEN** the applier applies an `extract-then-delete` entry
- **THEN** it completes the extraction write (ADR/CLAUDE.md/docs or vault) first, and performs the `git rm` only after that write succeeds
#### Scenario: A failed extraction skips the delete for that entry
- **WHEN** the extraction step of an `extract-then-delete` entry 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 `delete` entry whose path is a directory-rule aggregate entry
- **THEN** it performs a recursive `git rm` removing the entire matched directory in one operation staged into the single hygiene commit
#### Scenario: A vault extraction leaves an extracted.md pointer in the same commit
- **WHEN** an `extract-then-delete` entry extracts to the vault via `/os-vault:write`
- **THEN** a pointer entry naming the vault note, the reason to follow it, the source filename, and the date is appended to the deleted file's directory `extracted.md` (created if absent), and the append, the deletion, and the index file are all staged into the same single hygiene commit
#### Scenario: A repo-durable extraction leaves no index entry
- **WHEN** an `extract-then-delete` entry extracts into an ADR, CLAUDE.md, or docs target inside the repo
- **THEN** no `extracted.md` entry is written — the residue is already discoverable in-repo
#### Scenario: A failed pointer append skips the delete
- **WHEN** the vault write succeeds but appending the `extracted.md` pointer fails
- **THEN** the `git rm` is not applied for that entry and it is reported as skipped, preserving the invariant that a doc is never gone but undiscoverable