test(managementapi): cover the container upstream associate refusals and update part 13/15 (S17 Phase 6 plan: 42/42)
Why
Part 12 covered the reads and the associate happy paths. The sentinel-to-status mapping, which is the handler's share of S17 AC 82, 91, and 92, the body rules the closed schema fixes, and the audit events are unproven until this group runs them.
It also changes three npm tests. Lint flags the npm half of the two tables these twins duplicate, so both carry a dupl directive. npm's uppercase 404 case sent ...0A against a list seeded with ...01, so it passed without testing the spelling. It now seeds the id it misspells.
This part carries the four changes vespian_gl asked for on part 12, tracked in Follow-up from "test(managementapi): cover the ... (#1493 - closed) • Unassigned:
- The update gate's comment says the update reads before it moves.
- The mixed-pair
201message names the stored format it pins, and the verdict table checks a log line only on rows that expect one. - The standalone sibling-segment test is gone, because the format table's sibling row sends the same requests. The table gains that test's
Dissociatesand audit checks. - The container suites share part 11's arm table and row builder, and npm's id helper and route type. The literal ids follow the helper's
01930000prefix, because the three non-canonical spellings in the 404 table must still name a held row.
This part also builds the contract router once per test binary. Every assertMatchesContract call parsed and validated the whole OpenAPI document. At part 15's head, internal/managementapi took 394 s under -race on four cores. Part 15's test:race job failed at go test's ten-minute default. With the shared router, the same 7,931 tests pass in 56 s and the race detector reports nothing.
The stack
Fifteen parts, each stacked on the last, each green on its own, reviewed in this order. Each part stays under 700 changed lines, counted as insertions plus deletions against the part it targets, except part 13 at 891, which carries part 12's review-driven dedup.
The delete guard in part 9 must be deployed before part 11's associate route serves traffic. Merge order alone does not close the window: within one rollout, a pod without the guard can answer 202 on destructive=true for an upstream that a new pod has just associated, leaving a tombstone the reaper refuses.
891 changed lines against guardrail 18's 500 ceiling. This part's own test group is 623 (container_virtual_upstreams_test.go 600, npm_virtual_upstreams_test.go 23), and splitting it further would separate cases that share a rig and a fixture. Part 12's review-driven dedup is 236 (container_virtual_upstreams_test.go 223, container_upstream_arms_test.go 13), and the shared contract router is 32 (contract_test.go).
This test-only part adds no e2e scenario (guardrail 12). The docker and oci upstream scenarios land in part 14, test(managementapi): cover the container upstre... (!2859 - merged) • Hayley Swimelar • 19.5. It changes no customer-visible surface, so no docs/user page moves (guardrail 24).
Closes #1493 (closed) Related to #314 (closed)