docs(specs): specify the npm publish upload-session shed 503
What this does
Gives the npm publish upload-session shed its home in S11. The 503 and its
upload_session_capacity_exceeded code are rendered by the
upload-session-concurrency-cap plan's Step 4, and until this lands the code
is a client-visible value no merged spec names.
Six additions to docs/specs/S11-npm-hosted.md:
- The Error Cases row, which carries the condition, the jittered
Retry-Afterand what that number is priced on, and the two things the code is not: it is global rather than per-tenant, and it is not the per-organization upload-session-count limit that the413 request_entity_too_largerow above it carries. - The Response 503 row in the publish contract table.
- The Response 500 and Response 502 rows in that same table. S11 already gives publish both, in the Error Cases table and in the Step 3 and Step 5 failure-mode rows, but neither had a contract row. Listing only the 503 would have made a uniform absence read as a deliberate selection, and the new acceptance criterion makes the 502 load-bearing by contrasting the shed against it.
- The publish failure-modes row for Step 3, which now says the shed opens no session at all and so leaves nothing for the upload purger to reap.
- An acceptance criterion, asserting the status, the code, the
Retry-Afteras bounds rather than as a literal, and that the refusal stays distinct from the502 storage_upload_faileda storage transient produces at the same seam. It is appended at the end of the section, so every existing ordinal is unchanged: acceptance criteria 1 to 69 are byte-identical tomainand the new one is 70.
Why the Retry-After is bounds rather than a value
The value is drawn per response, uniform over whole seconds across a window around the base, so a fleet shed in one instant is not told to come back at the same second. A criterion naming a literal would be false on most responses.
The spec also says what the base is and is not. The 35 seconds is a magnitude
borrowed from inline_build_timeout's wait, not an estimate of when a slot
frees: an admitted hold runs to npm.publish_read_timeout, which defaults to
30 minutes, so a gate held by slow uploads outlasts every value the jitter can
draw.
Merge order
This MR merges first of the set below. Ahead of it, Step 4 renders a code no merged spec names.
| Order | MR | What it carries |
|---|---|---|
| 1 | this MR | the S11 Error Cases row, the Response 500, 502 and 503 rows, the failure-modes row, and the acceptance criterion |
| 2 | !2460 (merged) | the publish response write deadline, the npm half of #31 |
| 3 | !2465 (merged) | Step 4: the 503 rendering, its code and safe message, and the code budget move to 41 |
| 4 | !2466 (merged) | Step 4's corrected Files list and its Status row |
!2465 (merged) is gated behind this MR as a merge-request dependency, not only by this
table. It depends on !2460 (merged) as well: without that, a shed answered after the
admission gate's park cannot be written at all, because net/http arms the
write deadline once at the header read from server.timeouts.write.
!2469 (merged) also appends to S11's ## Acceptance Criteria, at 70 to 78. It is not
ordered against this MR: neither disturbs criteria 1 to 69, so whichever lands
second renumbers only its own block.
Scope
Spec text plus one writing-discipline convention. No Go file, no configuration, no generated file.
docs/dev/writing-discipline.md gains A contract table listing one status
of a class lists the whole class, the rule behind the 500 and 502 rows
above, landed as its own commit so it can be reviewed or reverted apart from
the spec change. It sat in AGENTS.md until this branch was rebased over
!2020 (merged), which routed the convention text into lazily-loaded modules.
AGENTS.md now says a new convention lands in the module its Context Routing
table names for the topic, and that table routes prose which outlives the
change to docs/dev/writing-discipline.md.
The status of S11 is unchanged: this is an amendment to a merged spec, not a re-approval.
Related to #1234 (closed)