Skip to content

feat(api)!: send problem bodies for commit-write failures upstream documents as ProblemDetails - #669

Merged
ThomasK33 merged 1 commit into
mainfrom
issue352-commit-write-problems
Nov 4, 2026
Merged

ThomasK33 merged 1 commit into
mainfrom
issue352-commit-write-problems

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

commit-pack, diff-commit and restore-commit now send the result envelope only on the failure statuses for which upstream documents it, and the plain problem body on every other failure. This is part 2 of item 3 of #352 (scope: issuecomment-6628583093).

Why

Upstream's spec (412b90c3, now ee8092bf) documents these failure bodies:

Route Result envelope (CommitWriteResponse / ReposCommitsRestoreResponse) Plain ProblemDetails
commit-pack 400, 409, 412, 413, 502 401, 403, 404, 429, 500, 503
diff-commit 400, 409, 412, 502 401, 403, 404, 429, 500, 503
restore-commit 412, 502 400, 401, 403, 404, 409, 429, 500, 503

open.storage sent the envelope on all of them. SDK 0.1.0 turns any body with result into a RefUpdateError with the message "N: request failed" and no code.

What changes

  1. withResultEnvelope wraps each commit write route with its envelope statuses (commitWriteEnvelopeStatuses). wcFail finds them through the writer's Unwrap chain, as problemInstance does. It writes the envelope for a listed status and the plain problem body for any other status. These handlers never send 502, so the table leaves it out.
  2. The five 404 sites write upstream's specific codes directly: repository_not_found, branch_not_found ("base branch …", "target branch …"), and ref_not_found ("base_ref … does not resolve to a commit", "restore target … not found"). wcFail asserts that it never gets a 404.
  3. wcInternal writes the 500 problem body itself, so merge can still share it through wcResolveRepo. Merge's repository-not-found 404 and its 500 come from that shared lookup, so they become plain problem bodies too, as upstream documents for merge.
  4. TestCommitWriteEnvelopeStatusesMatchUpstream parses the vendored spec and pins the table, for both route styles. wctRequireFail asks the same spec parser which shape each test failure must have.
  5. Cleanup from the feat(api)!: send problem bodies for write-route auth, rate-limit and alias failures #663 advisor: after part 1, requireAuth was the only caller of requireAuthWith and its authFailWriter parameter, so I folded them into requireAuth. The README citations follow.
  6. Docs: streaming-commit-protocols.md §3 (a table of the envelope statuses, which also replaces the status list that part 1 left contradicting the next sentence), http-api.md, and the RFC 9457 row of wire-compatibility.md.

Validation

  • go build ./..., golangci-lint run (2.15.0): 0 issues. Docs gate: 0 broken links.
  • go test ./internal/api passes, with the new unit tests TestWcFailEnvelopeStatuses and TestCommitWriteEnvelopeStatusesMatchUpstream.
  • Race lanes on the top of this stack: see the comment below.

Dogfood

I used the verify-openstorage harness on a node built from part 1 (db643380, the #663 head) and on this change before its rebase onto #666 (fb60003b). Each run passed 29 checks.

Request Before After
commit-pack, missing base_branch (404) envelope not_found problem body branch_not_found
commit-pack, ref policy no-push (403) envelope forbidden problem body forbidden
restore-commit, no base_ref (400) envelope invalid problem body bad_request
restore-commit, unknown base_ref (404) envelope not_found problem body ref_not_found
commit-pack malformed frame (400), diff-commit patch conflict (409), commit-pack with no changes (412) envelope envelope (unchanged)
  • The refused writes did not move main: GET .../branch?name=main equals the last accepted commit.
  • SDK 0.1.0 Go: commits.restore with an unknown base_ref changed from RefUpdateError "404: request failed" to NotFoundError ref_not_found, and with an unknown target branch to NotFoundError branch_not_found. The no-op restore (412) stays a RefUpdateError.
  • SDK 1.17.1 Go: RestoreCommit on a missing target or branch changed from RefUpdateError status not_found with the server's message to status 404 with the message "restore commit failed with HTTP 404".

Refs #352

BREAKING CHANGE: commit-pack, diff-commit and restore-commit answer the failures for which upstream documents ProblemDetails with the plain problem body instead of the result envelope: 403 (ref policy, quota), 404, 429 and 500 on all three, and 400 and 409 on restore-commit. Merge's repository-not-found 404 and its 500 also answer the plain problem body. The 404s carry repository_not_found, branch_not_found or ref_not_found. SDK 1.17.1 Go reports these restore-commit failures as RefUpdateError with status 404 (or the HTTP status) and a generic message, and builds the commit-pack and diff-commit RefUpdateError with status failed. I did not check the 1.17.1 TypeScript and Python clients.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

…cuments as ProblemDetails

commit-pack, diff-commit and restore-commit keep the result envelope only
on the statuses for which upstream documents CommitWriteResponse or
ReposCommitsRestoreResponse (400, 409, 412 and 413 on commit-pack; 400,
409 and 412 on diff-commit; 412 on restore-commit). Every other failure
is the plain problem body, and the 404s carry repository_not_found,
branch_not_found or ref_not_found. A test pins the table to the vendored
spec.

_Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high_

Change-Id: Id4ab091377681015946d0be57b8142591c0a5cb3
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

Race lanes (go test -race -count=1 -tags=openstorage_viewcheck), run before the rebase onto #666. The rebase added exactly #666's diff to each commit (I compared the changed lines), and #666 passed its own CI.

Head Lane Result
fb60003b (this PR) ./internal/api/... ./internal/auth/... ./cmd/... pass
500f6f0f (part 3, stacked on this) same pass
a94c6451 (item 1, top of the stack) same, plus ./internal/githttp on PostgreSQL and on the local backend pass

After the rebase, on d928b53b: go build ./... and go test ./internal/api/ ./internal/auth/ -count=1 pass.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T15:06:24.912336Z d928b53 Manual request
🔒 Security Review ✅ Completed 2026-11-04T15:07:24.497422Z d928b53 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: d928b53b77

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: d928b53b77

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant