Skip to content

3-way reconcile and stable task IDs #65

Description

@github-actions

3-way reconcile and stable task IDs

Two-way reconcile (v1) uses monotonic union: checked always wins, unchecked never propagates from the issue. Two limitations remain:

  1. Un-checking a task on the issue does not propagate — because v1 has no stored base state, it can't distinguish "human unchecked" from "was already unchecked". A 3-way merge with a stored base state would solve this.
  2. Wording changes in tasks.md break text matching — if the spec author rewrites a task line, the match fails and state from the issue can't co-apply. A stable task ID (e.g., hash of original text) would decouple matching from wording.

This change addresses both by storing a base snapshot per task and using a stable key for matching.

Out of scope

  • Real-time sync (specsync is invoke-and-exit)
  • Cross-provider state merging (each provider reconciles independently against OpenSpec)

Tasks

Tasks

Stored base state

  • Add base field to Ref struct: stores SHA of tasks.md at last sync
  • On reconcile, read base tasks.md from git history; compute 3-way diff against current tasks.md and issue state
  • Propagate un-checks from issue when base was checked but current is unchecked (3-way merge)
  • Tests: 3-way merge with un-check; base state preserved across syncs

Stable task ID

  • Match base tasks to current tasks by text then position to detect wording changes
  • Build reverse mapping (current text → base text) for rewritten task detection
  • Match issue tasks to spec tasks by base text via mapping, text fallback second
  • Tests: wording change in spec preserves state match via position-based mapping

Verification

  • go build ./..., go test ./..., gofmt clean

Plan changes

9 done

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions