Skip to content

Commit 23772fd

Browse files
committed
docs: a spec delta replaces a requirement, it does not patch it
A `## MODIFIED Requirements` block must restate the requirement in full, including the scenarios it is not changing. `openspec archive` rewrites the standing requirement to exactly what the delta contains, so anything omitted is deleted from the spec with nothing reporting it. Found on this branch's own change, which called itself strictly additive and would have dropped two normative scenarios about parameter-parsing order and whole-string signature comparison. `openspec validate --strict` passes either way, which is why the section carries the archive-and-diff procedure that found it rather than only the rule. Also records that the preserve-on-sync guidance in `openspec-sync-specs` does not reach `openspec archive`, so a delta that omits a scenario and a note saying the omission is deliberate produce the same result.
1 parent abb551f commit 23772fd

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

‎CLAUDE.md‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,37 @@ This happens when the **parent** PR is merged with `--delete-branch`: deleting t
270270
- **No OpenSpec archive check at all.** An unarchived change directory is expected on a pull request AND on `main` while a forward-merging stack drains. Neither is a failure, and nothing reports it. Archive the change on the tip slice; a replacement that measures abandoned work rather than in-progress work is a separate piece of design.
271271
- **Clean up local branches** once the stack lands: `git fetch --prune`, then delete the branches that merged (`git branch --merged main`).
272272

273+
## A spec delta REPLACES a requirement, it does not patch it
274+
275+
**A `## MODIFIED Requirements` block must restate the requirement in full, including every scenario you are not changing.** `openspec archive` rewrites the standing requirement to exactly what the delta contains. Anything you leave out is deleted from the spec, silently, with nothing reporting it.
276+
277+
Measured on `signature-coverage-statement`, whose proposal described itself as strictly additive and whose delta added one scenario while carrying one of the three that already existed:
278+
279+
```
280+
BEFORE AFTER ARCHIVE
281+
Envelope is emitted for algoVersion 1 -> Envelope is emitted for algoVersion 1
282+
Version is read before parameters -> (gone)
283+
Signatures compare as whole strings -> (gone)
284+
A v1 signature covers the engine rule file
285+
```
286+
287+
Two normative scenarios, about parameter-parsing order and whole-string comparison, would have left the spec as a side effect of documenting something unrelated.
288+
289+
**Do not rely on a preserve-on-sync guardrail.** `openspec-sync-specs` advises retaining content a delta does not mention, and that advice does not reach `openspec archive`, which is what actually runs. A delta that omits a scenario, and a comment saying the omission is deliberate, produce the same result: the scenario is gone.
290+
291+
**Check it the way it was found**, since nothing else will. `openspec validate --strict` passes on a delta that drops scenarios:
292+
293+
```bash
294+
# commit everything first: the revert below is a hard reset
295+
pnpm openspec archive <change-name> -y
296+
grep -n "^#### Scenario" openspec/specs/<capability>/spec.md
297+
git reset --hard HEAD && git clean -fd openspec/
298+
```
299+
300+
Every scenario present before must still be present, plus whatever you added. Two cautions from doing it: commit first, and restore uncommitted edits by copying files **over** the change directory rather than copying the directory onto itself, which nests a stray copy inside it.
301+
302+
**The paranoia is warranted because the failure is invisible.** Nothing fails, no check reports it, and the requirement still reads coherently afterwards. It just no longer says the thing it used to say.
303+
273304
## OpenSpec Apply
274305

275306
When implementing changes via `/opsx:apply`, **pause after each task group** for user review before continuing. Commit between groups and wait for confirmation.

0 commit comments

Comments
 (0)