ADR-0011: Retain Vault streaming without falling back to the PHP stream handler 

Status

Historical proposal (original status: Proposed)

Date

2026-10-08

Original decision makers

Project architecture/security owners; approval still pending in the original proposal.

Requirements

HG-028, HG-029, HG-030, HG-036, HG-037

Original supersession

None; a new decision for the proposed product.

Context 

Vault's ADR-039 describes streaming through a pinned curl-multi transfer whose progress is driven while the response body is read. stream=true would instead select the PHP stream handler and lose the pin. The credential-bearing API deliberately encapsulates transport, promise and secrets.

Sources: [S05, S08].

Decision 

In v1, global middleware supports ordinary buffered sends and explicitly rejects Guzzle's stream=true. This does not exclude Vault's separate streaming API. Its adapter uses the same policy/ConnectionPlan logic, but receives an internally controlled transfer lease for ongoing progress and cancellation.

A single owner is responsible for the tick loop, settlement and release. Cancellation before start prevents the transfer; cancellation in flight closes the active socket. Body close, errors and aborted consumption release resources idempotently. Errors after partial responses are not presented as complete EOF success.

Vault retains credential injection, prior secret permissions, audit, buffer limits, idle/total time semantics and the distinction between proxy and origin responses in its existing regressions. The new v1 proxy boundary is treated as an explicit compatibility change rather than hidden. Its public API still exports no raw security options.

Rejected alternatives 

  • Remove streaming entirely: unnecessary product loss.
  • Accept stream=true: selects the wrong transport.
  • Copy the streaming mechanism anew: avoidable errors around EOF, buffer limits and cancellation.
  • Expose a raw client: expands the credential-bearing surface.

Consequences 

The demanding Vault feature is retained. Migration requires real streaming/cancellation tests and is not complete merely by replacing a factory. Long streams remain resource-bearing transfers that must be ended explicitly.

Evidence and acceptance in the original proposal 

T058, T059, T060, T061, T069, T070, T071, T072. Details and expected results are in Original verification specification. These tests were specified, not executed as part of the original documentation delivery.

Reasons to reconsider 

Global incremental streaming is a later feature. It must satisfy the same pin, lifecycle and error obligations, rather than merely enabling a different Guzzle switch.