add paginated section index pages

The first collection page earns the Query primitive: content.Query{Section, Lang}
with Site.Run, newest first, undated after dated, ties broken by key so the same
query always answers in the same order. No cache signature — nothing caches, and a
signature with no consumer is speculation.

Pagination lives in the path (ADR-0028): page one is the bare listing URL,
/page/1/ redirects to it, and a page past the end is 404 rather than an empty page,
because an empty page is a URL that means nothing. `page` is therefore a reserved
segment inside a section, now recorded in content-model.md.

Two kinds of page means two parsed template sets already — base plus the block that
kind defines — which is ADR-0019's per-type shape arriving by need rather than by
anticipation. A head struct is embedded in both Page and List so base.html has one
contract, and theme-contract.md gains the listing fields.

Bundle gains Date, accepting an unquoted YAML date or an RFC 3339 string, since
yaml.v3 hands back time.Time for one and a string for the other.

Evidence: 12 posts → /posts/ shows 10 with rel=next to /posts/page/2/,
/posts/page/2/ shows 3 with rel=prev to /posts/, ordering is post-12 11 10,
/posts/page/1/ 301s to /posts/, /posts/page/9/ is 404, /bn/posts/ is 200.
This commit is contained in:
2026-07-30 02:08:12 +06:00
parent 2b6cdc7e9e
commit 85a49068d2
12 changed files with 394 additions and 46 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
# State
**Verified against:** `8a6857b` on 2026-07-30 — update this line every change.
**Verified against:** `2b6cdc7` on 2026-07-30 — update this line every change.
If this file disagrees with the code, the code is right and this file is a bug.
## Inventory
@@ -29,9 +29,9 @@ this change*.
| Counter | Now | Extraction due at | What it buys |
|---|---|---|---|
| Render transforms | 0 | **3** | Stage pipeline (ordered `func(ctx,*Page) error`) |
| Routing cases | 2 | **2** — done | Resolver extracted at `internal/web/resolve.go` |
| Collection pages | 0 | **1** | Query primitive |
| Views / output formats | 1 | **2** | View layer (contract per `theme-contract.md`) |
| Routing cases | 3 | **2** — done | Resolver at `internal/web/resolve.go`: bundle, language prefix, pagination |
| Collection pages | 1 | **1** — done | Query primitive: `content.Query` + `Site.Run` |
| Views / output formats | 2 | **2** — due | Two template sets exist (bundle, listing); the View layer is Arc 2's third item |
| Effects | 0 | **2** | Effect runner + trigger wiring (change / schedule / demand) |
| Extensions | 0 | **3** | Extension registry + wire file (`extensions.md`) |
| Interface implementations | — | **2** | The interface itself |