mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-19 06:10:10 +08:00
* fix(verify): read a removed requirement's baseline before searching Since #1962, verify inverts the check for `## REMOVED Requirements`: it searches the codebase for the removed behavior and passes when nothing is found. But a REMOVED block carries only the requirement name plus its `**Reason**` and `**Migration**` notes - the parser takes names and nothing else - so the search started from the heading alone. An implementation that used different vocabulary from the requirement title read as a clean removal, and because absence is the passing result here, the report showed a silent pass. The RENAMED branch immediately below already loaded its baseline from the main spec first. Give REMOVED the same treatment: read the requirement's body and scenarios from the main spec before searching, and search for that behavior. A removal needs one step a rename does not. Archive deletes a REMOVED requirement outright, while a rename is retitled in place, so after a sync there is no baseline left in the main spec to fall back on. Recover it from repository history instead, and when it cannot be recovered at all, report Spec Coverage as not verified for that entry rather than counting it as passing. Closes #2067 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(update): state the glob new-file exception on the scope guardrail The guardrails of /opsx:update contradicted step 4. The first scope bullet said to edit only the concrete files in `existingOutputPaths`, and a file step 4 creates to fill a gap under a partly written glob artifact is by definition not in that list. The exception sat two bullets below, so an agent applying the stricter blanket rule refused the very operation the glob-gap flow exists to perform, and the missing spec went unfilled. State the exception on the bullet carrying the stricter rule, where an agent reading it will see it, and leave the confirmation and path checks where they already live in step 4. Closes #2068 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(workflows): harden the removed-baseline and glob-scope guidance Adversarial review of the two preceding commits found one real bug, one half-applied fix, one stale spec, and a test guard with no teeth. The history fallback did not work. `git log -p -- <capability-path>/spec.md` omits the `openspec/specs/` prefix that `<capability-path>` is defined relative to, and `git log` reports an unmatched pathspec as success with no output. An agent following it literally saw silence, concluded the baseline was unrecoverable, and marked every already-synced removal not verified - so the recovery path the fix advertised could never once succeed. The command is now `git -C <planningHome.root> log -p -- openspec/specs/<capability-path>/spec.md`, anchored on the planning home because the capability may live in a store rather than the current checkout, and the text now warns that empty output means the pathspec matched nothing. Three further gaps in the same branch. A baseline that only restates its own title gives an agent no more vocabulary than the heading did, so it is now unusable evidence like a missing one. The not-verified bail-out moved ahead of the search, because it previously sat two bullets after the rule saying that finding nothing is expected. And a miss in the main spec is no longer attributed to an earlier sync alone, since a differently-worded baseline misses a literal title lookup. Step 6 claimed each REMOVED entry "is checked there against its baseline behavior" in the same breath as the branch that may not check it; it now excepts an entry marked not verified. The scorecard models the not-verified wording too, having offered only confirming phrasing. The #2068 fix was applied to the guardrail but not to step 2, which states the same scope rule two steps before the exception appears - the same reading order that caused the bug. Both sites now carry it, and the guardrail says "any" confirmed path rather than "the one", matching a step 4 written per gap. `openspec/specs/opsx-verify-skill/spec.md` still described the old behavior, its Removed-requirement scenario carrying none of the clauses its Renamed sibling has, so the accepted spec sanctioned the silent pass. It now mirrors the template, as #1962 did for the preceding fix. Tests: the ordering assertion compared two unguarded `indexOf` results, so a reworded sentence would have made it pass on -1 and retired the only structural guard in the change. Indices are now checked present first, the fallback is pinned between the primary read and the search, the negative guards match reworded re-introductions rather than one exact sentence, the scope-rule check sweeps the whole body instead of a tail slice that could not see step 2, and the git command and the "(step 4)" cross-reference are pinned. All 20 of the hardened assertions fail against the two preceding commits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(verify): quote the planning root in the history fallback command An unquoted `git -C <planningHome.root>` splits on spaces, so the fallback failed for any planning root with a space in its path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(verify): read history from the planning root, not the repo root `git show <rev>:<path>` resolves the path from the repository root, not from `-C`, so the fallback failed whenever the planning root is a subdirectory (a monorepo package or a store inside a larger repo). A leading `./` keeps the path relative to the planning root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>