[Service] Wire-level qty upper bounds on cart lines and /inventory/reserve - #98
Merged
Merged
Conversation
…serve Zod .max() caps on the three unbounded qty sites (service-hardening plan §4): CART_LINE_MAX_QTY = 10_000 on addLineBody/patchLineBody (the shopper-facing, anonymous-caller surface), RESERVE_MAX_QTY = 1_000_000_000 on reserveBody (aligned with the existing admin stockMovementBody precedent — the raw inventory primitive, a machine caller). Both exported as named constants so tests assert boundaries against the same symbol. Today qty: 1e9 (or Number.MAX_SAFE_INTEGER) is a "valid" wire request rejected only by store arithmetic; the cap makes "how much may one request ask for" an explicit, tested part of the contract and rejects it early (400 at the zod boundary, before any store call or row write). Wire-only — the domain's positive-integer bound is unchanged (defense-in-depth); no port change. This is NOT a rate limit and does not fix junk-failed-reservation-row amplification, which is request-count-bound, not qty-bound. Follow-up filed and linked from the schemas.ts comment and the changeset: #91 Tests: packages/service/test/qty-bounds.test.ts (8 new, IO-free, in-memory stores via app.request()) — over-cap 400 with structured error, store never touched (reserve() spy + onHand unchanged), at-cap 200 boundary for both POST/PATCH cart-line paths, the reserve-endpoint pair at RESERVE_MAX_QTY / +1, and the exact QA repro (qty: 1e9) now 400. Changeset: @urumi/service minor — the breaking bump at 0.x (no major yet); previously-accepted over-cap requests now 400.
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
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.
What
From the 2026-07-26 API-contract QA: cart/reserve qty had no upper bound —
qty: 10^9passed the schema and minted a junkfailed-reservation audit row per attempt.CART_LINE_MAX_QTY = 10_000onaddLineBodyandpatchLineBody(capping only add would leave PATCH as a bypass)RESERVE_MAX_QTY = 1_000_000_000onreserveBody(aligned with the existing admin stock-movement cap)onHandis untouchedScope honesty (also in the changeset): this removes the absurd-magnitude vector, not the junk-row amplification one — that is request-count-bound and tracked in #91 (rate limiting).
Verification
@urumi/servicevs Postgres 310/310Changeset
@urumi/serviceminor (0.x wire-visible: previously-accepted qty now 400s).Follow-up noted by review: unify
stockMovementBody's literal withRESERVE_MAX_QTY(trivial, out of scope here).🤖 Generated with Claude Code
https://claude.ai/code/session_013Fkmqxb8d6hh4ETNNz43eZ