Skip to content

v0.1.0-alpha.282

@jonesrussell jonesrussell tagged this 01 Jul 03:16
* fix(validation): null existsChecker now throws instead of silently passing

A null checker on EntityExists/UniqueField constraints is misconfiguration
— the constraint cannot enforce its invariant without a callable. Previously
the validator silently returned (passing every value), masking setup errors.
Both validators now throw \InvalidArgumentException (symmetric with the
existing non-callable rejection) when existsChecker is null. Tests updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(mail): throw on local write failure and on empty recipients; scope README error-handling guidance

LocalTransport::send() now throws RuntimeException when file_put_contents
returns false (previously the write failure was silently ignored).
SendGridTransport::send() now throws InvalidArgumentException when all
recipients are blank (previously silently returned). README scopes the
wrap-in-try-catch guidance to non-critical mail and adds a warning that
auth-critical mail (password resets, verification) must let exceptions
propagate. TDD: LocalTransportTest and SendGridTransportTest cover the
new throw paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(L0): WP1 — minor cleanup across eight Layer-0 packages (F3–F8)

F3 – scheduler: inject clock into lock TTL and run-record timestamps
  LockInterface::acquire(), DatabaseLock, InMemoryLock, and
  ScheduleStateRepository::recordRun() all accept ?\DateTimeInterface $now = null
  (defaults to 'now' UTC). ScheduleRunner threads $now through every callsite,
  replacing direct time()/date() calls. Lock-expiry and timestamps are now
  deterministically testable.

F4 – i18n: Translator::has() walks fallback chain; LanguageManager::resetToDefault()
  has() previously checked only the active locale, missing translations available
  via the fallback chain. It now walks the full chain and treats empty-string values
  as absent. LanguageManagerInterface gains resetToDefault(): void for worker-mode
  locale teardown.

F5 – analytics: UmamiClient language is now injectable
  New optional trailing constructor parameter string $language = 'en'
  (backward-compatible) replaces the hardcoded 'en' in the Umami payload.

F6 – queue: DbalTransport::release() increments attempts atomically
  Previous SELECT+UPDATE race closed with a single
  UPDATE … SET attempts = attempts + 1 DML. Unused getAttempts() removed.

F7 – error-handler: EditorLinkGenerator is now a pure value object
  getenv('EDITOR') resolution moved to DevExceptionRenderer (composition root).
  EditorLinkGenerator accepts only string $editorId = 'vscode'.
  DevExceptionRenderer gains optional ?string $editorId = null constructor param.

F8 – geo: GeoDistance::haversine() validates coordinate ranges
  Latitude outside -90..90 and longitude outside -180..180 now throw
  \InvalidArgumentException naming the offending parameter. Boundary
  values (±90, ±180) are accepted.

CHANGELOG.md updated for all eight findings (F1–F8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(mail): suppress file_put_contents I/O warning in LocalTransport

The @-suppression is deliberate: file_put_contents() emits a PHP warning
on I/O failure, but we detect the failure via the false return value and
re-surface it as a RuntimeException — making the PHP warning pure noise
(and causing PHPUnit to exit 1 on test runs that exercise the failure path).

This is the accepted PHP pattern when you own the error-handling contract
and convert the signal into a typed exception.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Assets 2
Loading