Repository navigation
feat(items): idempotency keys for comments, notes and decisions; idempotency_target_gone is structured (TASK-3585) - #2068
Merged
Merged
Conversation
…orts (TASK-3585) A replayed create whose item has since been deleted answers 410 idempotency_target_gone. Remote MCP had no 410 arm, and the CLI wrote no stdio marker for it, so it reached agents as a generic error. It is now allow-listed, mapped on the remote 410 arm, and marked on stdio, with a hint shared between internal/cli and internal/mcp. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
POST .../items/{ref}/comments accepts op_key (body) or Idempotency-Key.
The key's answer (the comment id) is recorded inside
CreateCommentWithActivity's transaction, so a retry whose first answer
was lost returns that comment instead of a twin. A refused comment
releases its key; a replay of a comment deleted since answers 410
idempotency_target_gone. `pad item comment --op-key` (a fresh key per
invocation by default) retries once behind the idempotency_keys
capability; MCP comment forwards op_key on both transports.
Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
PATCH /workspaces/{ws}/items/{ref} accepts op_key (body) or
Idempotency-Key, but only on an append-only update
(append_implementation_note and/or append_decision, plus source); a key
with any other member is refused 400. The answer (the item id and the
minted entries) is recorded in the update's own transaction, so a retry
whose first answer was lost echoes the first entries in `appended`
instead of appending twice. The built-in and patch callers, which reach
this handler with their own key, are untouched.
`pad item note|decide --op-key` (fresh per invocation by default) retry
once behind the idempotency_keys capability; MCP note/decide forward
op_key. ToolSurfaceVersion 0.91 -> 0.92 (additive; also records the 410
now being structured). docs/api.md covers create, comment and append keys.
Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
xarmian
added a commit
that referenced
this pull request
Oct 12, 2026
… hard-coded current version docs/mcp.md said "currently 0.90" in two places, while #2065 and #2068 moved the constant to 0.92 without a changelog entry. The entries are added from version.go's own notes, and the "currently" figures (catalog, ToolSurfaceVersion, CmdhelpVersion) now point at the constants in internal/mcp/version.go, so they cannot go stale again. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ
xarmian
added a commit
that referenced
this pull request
Oct 12, 2026
… hard-coded current version docs/mcp.md said "currently 0.90" in two places, while #2065 and #2068 moved the constant to 0.92 without a changelog entry. The entries are added from version.go's own notes, and the "currently" figures (catalog, ToolSurfaceVersion, CmdhelpVersion) now point at the constants in internal/mcp/version.go, so they cannot go stale again. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ
xarmian
added a commit
that referenced
this pull request
Oct 12, 2026
… hard-coded current version docs/mcp.md said "currently 0.90" in two places, while #2065 and #2068 moved the constant to 0.92 without a changelog entry. The entries are added from version.go's own notes, and the "currently" figures (catalog, ToolSurfaceVersion, CmdhelpVersion) now point at the constants in internal/mcp/version.go, so they cannot go stale again. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ
xarmian
added a commit
that referenced
this pull request
Oct 12, 2026
… hard-coded current version (#2095) docs/mcp.md said "currently 0.90" in two places, while #2065 and #2068 moved the constant to 0.92 without a changelog entry. The entries are added from version.go's own notes, and the "currently" figures (catalog, ToolSurfaceVersion, CmdhelpVersion) now point at the constants in internal/mcp/version.go, so they cannot go stale again. Claude-Session: https://claude.ai/code/session_01FAVXA5mJ5BNhKmv95jxQkQ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TASK-3585, appends: idempotency keys for comment create and the note and decision appends. This also folds in the lead's ask from #2065:
idempotency_target_goneis now a structured code.What changes
idempotency_target_gone(410) is allow-listed and mapped on both MCP transports:errors.go.IsPatchRefusal.internal/cliandinternal/mcp, and the parity test covers it.POST .../items/{ref}/comments): acceptsop_keyin the body or anIdempotency-Keyheader.CreateCommentWithActivity's transaction (CommentCreate.AfterWriteTx).PATCH .../items/{ref}): a key is accepted only on an append-only update, meaningappend_implementation_noteand/orappend_decision, plussource.ItemUpdate.AfterWriteTx).appended. It is enriched with the caller's visible collections, like the update's own response.b != nil) already carry their own key and are skipped.pad item comment|note|decide --op-key, with a fresh key per invocation by default. Each retries once with the same key on a 5xx or transport error, only when the server advertisesidempotency_keys.op_keyon both transports.ToolSurfaceVersiongoes from 0.91 to 0.92 (additive). The golden files, README, instructions.md and docs/api.md are updated.Tests
AfterWriteTxunset). A key on a non-append update is refused and writes nothing. Unkeyed appends still append each time.op_keytests go red with forwarding removed. A create replay of a deleted item returns the structured 410 on remote and stdio, red with the 410 arm removed.go test ./...(41 packages) and lint are green before the rebase. After it,cmd/pad,internal/cli,internal/mcp,internal/modelsand the server/store guard and TASK-3585 tests are green.https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS