4.9 KiB
Adopt Delta-Based Changes for Specifications
Why
The current approach of storing complete future states in change proposals creates a poor review experience. When reviewing changes on GitHub, reviewers see entire spec files (often 100+ lines) as "added" in green, making it impossible to identify what actually changed. With the recent structured format adoption, we now have clear section boundaries that enable a better approach: storing only additions and modifications.
What Changes
Store only the requirements that actually change, not complete future states:
- ADDED Requirements: New capabilities being introduced
- MODIFIED Requirements: Existing requirements being changed (must match current header)
- REMOVED Requirements: Deprecated capabilities
- RENAMED Requirements: Explicit header changes (e.g.,
FROM: Old Name→TO: New Name)
The archive command will programmatically apply these deltas using normalized header matching (trim leading/trailing whitespace) instead of manually copying entire files.
Impact
Affected specs: openspec-conventions, cli-archive, cli-diff
Benefits:
- GitHub diffs show only actual changes (25 lines instead of 150+)
- Reviewers immediately see what's being added, modified, or removed
- Conflicts are more apparent when two changes modify the same requirement
- Archive command can programmatically apply changes
Format: Delta format only - all changes must use ADDED/MODIFIED/REMOVED sections.
Example
Instead of storing a 150-line complete future spec, store only:
# User Authentication - Changes
## ADDED Requirements
### Requirement: OAuth Support
Users SHALL authenticate via OAuth providers including Google and GitHub.
#### Scenario: OAuth login flow
- **WHEN** user selects OAuth provider
- **THEN** redirect to provider authorization
- **AND** exchange authorization code for tokens
## MODIFIED Requirements
### Requirement: Session Management
Sessions SHALL expire after 30 minutes of inactivity.
#### Scenario: Inactive session timeout
- **WHEN** no activity for 30 minutes ← (was 60 minutes)
- **THEN** invalidate session token
- **AND** require re-authentication
## RENAMED Requirements
- FROM: `### Requirement: Basic Authentication`
- TO: `### Requirement: Email Authentication`
This makes reviews focused and changes explicit.
Conflict Resolution
Git naturally detects conflicts when two changes modify the same requirement header. This is actually better than full-state storage where Git might silently merge incompatible changes.
Decisions and Product Guidelines
To keep the archive flow lean and predictable, the following decisions apply:
-
New spec creation: When a target spec does not exist, auto-generate a minimal skeleton and insert ADDED requirements only. Skeleton format:
# [Spec Name] Specification## Purposewith placeholder: "TBD — created by archiving change [change-name]. Update Purpose after archive."## Requirements- If a non-existent spec includes MODIFIED/REMOVED/RENAMED, abort with guidance to create via ADDED-only first.
-
Requirement identification: Match requirements by exact header
### Requirement: [Name]with trim-only normalization and case-sensitive comparison. Use a requirement-block extractor that preserves the exact header and captures full content (including scenarios) for both main specs and delta files. -
Application order and atomicity: Apply deltas in order RENAMED → REMOVED → MODIFIED → ADDED. Validate all operations first, apply in-memory, and write each spec once. On any validation failure, abort without writing partial results. An aggregated totals line is displayed across all specs:
Totals: + A, ~ M, - R, → N. -
Validation matrix: Enforce that MODIFIED/REMOVED exist; ADDED do not exist; RENAMED FROM exists and TO does not; no duplicates after all operations; and no cross-section conflicts (e.g., same item in MODIFIED and REMOVED). When a rename and modify apply to the same item, MODIFIED must reference the NEW header.
-
Idempotency: Keep v1 simple. Abort on precondition failures (e.g., ADDED already exists) with clear errors. Do not implement no-op detection in v1.
-
Output and UX: For each spec, display operation counts using standard symbols
+ ~ - →. Optionally include a short aggregated totals line at the end. Keep messages concise and actionable. -
Error messaging: Standardize messages as
[spec] [operation] failed for header "### Requirement: X" — reason. On abort, explicitly state:Aborted. No files were changed. -
Subsections: Any subsections under a requirement (e.g.,
#### Scenario: ...) are preserved verbatim during parsing and application. -
Backward compatibility: Reject full future-state spec copies for existing specs with guidance to convert to deltas. Allow brand-new specs to be created via ADDED-only deltas using the skeleton above.
-
Dry-run: Deferred for v1 to keep scope minimal.