Skip to content

feat: capture delta baselines (content hash + git ref) on validation #22

@lsmonki

Description

@lsmonki

Problem

Deltas are authored by an LLM against the current state of a spec. Between delta creation and archive, another change may be archived that modifies the same spec. Today this conflict is only discovered at apply() time during ArchiveChange, with no context about what changed or when.

There is no mechanism to:

  1. Detect drift — know that the spec base changed since the delta was authored
  2. Diagnose the change — see what the spec looked like when the delta was designed vs now
  3. Enable safe rollback — restore a spec to its pre-delta state if a change is discarded after sync (see feat: delta visibility before archive — materialized view, preview, and conditional sync #21 Level 3)

Proposal

When a delta passes validation in ValidateArtifacts, persist the baselines of all affected specs in the change manifest. Keyed by fully-qualified spec ID (workspace:capabilityPath) + artifact filename.

Domain layer (always present)

The contentHash is a domain concern — it enables drift detection regardless of VCS or infrastructure:

deltaBaselines:
  "default:auth/login":
    "spec.md":
      contentHash: "sha256:abc..."
  "default:auth/register":
    "spec.md":
      contentHash: "sha256:def..."
  • contentHash: SHA-256 of the base spec content at validation time. This is the drift detector — if the current spec hash differs from this value, the base has changed.

Restoration strategies (optional)

When drift is detected or rollback is needed, specd needs access to the original spec content. Two strategies are considered — they are not mutually exclusive:

Strategy A: VCS reference

If a VCS adapter is available, it can enrich baselines with a restore reference. For git, this would be the commit hash:

deltaBaselines:
  "default:auth/login":
    "spec.md":
      contentHash: "sha256:abc..."
      vcsRef: "8679b77"
  • vcsRef: an opaque reference that the VCS adapter can use to recover the original file (e.g. git show <ref>:<path>). Enables restoration, diffing, and delta rewrite guidance.
  • This field is optional — specd must function without it. If absent, drift detection still works (via contentHash) but restoration is not available.
  • The domain does not interpret this value — it's passed through to the VCS adapter when restoration is needed.

This keeps the domain VCS-agnostic. Teams using git get restore capabilities; teams using other VCS or no VCS still get drift detection and safe merge guards.

Strategy B: Cached original content

Cache the original spec content within the change directory at validation time. This guarantees restoration is always available, regardless of VCS.

The exact storage mechanism is TBD (e.g. a baselines/ directory within the change, an embedded field in the manifest, a content-addressable store). Key considerations:

  • Pros: works without VCS, self-contained change directory, no external dependencies for restoration
  • Cons: duplicates content (specs can be large), increases change directory size
  • Open question: what format? Full file copy, compressed, or content-addressable by hash?

Strategies A and B can coexist — use vcsRef when available for lightweight diffing, fall back to cached content when VCS is absent or the ref is no longer reachable.

Capture timing

Not when the LLM writes the delta (it may edit it multiple times), but when it passes validation in ValidateArtifacts. This use case already performs an internal merge to validate the delta — persisting the hashes is a side-effect of a successful validation pass.

If the delta is edited and re-validated, baselines are overwritten with fresh values (and cached content, if Strategy B is used).

Use cases

Drift detection in ArchiveChange

Before applying deltas, ArchiveChange can compare contentHash against the current spec hash:

  • Match → safe to apply
  • Mismatch → warn or block, with actionable context. If a restoration strategy is available, point the user to the original state for comparison.

Today this conflict surfaces as a cryptic DeltaApplicationError (selector not found, wrong node, etc.) with no explanation of why.

Safe merge in CompileContext (#21 Level 1)

If #21 Level 1 is implemented (materialized view in CompileContext), baselines enable a safety check before merging:

  • Hash matches → merge is safe, show materialized view
  • Hash differs → fall back to outline with a warning

Without this check, CompileContext could silently produce an incorrect merged view.

Rollback for sync (#21 Level 3)

If #21 Level 3 is implemented (conditional sync), baselines enable rollback when a synced change is discarded:

  • With restoration strategy → restore original via VCS adapter or cached content
  • Without restoration strategy → warn user that automatic rollback is not available

Delta rewrite guidance

When drift is detected and a restoration strategy is available, the agent or human can compare:

  • Original spec (via VCS ref or cached content) — what the spec looked like when the delta was designed
  • Current spec content — what it looks like now
  • Delta entries — what changes were intended

This gives enough context to decide whether to rewrite the delta or proceed.

Related

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions