4.6 KiB
Web Advanced: support matrix
Every capability is off unless named. WebAdvancedPromotionGate.forFeature is the machine-checked
form of the last two columns; if this table disagrees with it, the code wins.
| Capability | Flag | What it adds | Required suites | Soak |
|---|---|---|---|---|
MVC_VIRTUAL_THREADS |
backend.web.advanced.mvc-virtual-threads.enabled |
A different scheduling model for every request | web:test, webCrossStackParityTest, virtual-thread-admission, pinning-jfr |
24h |
WEBFLUX_BLOCKING_BRIDGE |
…webflux-blocking-bridge.enabled |
A bounded offload; affects the shared event loop | web:test, blocking-bridge-bounded, event-loop-guard |
24h |
JSON_MERGE_PATCH |
…json-merge-patch.enabled |
RFC 7396, partial documents | web:test, patch-security, patch-atomicity |
8h |
JSON_PATCH |
…json-patch.enabled |
RFC 6902, arbitrary pointers | as merge patch | 8h |
SSE |
…sse.enabled |
Long-lived connections | web:test, streaming-soak-10k, slow-consumer-bounded, cancellation-propagation, pod-drain |
24h |
NDJSON |
…ndjson.enabled |
Long-lived connections | as SSE | 24h |
JSON_SEQUENCE |
…json-sequence.enabled |
Long-lived connections | as SSE | 24h |
FUNCTIONAL_WEBFLUX |
…functional-webflux.enabled |
Routes with no annotation to scan | web:test, functional-route-parity |
8h |
CBOR |
…cbor.enabled |
A second decoder | web:test, codec-security, codec-budget |
8h |
XML |
…xml.enabled |
A decoder with dangerous defaults | as CBOR | 8h |
OPENAPI_32 |
…openapi-32.enabled |
A parallel description artifact | web:test, openapi-32-toolchain-matrix |
8h |
RATELIMIT_DRAFT_HEADERS |
…ratelimit-draft-headers.enabled |
Additive response headers | web:test, ratelimit-draft-headers |
8h |
Two capabilities change requests that do not use them
WebAdvancedFeature.affectsUnrelatedRequests() is true for exactly MVC_VIRTUAL_THREADS and
WEBFLUX_BLOCKING_BRIDGE. A codec affects only requests that negotiate it; a virtual-thread
executor affects every request in the process, and the blocking bridge affects the event loop they
all share. WebAdvancedFeatureFlags.stableBehaviourPreserved() reports whether either is on.
That distinction is why those two soak for 24 hours and why their rollback test is the one that matters most.
What is refused, and why the row is here
| Refused | Reason |
|---|---|
| Virtual threads without an admission limit | The pool size was the admission policy. Removing it accepts every arrival and queues them on downstream budgets that did not grow. |
| A blocking offload for an unregistered operation | boundedElastic() is reachable from anywhere and unbounded in practice; an unenumerable set of offloads is invisible until the pool is the heap. |
| A merge patch outside its field allowlist | A merge patch is partial, so no DTO's absent fields say "not permitted". Without an allowlist the writable set grows every time somebody adds a field. |
| A JSON Patch pointer above its allowed prefix | Replacing a parent deletes every sibling, so permission on a child cannot grant it. |
A move whose source is unauthorized |
Checking only the destination lets a caller relocate data out of a field they may not touch. |
| XML with a DTD or an external entity | Billion-laughs and XXE. Neither errors when it fires; the parse succeeds and the document contains something it should not. |
| A non-JSON representation without all three gates | Flag, route produces, and client allowlist. An Accept header is not evidence the route was tested against that codec. |
| Compression-style silent fallback on a 406 | A client that asked only for CBOR and gets JSON parses the bytes as CBOR and fails somewhere far away. |
| Changing HTTP status after commit | The body becomes half stream, half JSON, and the 200 is cached. |
| Unbounded buffering for a slow consumer | It moves the client's slowness into the server's heap. |
Promotion
Each capability is promoted on its own evidence. Two conditions apply to all and are not waivable:
- Rollback exercised. A flag nobody has turned off is not known to turn off.
- Stable behaviour unchanged with the feature off. If it is not, the feature was never optional and every deployment has it.
Parsers and patch appliers additionally require a security review —
WebAdvancedPromotionGate.needsSecurityReview names them.
See docs/adr/ADR-WEB-ADV-001-streaming-is-live-delivery.md,
ADR-WEB-ADV-002-virtual-threads-do-not-remove-admission.md, and
ADR-WEB-ADV-003-openapi-32-remains-experimental.md.