Repository navigation
Add an opt-in best-effort throwable handler aggregate #6
Description
Delivery track and decision
The owner approved this separate, compatible 2.x minor, then merged PR80 at 2026-10-16T05:30:13Z, producing 1d31a0c3cafa0fcda495961951e216b0b163f4e0. The PR natively closed this issue as COMPLETED. The two new classes shipped in v2.4.0 and remain present in current master/v2.4.1. No agent performed the merge or release. The existing fail-fast aggregate, defaults, factories and typed ErrorHandler constructor remain unchanged.
This supersedes the earlier major-snapshot investigation below: the current 2.x ErrorHandler has no general reporter-failure reentry guard, and its middleware delegates rendering to the existing response factory. This feature changes neither boundary. Broader lifecycle/HTTP changes remain in the major roadmap.
Approved contract
- Add
Handler\BestEffortThrowableHandlerAggregate(ThrowableHandlerInterface ...$handlers)with a fixed, explicitly supplied reporter list. - On each
handleThrowable($original)call, attempt every constructor slot once, in order, with the identical original Throwable. Duplicate slots are deliberate separate attempts. - Catch reporter
Throwablefailures during that single pass. If any fail, including partial success, throw oneException\AggregateReportingExceptionafter all attempts. Zero reporters and all-success calls return normally. - The exception receives the original, one required reporter failure and remaining variadic failures.
getOriginalThrowable()returns the original object;getFailures()returns the nonempty, ordered list of identical reporter failure objects. The previous cause is the original. Its fixed summary message does not concatenate diagnostics; the exception and previous cause remain private diagnostic data. - No retries, automatic recursive delivery, reentry guard, observer, factory, discovery, dependencies or configuration DSL. Applications own terminal handling and durable delivery.
The existing ThrowableHandlerAggregate stays fail-fast. Keeping both policies in a future major is a recommendation, not a separately approved major redesign. Bare-callable ErrorHandler constructor inputs remain major work.
Acceptance
- Agree on the aggregate-exception terminal policy and additive 2.x scope.
- Implement the two opt-in classes with English PHPDoc and PHP 7.4-compatible syntax, proposed in PR80.
- Add focused PHPUnit tests for inert construction, zero/one/many reporters, first/middle/last/all failures, partial success, Throwable kinds, object identities, ordered failures, deliberate duplicates, named variadic arguments and independent repeated invocations.
- Preserve fail-fast/default behavior and document that native registration, shutdown and legacy HTTP behavior gain no new recovery/redaction guarantees.
- Align a runnable synthetic example, README, API/container/HTTP guidance, static source parity and the portable
coisa-error-handlerskill. - Include a minor Changeset and verify focused minimum/modern PHP, ordinary quality checks, clean no-dev/archive loading and exact-head hosted CI. PHP CI38854392241 passes14jobs at the PR head;22checks succeed with17expected skips. Local full quality:232tests/746assertions; focused7.4/8.5:14/55; both new classes100%, overall95.91%→96.14%.
The completed implementation checks above belong to candidate cd379c1f; the later owner merge and published release are recorded at the top. Native Closes #6 linked PR80 and closed the issue. Released-adapter wording was corrected by PR83, and the complete source-checked recipe was added by PR86, both released in 2.4.1. This reconciliation adds no feature, new publication or retry policy.
No real logger, network sink or production data is required. A return from a reporter is not proof of transport delivery. Partial reporter output and the aggregate exception must not be treated as a public response body.
Related: compatible maintenance, major API/lifecycle roadmap, logging, filtering.
Activity
[-]Design an opt-in best-effort throwable handler aggregate[/-][+]Add an opt-in best-effort throwable handler aggregate[/+]