Hi. Thank you for OpenSpec. We appreciate its flexibility and design, and it has worked super well for us.
After using it for a while, we hit the concurrent-modification problem described in openspec-parallel-merge-plan.md: two open changes modify the same requirement, and the second one to archive either conflicts late or, in the rebase-then-archive ordering, silently overwrites the first author's edit. The root cause is that a delta records only the new text of a MODIFIED requirement, with no record of the base it was derived from. The v1.6.0 archive guardrail (#1340) helps at archive time, but by then the second author has already worked against stale context, and overlap between open changes is not visible at all.
To help us deal with this, we built a small companion CLI that does the detection part today, before archive and in CI. We'd like to offer the ideas (and code, if useful) upstream.
concord: npm i -g @lucinate-ai/concord (Apache-2.0, TypeScript, parsers mirror the v1.6.0 header patterns exactly)
concord check verifies every MODIFIED/REMOVED/RENAMED target in every open change against the base branch and reports four finding kinds:
drift: the requirement changed on main after the branch diverged, so archiving would discard that change (shown as a redline)
removed-upstream: the target was deleted or renamed on main
target-missing: the name matches nothing, usually a typo, so archive can't apply the entry
name-collision: an ADDED or RENAMED-to name already exists
concord overlap lists any requirement claimed by more than one open change, so two authors find out on day one instead of at archive time. Exit codes are 0/1/2 for CI use, and both commands take --json.
One implementation detail may be of interest: no stored state is needed for the common case. For a PR branch, the base a delta was derived from is the requirement's text at merge-base(HEAD, main), and the landing target is the text at the main tip. Both reconstruct from git history. Blocks are canonicalised (line endings, trailing whitespace, blank-line runs) before hashing, so reformatting never registers as drift. Rebasing or merging main advances the merge-base, which clears the finding at the point where the author has re-derived their block anyway.
How this relates to the plan's phases, as we read them:
- The git reconstruction gives Phase-0-style detection before archive, on brownfield repos, with no format changes.
- Your planned
meta.json base snapshots cover exactly what git history cannot reconstruct (hand-edited deltas, provenance across an archive). We'd switch to them as the preferred source as soon as they exist.
- A Phase-1 sync/rebase (structured three-way merge keyed on requirement and scenario) is where we want to go next. Scenario-keyed merging would auto-resolve the most common collision: two changes editing different scenarios of one requirement. Happy to compare notes or pool effort there.
Questions:
- Would you take some or all of this upstream (as subcommands or a validation pass), or would you rather it stayed a companion tool?
- Any objection to us tracking your delta grammar? If the header patterns are going to change (for example the Phase-3 stable-ID work), a pointer to the direction would help us stay compatible.
- Is the
meta.json snapshot schema in the plan settled enough to build against?
Happy to open PRs against Phase 0/1 if that's welcome. We built this so teams can adopt OpenSpec with confidence, and we'd be glad to see any of it absorbed upstream.
Hi. Thank you for OpenSpec. We appreciate its flexibility and design, and it has worked super well for us.
After using it for a while, we hit the concurrent-modification problem described in openspec-parallel-merge-plan.md: two open changes modify the same requirement, and the second one to archive either conflicts late or, in the rebase-then-archive ordering, silently overwrites the first author's edit. The root cause is that a delta records only the new text of a MODIFIED requirement, with no record of the base it was derived from. The v1.6.0 archive guardrail (#1340) helps at archive time, but by then the second author has already worked against stale context, and overlap between open changes is not visible at all.
To help us deal with this, we built a small companion CLI that does the detection part today, before archive and in CI. We'd like to offer the ideas (and code, if useful) upstream.
concord:
npm i -g @lucinate-ai/concord(Apache-2.0, TypeScript, parsers mirror the v1.6.0 header patterns exactly)concord checkverifies every MODIFIED/REMOVED/RENAMED target in every open change against the base branch and reports four finding kinds:drift: the requirement changed on main after the branch diverged, so archiving would discard that change (shown as a redline)removed-upstream: the target was deleted or renamed on maintarget-missing: the name matches nothing, usually a typo, so archive can't apply the entryname-collision: an ADDED or RENAMED-to name already existsconcord overlaplists any requirement claimed by more than one open change, so two authors find out on day one instead of at archive time. Exit codes are 0/1/2 for CI use, and both commands take--json.One implementation detail may be of interest: no stored state is needed for the common case. For a PR branch, the base a delta was derived from is the requirement's text at
merge-base(HEAD, main), and the landing target is the text at the main tip. Both reconstruct from git history. Blocks are canonicalised (line endings, trailing whitespace, blank-line runs) before hashing, so reformatting never registers as drift. Rebasing or merging main advances the merge-base, which clears the finding at the point where the author has re-derived their block anyway.How this relates to the plan's phases, as we read them:
meta.jsonbase snapshots cover exactly what git history cannot reconstruct (hand-edited deltas, provenance across an archive). We'd switch to them as the preferred source as soon as they exist.Questions:
meta.jsonsnapshot schema in the plan settled enough to build against?Happy to open PRs against Phase 0/1 if that's welcome. We built this so teams can adopt OpenSpec with confidence, and we'd be glad to see any of it absorbed upstream.