record ADR-0033: series membership is structural
Answers the question that blocked sequences. A chapter belongs to the series it is nested under, so the engine reads no `series` field; `order` stays, optional, and a member without one sorts by name after every member carrying one. This supersedes ADR-0016's membership clause and keeps its position rules — the point of that ADR was that position never reaches a URL, which still holds. The directory already states membership unambiguously; a second statement in frontmatter can only agree or be a typo that silently orphans a chapter. Cost, stated in the ADR: a series can never span directories, and membership now rides on the bundle key, which ADR-0008 makes permanent.
This commit is contained in:
+28
-12
@@ -31,7 +31,7 @@ overrides the defaults the binary embeds, so a bare root still renders.
|
|||||||
comics/ # webcomics [spec]
|
comics/ # webcomics [spec]
|
||||||
the-long-monsoon/
|
the-long-monsoon/
|
||||||
_index.en.md # the series bundle; also the cascade point for it
|
_index.en.md # the series bundle; also the cascade point for it
|
||||||
first-rain/ # slug is the name, never the position (ADR-0016)
|
first-rain/ # a chapter because it is nested here (ADR-0033); slug is never the position
|
||||||
index.en.md
|
index.en.md
|
||||||
page.png
|
page.png
|
||||||
art/ # single images or sets [spec]
|
art/ # single images or sets [spec]
|
||||||
@@ -78,7 +78,7 @@ readable by templates (ADR-0002). Never add a required field.
|
|||||||
| `nocache` | bool | Never cache this bundle's render. Named so absence means cacheable, per ADR-0002 |
|
| `nocache` | bool | Never cache this bundle's render. Named so absence means cacheable, per ADR-0002 |
|
||||||
| `summary` | string | Explicit summary; otherwise derived |
|
| `summary` | string | Explicit summary; otherwise derived |
|
||||||
| `tags` | []string | Flat, case- and script-preserved as written. A scalar or a list. The URL form is lowercased with spaces hyphenated, so `Long Monsoon` and `long monsoon` are one term; scripts without case pass through unchanged (ADR-0018) |
|
| `tags` | []string | Flat, case- and script-preserved as written. A scalar or a list. The URL form is lowercased with spaces hyphenated, so `Long Monsoon` and `long monsoon` are one term; scripts without case pass through unchanged (ADR-0018) |
|
||||||
| `series` / `order` | string / int | Series membership and position. Sparse by convention (10, 20, 30) so insertion is one edit; never appears in a URL (ADR-0016) |
|
| `order` | int | Position within the series this bundle is nested in (ADR-0033). Sparse by convention (10, 20, 30) so insertion is one edit; never appears in a URL (ADR-0016). Absent, the bundle orders by name, after every sibling carrying one |
|
||||||
| `cover` | string | Relative path to the lead image |
|
| `cover` | string | Relative path to the lead image |
|
||||||
| `view` | string | Per-bundle View override (Arc 2) |
|
| `view` | string | Per-bundle View override (Arc 2) |
|
||||||
| `styles` / `scripts` | []string | Page-specific assets, relative to the bundle |
|
| `styles` / `scripts` | []string | Page-specific assets, relative to the bundle |
|
||||||
@@ -152,19 +152,35 @@ path — `/pages/about/` and `/bn/pages/about/`. `/en/…` permanently redirects
|
|||||||
never live.
|
never live.
|
||||||
Emit `hreflang` and `canonical` from the variants that actually exist.
|
Emit `hreflang` and `canonical` from the variants that actually exist.
|
||||||
|
|
||||||
## Sequences, galleries, collections `[spec]`
|
## Sequences
|
||||||
|
|
||||||
All of these are a Query over bundle metadata with a stable sort; none justifies a new primitive.
|
Comics, serial fiction and multi-part essays all reduce to a sequence, which is why it is the one
|
||||||
|
grouping with a name (ADR-0016).
|
||||||
|
|
||||||
A **sequence** is the one that needs naming, because comics, serial fiction and multi-part essays all
|
**Membership is structural** (ADR-0033): a bundle belongs to the series it is nested under, so
|
||||||
reduce to it (ADR-0016). Membership is `series`; position is whatever the type declares as its `order`
|
`comics/the-long-monsoon/first-rain` is a chapter of `comics/the-long-monsoon`. The engine reads no
|
||||||
rule — date, sequence, or manual. Position lives in frontmatter, sparse, and never in the path, so
|
`series` field. A bundle with bundles nested under it is a landing page and they are its members; a
|
||||||
inserting a chapter between two others is a single edit with no renames, no changed bundle keys and no
|
landing page nested inside another series reports its own members rather than its siblings, since the
|
||||||
aliases. Resolution — first, prev, next, last, index, count — is defined once, honours `draft`, and
|
deeper series is what the page is about. Membership therefore rides on the bundle key, which is permanent
|
||||||
respects the language fallback chain, so a missing Bengali chapter does not break Bengali prev/next.
|
— re-parenting a chapter changes its URL and needs an alias like any other move.
|
||||||
|
|
||||||
A gallery is a Query plus an image View. Related posts are a Query with a scoring function, not a stored
|
**Order is `order` ascending where set, then by name.** A member without `order` sorts after every member
|
||||||
graph. Pagination is a Query parameter plus a permalink rule for page 2+, still undecided.
|
carrying one, the same way an undated bundle sorts after dated ones. Position lives in frontmatter, sparse
|
||||||
|
by convention, and never in the path, so inserting a chapter between two others is a single edit with no
|
||||||
|
renames, no changed keys and no aliases.
|
||||||
|
|
||||||
|
Resolution — first, prev, next, last, index, count — is defined once, and members resolve through the
|
||||||
|
language fallback chain, so a chapter missing in Bengali still appears in Bengali reading order rather
|
||||||
|
than breaking prev/next. Reading order is *ascending*, the opposite of a dated listing: a sequence's
|
||||||
|
"prev" is the earlier entry.
|
||||||
|
|
||||||
|
`draft` is not honoured yet, because no bundle carries it and nothing else excludes drafts either; the
|
||||||
|
feature that adds the field adds it here in the same change.
|
||||||
|
|
||||||
|
## Galleries, collections `[spec]`
|
||||||
|
|
||||||
|
Both are a Query over bundle metadata with a stable sort; neither justifies a new primitive. A gallery is
|
||||||
|
a Query plus an image View. Related posts are a Query with a scoring function, not a stored graph.
|
||||||
|
|
||||||
## Taxonomies `[spec]`
|
## Taxonomies `[spec]`
|
||||||
|
|
||||||
|
|||||||
+19
-1
@@ -161,7 +161,7 @@ boundary must route through the normaliser rather than accepting a raw string.
|
|||||||
Revisit if: never for normalisation. Slug derivation rules change with the default locale.
|
Revisit if: never for normalisation. Slug derivation rules change with the default locale.
|
||||||
|
|
||||||
## ADR-0016 — Sequence position is metadata and never appears in a URL
|
## ADR-0016 — Sequence position is metadata and never appears in a URL
|
||||||
Date: 2026-07-28 · Status: accepted
|
Date: 2026-07-28 · Status: accepted; its membership clause is superseded by ADR-0033 (position rules stand)
|
||||||
Decision: a bundle's slug is its name, never its position — `comics/the-long-monsoon/the-flood/`, not
|
Decision: a bundle's slug is its name, never its position — `comics/the-long-monsoon/the-flood/`, not
|
||||||
`.../02-the-flood/`. Position comes from a single declared source per type (`order` in the type
|
`.../02-the-flood/`. Position comes from a single declared source per type (`order` in the type
|
||||||
declaration: date, sequence, or manual), sparse by convention (10, 20, 30) so inserting between two
|
declaration: date, sequence, or manual), sparse by convention (10, 20, 30) so inserting between two
|
||||||
@@ -384,3 +384,21 @@ caller is what earned `Query.Tag` rather than a guess. Expensive — tag hygiene
|
|||||||
since nothing scopes terms, so `check` owes a near-duplicate report; and `tags` is now reserved at the top
|
since nothing scopes terms, so `check` owes a near-duplicate report; and `tags` is now reserved at the top
|
||||||
level and inside every section.
|
level and inside every section.
|
||||||
Revisit if: the pool becomes unusable in practice — and then the answer is curation, not namespacing.
|
Revisit if: the pool becomes unusable in practice — and then the answer is curation, not namespacing.
|
||||||
|
|
||||||
|
## ADR-0033 — Series membership is structural; `order` is optional
|
||||||
|
Date: 2026-07-30 · Status: accepted (supersedes ADR-0016's membership clause, not its position rules)
|
||||||
|
Decision: a bundle is a member of a series because it is nested under the series' landing bundle —
|
||||||
|
`comics/the-long-monsoon/first-rain` under `comics/the-long-monsoon` — so the engine reads no `series`
|
||||||
|
field. Reading order is `order` ascending where it is set, then by key; a member without `order` sorts
|
||||||
|
after every member that has one. A bundle with bundles nested under it is a series landing page, and one
|
||||||
|
nested inside another series reports its own members rather than its siblings.
|
||||||
|
Why: the directory already states membership unambiguously, and a second statement of it in frontmatter
|
||||||
|
can only agree or be a bug — a typo in `series` silently orphans a chapter, which is precisely the class
|
||||||
|
of error a single source of truth removes. Making `order` optional keeps the cheap case cheap: a series
|
||||||
|
whose filenames already sort correctly needs no frontmatter at all, and `order` is for when they do not.
|
||||||
|
Consequence: cheap — nothing to declare, nothing to keep in sync, and moving a series moves its
|
||||||
|
membership with it. Expensive — a series can never span directories, so a cross-directory collection
|
||||||
|
needs a Query over some other field, not this; and membership now depends on the bundle key, which
|
||||||
|
ADR-0008 makes permanent, so re-parenting a chapter is a permalink event with an alias.
|
||||||
|
Revisit if: a real collection must span sections. Then it is a declared taxonomy (ADR-0032's second
|
||||||
|
half), not a change to how a series is joined.
|
||||||
|
|||||||
Reference in New Issue
Block a user