Delete Review Comment - #283
Conversation
/speckit.confirmissue now deletes the review comment after the decisions reach the issue body, and the "already been through the pre-spec gate" signal moves off the comment's existence onto the `ready` label. The comment is working material: a numbered gap carries framing, evidence, a recommendation and an answer slot, and ten of those compress to ten one-line decisions. Once compressed it dwarfs the section that matters. Moving the done-marker is the real work, because two consumers keyed on the comment existing — /speckit.reviewissue step 1 and the guard step in speckit-reviewissue.yml. Both now check `ready` first and fall back to the sentinel, so issues confirmed under the old behaviour still read as reviewed with no migration. Deletion is conditional on the `ready` label having landed: the label step is never-fatal by design, so deleting without it would leave an issue with decisions, no label and no comment — indistinguishable from never-reviewed, and it would be re-reviewed on top of its own decisions. Removing `ready` is the reopen path — an issue whose scope has moved is by definition no longer ready — so putting one back into review needs no hand-editing of the body. RED-GREEN (Constitution Principle I, tooling carve-out): the workflow guard predicate run against a confirmed-issue fixture (`ready`, no review comment) did not fire, so the job would have proceeded to post a second full review; with the `ready` condition added it skips, while the reviewed-but-unconfirmed and never-reviewed fixtures keep their existing paths. Real-issue evidence before and after belongs in the PR body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Blockers:
- Step 7's DELETE used the wrong ID namespace. Step 1 resolved the comment
via `gh issue view --json comments`, which returns the GraphQL node id
(IC_kwDO...); `DELETE repos/.../issues/comments/<id>` takes the numeric
REST id. Verified live: node IC_kwDONbNDk88AAAABTCYLgw vs REST 5572529027.
Every run would have 404'd, and the never-fatal rule would have reported
it as bad luck forever. Step 1 now resolves over REST, and picks the most
recent marker comment by created_at — node ids do not sort chronologically,
and that choice now decides which comment is destroyed.
- The irreversible step gated on an unverified precondition. Step 6 is
never-fatal by design, so "only after step 6 succeeded" left "did it?" to
the model's reading of tool output. Step 7 now reads the label and the
body back from the issue and requires both before deleting — which also
covers the case where the body patch returned 200 with the wrong content.
- The workflow guard failed open. `jq -e '[.labels[].name] | index("ready")'`
exits 5 on a missing or null labels key, and inside an `if` errexit is
suppressed, so a jq error was indistinguishable from "not ready" and fell
through to posting. The label is now read live and assigned outside the
`if`, so a gh/jq failure fails the job instead (verified under `bash -e`).
Reading the label live also fixes a mixed-freshness window: the snapshot was
taken in the previous step while comments were read live, so an issue
confirmed by a local run in between read as neither ready nor reviewed.
Also: the rebuild path now carries forward decisions a new review does not
re-raise, instead of telling an absent actor to do it by hand; the 2026-09-07
CIR's second behaviour clause is annotated rather than exempted; and the new
CIR records three residuals the review surfaced — deletion is prompt-enforced
with no CI step to move it into, the reopen signal is indistinguishable from
a lost label, and speckit.draftissue is a third reader of the deleted comment.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@claude Review this pull request. Analyse the code changes and provide feedback covering:
End the review with a recommendation whether to merge the PR, and if not, what you suggest needs addressing first. |
|
Claude finished @FrankRay78's task in 5m 24s —— View job Review complete
Bugs / correctnessThis is a well-defended design, and the PR's own
One latent edge case I don't see called out anywhere: SecurityNo new secret handling; token usage ( CLAUDE.md / constitution adherenceGood. This is a tooling/config change and correctly uses Principle I's carve-out rather than inventing a bespoke test — the PR body documents real tool failure→pass evidence. The new CIR follows the established format, in-place-annotates the superseded Test coverageNo C# changed; Spec/test-plan mismatchesNone found — no active Note unrelated to the PR's contentWhile reviewing, this checkout's working tree had uncommitted local diffs on exactly RecommendationLean toward merge, conditional on completing the PR's own outstanding checklist — specifically the live |
Why
The pre-specification review comment is working material. A numbered gap carries framing, cited evidence, a recommendation with its reason, and an answer slot — and ten of those compress to ten one-line decisions once
/speckit.confirmissuehas folded them in. After that the comment dwarfs the## Confirmed decisionssection that matters, and whoever picks the issue up has to work out which of the two halves is current. In practice it was already being deleted after every successful run; the prompt forbade the thing that actually happened.Deleting it is the easy half. The comment's existence was the done-marker —
docs/agentic-workflow-NetPace.mdstated the contract, and two guards keyed on it — so the marker had to move first, or "confirmed" would have become indistinguishable from "never reviewed".What changes
The marker moves to the
readylabel./speckit.reviewissueand thespeckit-reviewissue.ymlguard both check it before falling back to the<!-- speckit:review -->sentinel, so issues confirmed under the old behaviour still read as reviewed with no migration./speckit.confirmissuedeletes the review, but only after reading thereadylabel and the## Confirmed decisionssection back from the issue. Every hard-stop sits upstream of that point, so a run that stops early leaves the review answerable and re-runnable.Re-running confirmation on a confirmed issue now says so, instead of reporting that there is no review to confirm — and repairs a missing
readylabel while it is there.Reopening is removing the
readylabel. An issue whose scope has moved is by definition no longer ready; nobody has to hand-edit the body.Docs: the state contract in
docs/agentic-workflow-NetPace.md, a new CIR, and in-place supersede annotations on2026-09-07-automated-prespec-review.md.Non-obvious things a reviewer should know
The marker is the label alone, not "label OR body section". The issue's technical notes sketched the OR, but it cannot coexist with AC #8 — the only way to clear a body section is to hand-edit the body, which is exactly what AC #8 forbids of the reopen path. CIR decision 1 records this and both rejected alternatives. This is the one place the implementation deliberately departs from the issue's own technical sketch.
Deletion is gated on the label having landed, not merely on the body patch. The label step is never-fatal by design, so deleting after a label failure would leave decisions on the body with no label and no comment — indistinguishable from never-reviewed to both guards, and re-reviewed on top of its own decisions. That state is the one thing the design exists to prevent, and it is the only one reached through a door that cannot be reopened.
Three blockers were found in review and are fixed here — worth knowing because the first would have made the feature a silent no-op:
gh issue view --json commentsreturns the GraphQL node id (IC_kwDONbNDk88AAAABTCYLgw);DELETE repos/.../issues/comments/<id>takes the numeric REST id (5572529027). Every run would have 404'd, and the "never fatal" rule would have reported that permanent failure as transient bad luck indefinitely. Step 1 now resolves over REST and selects bycreated_at— node ids do not sort chronologically, and that selection decides which comment is destroyed.jq -e '[.labels[].name] | index("ready")'exits 5 on a missing or nulllabelskey, and inside aniferrexit is suppressed, so a jq error was indistinguishable from "not ready" and fell through to posting a duplicate. The label read is now live and assigned outside theif, so agh/jqfailure fails the job./speckit.confirmissueis a second writer to the same state, so an issue confirmed between the two reads showed neither marker — and the post-condition check would still have passed the run green. Both reads are live now.Deliberately not done, and recorded as residuals in the new CIR rather than silently dropped:
ready, no comment, decisions on the body" is both the deliberate reopen state and what a repo-level label rename leaves behind. Telling them apart needs an explicit reopen signal, which reopens CIR decision 1.2026-09-07decision 5)./speckit.confirmissueis a local command with no CI step to move it into; the read-back narrows the gap as far as the mechanism allows.How to verify
Per Constitution Principle I's configuration/tooling carve-out there is no xUnit test here — the RED-GREEN evidence is the real tool failing before and passing after. The local half is done; the real-issue half is not, and should be captured before merge.
Done locally:
ready, no review comment) the pre-change guard did not fire — the job would have proceeded to post a second full review over## Confirmed decisions.IC_kwDONbNDk88AAAABTCYLgwvs REST5572529027for the same comment.ghin the label assignment exits non-zero underbash -erather than falling through.dotnet build ./srcclean (0 warnings),dotnet test ./srcgreen — 648 passed, 0 failed, 0 skipped. No C# changed; this is the unconditional gate, not evidence for the change.Still to do on a real issue:
speckit-reviewissue.ymlagainst this branch ref (workflow_dispatchruns the ref it is dispatched against) for an issue carryingready, and confirm it skips and clears thereviewlabel rather than posting./speckit.confirmissueend-to-end on a throwaway issue with an answered review: decisions land,readyapplies, the comment is deleted.readyand confirm a fresh first review is.Note the
issuespath runs the default branch's copy of both the workflow and the command file, so the label trigger only takes effect on merge —workflow_dispatchis the branch-testable path.Related
Closes #280
docs/change-intent-records/2026-09-11-confirmed-decisions-replace-the-review.md— new CIR: decisions, constraints, four known residuals.docs/change-intent-records/2026-09-07-automated-prespec-review.md— annotated in place where this supersedes it.docs/study/280.md— what surprised this work: 8 Execution, 1 Plan-spec, 1 Codebase.