* paper-plane: dark-mode refinements (readable forms/rows, consistent button system)
* tests: make CactiErrorHandler suppression test hermetic against leaked IN_CACTI_INSTALL
The three suppression cases eval a sandboxed copy of CactiErrorHandler to exercise the error_reporting() mask and logging path. Pest runs the whole suite in one process, and tests/integration/BoostProcessTableUpgradeIntegrationTest defines the global IN_CACTI_INSTALL constant at collection time. A constant cannot be unset, so the handler short-circuited to true before reaching the branch under test, failing 'an enabled level is logged and reported to PHP as unhandled'. Strip the install-mode guard from the sandboxed copy so the case is independent of collection order.
---------
Co-authored-by: TheWitness <larry@thewitness.org>
* Honor @ error suppression in CactiErrorHandler on PHP 8
CactiErrorHandler() guarded against the @ operator with error_reporting() == 0,
which was the PHP 7 semantics. On PHP 8 the @ operator sets error_reporting()
to a non-zero bitmask that merely excludes the suppressed level, so the guard
never matched and deliberately suppressed warnings still reached the log.
This surfaced after the Symfony mailer swap: Symfony's SendmailTransport writes
to the sendmail pipe with @fwrite(), and when sendmail is misconfigured the
broken-pipe notice leaked into the Cacti log instead of being swallowed and
reported as the handled TransportException.
Mask error_reporting() against the incoming level so the @ operator is honored
on every supported PHP version.
* Add regression test for CactiErrorHandler @-suppression mask
Exercises both paths of the error_reporting() mask check: a notice and a
warning raised under PHP 8's @-operator bitmask return before logging, while an
enabled level is logged and reported back to PHP as unhandled. The suppressed
cases would have logged under the previous error_reporting() == 0 guard, so the
test fails closed if that regression returns.