fix: make accessibility PATCH a real merge patch instead of a full replace - #125
Conversation
|
Claude finished @koinsaari's task in 6m 20s —— View job Review: PR #125 — accessibility PATCH merge-patch safety
No blocking issues. This is a solid fix — traced the merge-patch logic end to end (
🟡 Nit
Note: Setting the |
…place
PATCH /places/{id}/accessibility previously replaced the whole profile with
whatever the caller sent, so submitting one field silently wiped every other
previously-stored component. UpsertProfile now applies the request body as an
RFC 7396 JSON Merge Patch on top of the current row (omitted = untouched,
explicit null = cleared), with the read-merge-write done inside one
transaction using SELECT ... FOR UPDATE so concurrent PATCHes on the same
place can't clobber each other.
Also fixes two bugs found while building this: captureRawBody was wired to
run before bodySizeLimiter, silently defeating the 1MB request cap, and it
mis-treated chunked/unknown-length bodies (ContentLength == -1) as empty,
rejecting legitimate requests. Adds a length cap on SourceReports entries
(internal/validation), the only free-text field left on this endpoint.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5666568 to
f1d6361
Compare
|
Claude finished @koinsaari's task in 4m 0s —— View job Review: PR #125 — accessibility PATCH merge-patch safety (re-review after push)
No blocking issues. This is the same commit (
I wasn't able to run Note: Setting the |
Summary
PATCH /places/{id}/accessibilitypreviously did a blind full replace: submitting one field silently wiped every other previously-stored component.UpsertProfilenow applies the request body as an RFC 7396 JSON Merge Patch on top of the current row (omitted = untouched, explicitnull= cleared).SELECT ... FOR UPDATE, so two concurrent PATCHes on the same place can no longer clobber each other's just-committed fields.captureRawBodywas wired to run beforebodySizeLimiter, silently defeating the 1MB request cap; and it mistreated chunked/unknown-length bodies (ContentLength == -1) as empty, rejecting legitimate requests.SourceReportsentries (internal/validation) — the one remaining free-text field on this endpoint.Test plan
make buildmake lint(0 issues)make test(unit, all packages green,validationcoverage 98.2%)make test-integration(all packages green, including a new goroutine-based concurrent-PATCH test and explicit-null/partial-submission tests against real Postgres via testcontainers)internal/api/v1/server.gen.gois byte-identical to whatopenapi.yamlcurrently generates🤖 Generated with Claude Code