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-08-01 02:23:34 +06:00
parent 9dba59be2f
commit 60a7e10aee
12 changed files with 394 additions and 46 deletions
+3 -1
View File
@@ -31,7 +31,9 @@ reaches its threshold. Check it; do not guess.
## Query — filter/sort bundles into a list
Returns a list plus a signature doubling as a cache key. All grouping is a Query: sections, tags,
series, latest, related, pagination, feeds.
**STATUS: deferred until the first collection page.** One-off directory reads are fine before then.
**STATUS: live.** Earned at the first collection page. `content.Query{Section, Lang}` with `Site.Run`;
it carries no cache signature yet, because nothing caches and a signature with no consumer is
speculation.
## View — bundle-or-query → output
Overridable per bundle. All presentation. Emits HTML, gemtext, PDF, a program, JSON.