openspec 1.5.0.
validate checks a MODIFIED delta's SHAPE but never that its ### Requirement: header matches anything in the target spec. A header typo, or a requirement renamed upstream after the delta was written, passes validation and is then applied by archive as an ADDITION — so the original requirement survives alongside its replacement, and the spec ends up holding two contradictory SHALL statements with nothing recording which one won. Silent, and permanent once archived.
REPRO
-
openspec/specs/example-cap/spec.md:
Requirements
Requirement: Widgets are validated
The system SHALL validate widgets.
Scenario: A widget is validated
- WHEN a widget arrives
- THEN it is validated
-
openspec new change fix-widgets
-
openspec/changes/fix-widgets/specs/example-cap/spec.md:
MODIFIED Requirements
Requirement: Widgets are validated thoroughly
The system SHALL validate widgets thoroughly.
Scenario: A widget is validated
- WHEN a widget arrives
- THEN it is validated thoroughly
(header deliberately does not match the baseline)
-
openspec validate fix-widgets -> "Change 'fix-widgets' is valid"
openspec validate fix-widgets --strict -> "Change 'fix-widgets' is valid"
openspec archive fix-widgets -y -> applied as an addition
RESULT: example-cap/spec.md now contains both "Widgets are validated" and
"Widgets are validated thoroughly".
EXPECTED: validate fails, naming the header that matches nothing. The intent
already exists in the docs — openspec instructions specs says "Common pitfall:
Using MODIFIED with partial content loses detail at archive time" and "Ensure
header text matches exactly" — there is just no check behind it.
Two adjacent cases worth the same treatment: a MODIFIED block byte-identical to
its baseline (a copy-paste that forgot the edit, archives as a no-op but reads as
a decision), and an ADDED header that collides with an existing requirement,
which reaches the same duplicate end state from the other direction.
SECONDARY REQUEST
openspec show <change> --json --deltas-only omits the requirement header:
deltas[].requirement has only text and scenarios, and description is
"Modify requirement: ". Since header matching is what MODIFIED depends on,
external tooling cannot match a delta to its baseline requirement from the JSON
and has to re-parse the markdown. Exposing the header/name would let people build
delta review on the CLI's own parser instead of a second implementation.
CONTEXT
Hit this while reviewing a change with a MODIFIED delta. A delta file is a new
file, so every diff view renders it all-added and the modification is invisible;
reviewers cannot see which words moved without reconstructing the before-state by
hand. A --diff-style view over deltas plus the validation above would cover
both problems. Happy to contribute a PR if the approach sounds right.
Unrelated, found while reporting this: openspec feedback "<msg>" --body "<text>" fails with could not add label: 'feedback' not found and creates nothing. This repo's labels are bug / documentation / duplicate / enhancement / …, with no feedback label, so the CLI's own feedback path is unusable. Hence the manual issue.
openspec 1.5.0.
validatechecks a MODIFIED delta's SHAPE but never that its### Requirement:header matches anything in the target spec. A header typo, or a requirement renamed upstream after the delta was written, passes validation and is then applied byarchiveas an ADDITION — so the original requirement survives alongside its replacement, and the spec ends up holding two contradictory SHALL statements with nothing recording which one won. Silent, and permanent once archived.REPRO
openspec/specs/example-cap/spec.md:
Requirements
Requirement: Widgets are validated
The system SHALL validate widgets.
Scenario: A widget is validated
openspec new change fix-widgets
openspec/changes/fix-widgets/specs/example-cap/spec.md:
MODIFIED Requirements
Requirement: Widgets are validated thoroughly
The system SHALL validate widgets thoroughly.
Scenario: A widget is validated
(header deliberately does not match the baseline)
openspec validate fix-widgets -> "Change 'fix-widgets' is valid"
openspec validate fix-widgets --strict -> "Change 'fix-widgets' is valid"
openspec archive fix-widgets -y -> applied as an addition
RESULT: example-cap/spec.md now contains both "Widgets are validated" and
"Widgets are validated thoroughly".
EXPECTED: validate fails, naming the header that matches nothing. The intent
already exists in the docs —
openspec instructions specssays "Common pitfall:Using MODIFIED with partial content loses detail at archive time" and "Ensure
header text matches exactly" — there is just no check behind it.
Two adjacent cases worth the same treatment: a MODIFIED block byte-identical to
its baseline (a copy-paste that forgot the edit, archives as a no-op but reads as
a decision), and an ADDED header that collides with an existing requirement,
which reaches the same duplicate end state from the other direction.
SECONDARY REQUEST
openspec show <change> --json --deltas-onlyomits the requirement header:deltas[].requirement has only
textandscenarios, anddescriptionis"Modify requirement: ". Since header matching is what MODIFIED depends on,
external tooling cannot match a delta to its baseline requirement from the JSON
and has to re-parse the markdown. Exposing the header/name would let people build
delta review on the CLI's own parser instead of a second implementation.
CONTEXT
Hit this while reviewing a change with a MODIFIED delta. A delta file is a new
file, so every diff view renders it all-added and the modification is invisible;
reviewers cannot see which words moved without reconstructing the before-state by
hand. A
--diff-style view over deltas plus the validation above would coverboth problems. Happy to contribute a PR if the approach sounds right.
Unrelated, found while reporting this:
openspec feedback "<msg>" --body "<text>"fails withcould not add label: 'feedback' not foundand creates nothing. This repo's labels are bug / documentation / duplicate / enhancement / …, with nofeedbacklabel, so the CLI's own feedback path is unusable. Hence the manual issue.