feat: static generation and the read-through cold path #135
No reviewers
Labels
No labels
area: api
area: auth
area: build
area: cache
area: ci
area: compare
area: model
area: provenance
area: rite
backport
blocked
breaking
confirmed
dependencies
duplicate
epic
invalid
needs-info
needs-triage
php
priority: high
priority: low
priority: medium
regression
type: chore
type: correction
type: docs
type: enhancement
type: feature
type: fix
type: perf
type: refactor
type: security
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Directorium/Api!135
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/13-static-generation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Serves the hot calendar paths from a static tier, computing only on a cold miss (epic #13) — the cache-first model the R2 deployment depends on.
What's here
Cache\StaticStore(#15) — a filesystem store of pre-rendered response bodies, one JSON file per request key (v1/day/2026-09-03/1962/sspx). The whole tree is namespaced by the data version, so a corpus/engine/contract bump lands in a fresh directory and a stale file can never be served (the #28 rebuild-and-purge just drops the old dir). No root configured → the store is disabled and the service runs identically (the dev/test default).Cache\ResponseCache(#16) — read-through: a hit returns the stored bytes untouched; a miss computes, writes back, and returns, with cache-friendly headers so the edge can hold it (x-cache: HIT|MISS,Cache-Control). The day/month/year handlers respond through it, keyed by the query'scacheKey().bin/generate-static.php(#14) — warms the store for a year range by replaying every hot request (year, months, days × systems × calendars) through the real kernel, so generation reuses the exact response shape the endpoints serve — no second serialiser to drift — resolving each civil year once per (year, calendar).Verification
composer checkgreen: phpcs (bin now scanned too), PHPStan[OK], PHPUnit 56 tests / 199 assertions — including store round-trip, data-version isolation, read-through HIT/MISS, and end-to-end write-through at the kernel level.php bin/generate-static.php 2026 2026 <dir>wrote 756 files (2 calendars × 378 paths); the SSPX Sep 3 file resolves first class; a repeat request is anx-cache: HITwith byte-identical output; the usage guard rejects out-of-range/misordered years.Scope notes
The conservative
Cache-Controlhere is hardened to ETag + immutable, version-keyed caching in the next PR (epic #17). In production a web-server rewrite serves an existing static file directly (try-file →public/index.php), so the hot path never enters PHP.Refs #13 #14 #15 #16