Bound each provider's startFetch()/resolveFetch() to an optional
since/until window, wire a SQLite-backed ContributionStore into
ContributionAggregator (fetch only the trailing window past the last
stored date, merge into the store, prune by CONTRIBUTIONS_RETENTION_DAYS),
and add a graph:contributions:refetch command to force a full or ranged
re-fetch in <=365-day chunks. This is the root fix for the full
365-day-refetch timeout that used to hit on every cache miss.
- Run cache:warmup in the build stage so containers start with a
pre-built Symfony kernel and DI container
- Scope the cache volume to var/cache/prod/pools where Symfony writes
pool data, preserving the warmed kernel across container restarts
- Add docker-compose.prod.yml for deploying the registry image without
the dev override being picked up automatically
- Expand .dockerignore to exclude vendor/, tests/, docs, compose files,
and env files from the build context
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>