Skip to content

validate accepts a MODIFIED requirement whose header matches no requirement in the target spec #1918

Description

@rafica11

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

  1. 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
  2. openspec new change fix-widgets

  3. 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)

  4. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    design-reviewNeeds product/design decision

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions