Repository navigation
refactor: share the JSON body reader in internal/jsonbody - #160
Merged
Merged
Conversation
todos and notify each had a copy of the same function that reads a request's JSON body, and worklog-add would need a third. It moves to the root internal/, as AGENTS.md asks of code that two services need. Nothing changes in behaviour. The plan records decision 190: time-tracking gains this step and jira-own-writes, since Jira's search lags behind its writes.
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.
Brief
Goal. todos and notify read a request's JSON body with the same function, a copy each, and
worklog-addwould copy it a third time intotime. AGENTS.md moves code that two or more services need to the rootinternal/, so it moves to a package of its own,internal/jsonbody, a step ahead ofworklog-add, asshared-jira(#147) andshared-poller(#109) did. Nothing changes in behaviour. The fifteenth oftime-tracking's eighteen steps (decision 190).Scope.
internal/jsonbody:Read(w, r, v, refusal) bool, todos'readBody, moved: it decodes r's body, a JSON object without members that v lacks, into v, through json/v2; a body over 64 KiB gets a plain 413, and anything else it can't read a plain 400 with the refusal.add.go,edit.go) and notify (api.go) calljsonbody.Read; theirreadBodyandmaxBodyare gone, and todos'body.gowith them.time-tracking's eighteen steps:shared-json-bodyandjira-own-writesbeforeworklog-add), and decision 190.Out of scope. nudge's two readers, whose 400s say what went wrong (
read the question: …,read the answer: …) rather than a fixed refusal: sharing them would change what nudge answers. The 64 KiB limit as a setting. Anything ofworklog-additself.Acceptance criteria.
internal/jsonbodyholdsRead; noreadBodyor 64 KiBmaxBodyis left in todos or notify.mise run checkpasses.What changed
internal/jsonbody/jsonbody.go:Read, moved from todos'body.gobyte for byte apart from its name and doc (checked withdiff), and the unexportedmaxBody(64 KiB).internal/jsonbody/jsonbody_test.go: a body read (every member, one missing, none), ten refusals, and the 64 KiB limit (64 KiB read; a byte more, and a 64 KiB string, refused with a plain 413).body.godeleted;add.goandedit.gocalljsonbody.Read, with the same refusals, and their docs say "64 KiB" rather thanmaxBody.maxBodyandreadBodydeleted fromapi/api.go;route.handlercallsjsonbody.Read.docs/plan.md: the §0 row; §8.2time-trackinghas eighteen steps, withshared-json-bodyandjira-own-writesbeforeworklog-add; decision 190 (the split, the shared reader, Jira's search lag and the plan forjira-own-writes, with the evidence and the rejectedreconcileIssues).QA
grepfindsMaxBytesReaderandRejectUnknownMembersonly ininternal/jsonbodyand nudge's two readers; the onlymaxBodyleft in todos or notify ispush.go's 500-character cut of a notification's text, which is another thing.TestPostTodosTakesUpTo64KiBandTestPatchTodoTakesUpTo64KiBchecked to run, not skip).internal/jsonbodyat 100%.mutate.py, kept outside the repo): 17 mutants ofRead, among them a byte less or more, no cap, unknown or repeated members, invalid UTF-8, names in any case, one value read with the rest left, a 400 or another text for too large, another status or text for a refusal, and each return flipped. With the package's own tests alone 16 of 17 were caught at first:json.MatchCaseInsensitiveNames(true)survived, so QA added the refusal of{"Title":"Buy milk"}(json/v2 matches names exactly, where v1 didn't). Now 17 of 17 with the package's tests alone, and 17 of 17 with todos' and notify's handler tests added.mise run --jobs 1 checkgreen: golangci-lint 0 issues, buf lint, govulncheck none,go test -race, coverage 96.1% (thresholds met), web lint, knip, svelte-check, 1108 unit tests, audit, build, and E2E 339 passed + 7 skipped.Review
agent.go's answers a 400 with the decoder's error;phone.go's also answers a 400, not a 413, for an answer over its own limit. That's the nudge session's code (nudge-merge), so this step leaves it alone.nullreads as a body and zeroes v (json/v2's rule, checked), as before the move; todos then refuses it for its missing title.jsonbodysays what it does, clashes with no standard package), error handling (each error answered once) and the gates' limits: no findings.Merged under the user's standing OK (2026-10-26): merge once CI's
checkis green, and review everything at the end.