Remove the infrastructure Env leak and ambient time from the domain core, and
model the sender policy as a value object.
- Point 1: Feed.create/edit no longer receive Env. The application layer resolves
the effective lifetime (parsing FEED_TTL_HOURS and applying the server override)
via feed-service.resolveTtlHours and hands the domain a plain ttlHours.
resolveExpiresAt(ttlHours, now) is now pure.
- Point 4: introduce a Clock port (systemClock default), injected at
create/reconstitute. The aggregate uses clock.now() instead of Date.now().
The isExpired edge helper keeps its Date.now() default for routes.
- Point 6b: extract SenderPolicy value object built once from the lists
(decide(senders)) instead of re-parsing per sender; applySenderPolicy is now a
thin wrapper over it.
Coverage moved with the logic: the FEED_TTL_HOURS override is now pinned by
feed-service.test.ts; aggregate tests use an injected fixed clock.
351 tests pass; tsc --noEmit clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>