Skip to content

Repeated delta section headers silently discard requirements #1801

Description

@dwin-gharibi

Description

When a change's delta file writes the same delta header more than once — for
example two ## ADDED Requirements sections — only one of them is applied. The
requirements under the other are discarded with no error, no warning, and no
INFO note. openspec validate reports the change valid, openspec archive
exits 0 with "Specs updated successfully", and the change is moved into
openspec/changes/archive/, so the active change is gone while the live spec no
longer matches what was authored and reviewed.

The same happens when two copies differ only in casing
(## ADDED Requirements and ## Added Requirements), except the opposite copy
is the one dropped.

Reproduction

openspec init --tools claude
openspec new change add-billing

openspec/changes/add-billing/specs/billing/spec.md:

## ADDED Requirements
### Requirement: Invoice Generation
The system SHALL generate an invoice for every completed billing period.

#### Scenario: Period closes
- **WHEN** a billing period closes
- **THEN** an invoice is generated for the account

## ADDED Requirements
### Requirement: Dunning Notices
The system SHALL send a dunning notice when an invoice is 7 days overdue.

#### Scenario: Invoice overdue
- **WHEN** an invoice is 7 days overdue
- **THEN** a dunning notice is sent to the account owner
openspec validate add-billing --json   # "valid": true, "issues": []
openspec archive add-billing --yes     # exit 0, "+ 1 added"

Expected

Either both ## ADDED Requirements sections are merged, or the change is
rejected with an error naming the duplicated header. A delta operation the
author wrote should never be discarded without being reported.

Actual

Invoice Generation and its scenario are absent from
openspec/specs/billing/spec.md. Archive printed Totals: + 1, ~ 0, - 0, → 0
for a delta that declared two additions, and reported success.

The loss is not visible from any command:
openspec show add-billing --json --deltas-only — the inspection command
OpenSpec's own "no deltas found" error recommends — reports "deltaCount": 1
and lists only the surviving requirement.

Affects all four operations:

Delta shape archive totals Result
## ADDED Requirements ×2 + 1 added first ADDED section dropped
## ADDED Requirements + ## Added Requirements + 1 added last ADDED section dropped
## MODIFIED Requirements ×2 ~ 1 modified a modification never applied; spec keeps stale text
## REMOVED Requirements ×2 - 1 removed a removal never applied; requirement survives

Impact

Silent loss of specification content in the primary write path, with a success
exit code. Delta files are the artifact OpenSpec asks an AI agent to author, and
emitting a delta header twice is an ordinary model output shape. A delta that
documents OpenSpec's own syntax in a fenced example can also produce the
duplicate without any authoring mistake, because an inner ``` closes the outer
fence and the ## ADDED Requirements line inside the example becomes a real
second section.

Environment

  • OpenSpec 1.12.0 (reproduced on the published npm package and on a build of
    main @ e062b95)
  • Node v22.23.2, Linux
  • Also reproduced in a project created entirely by openspec init +
    openspec new change, with the baseline main spec produced by archiving a
    first change

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions