Context

examples/ holds seven complete records. They were excluded from this project’s site (site.exclude = ["examples/**"]), so the worked configurations this repository argues from were the one part of it a reader could not browse. Each could be staged on its own — LURIA_ROOT=$PWD luria site — but nothing published them, and the exclusion read as though it could not be done.

The obvious repair, dropping the exclusion, is wrong, and the reason is the rule publishable() turns on:

A source that renders into a view is not published; the view is.

That test is Config.link_base(path) != path.parent, and it answers from the reading config’s schemes. Under this project’s config an example’s VALUE-001.md has no scheme to belong to, so link_base falls back to the file’s own directory and the file reads as ordinary prose. The parent would publish the fragment and docs/values.md, the view it renders into — and the views are not committed, so what it published would be whatever a contributor’s working tree happened to hold.

Measured before the change, under the root config:

examples/constitution/record/values.d/VALUE-001.md
    link_base=…/record/values.d  own_dir=…/record/values.d  PUBLISHED IN PLACE

Decision

A new key, site.include_records, listing directory globs. Each match that holds its own luria.toml is staged by that config into a temporary vault, and only the finished content/ is mounted under the parent’s, at the child’s own path.

Three properties follow, and each is a deliberate choice rather than a consequence:

The parent skips a nested record’s files entirely. include_records implies exclusion from the parent’s own pass — otherwise the merge reintroduces exactly the problem above. Naming the same directory in exclude is unnecessary and would be a second place to keep in step.

The child is generated in a copy, never in place. A nested record’s views are not committed, so they must be rendered before they can be staged, and rendering them into the working tree would create the stale committed view the arrangement exists to avoid.

One level only. A child’s own include_records is not honoured. One level is a section; two is a maze, and nothing needs it. Stated in the code because the absent recursion would otherwise look like an oversight.

Switching the reading config is done through config.rooted(), a bounded context manager that restores the previous LURIA_ROOT including its absence. load(root) alone is not enough: the modules underneath — doc_refs.link_base, edges.graph, the renderers — call current() for themselves by design, and threading a config through every call site would be its own mess. The honest move is to name the global switch and bound it, not to have callers set an environment variable and hope.

Consequences

The seven examples publish as sections of this site, 103 pages growing to 206. Each keeps its own title, theme derivation, and record lines, because each was staged by the config that knows about it.

A pattern matching no record is an error rather than a silent skip: an empty include is a section of the site that quietly does not exist, which is the failure mode nothing reports. A pattern matching a directory that is not a record is skipped quietly, because examples/* is the natural way to write “every example” and a stray file beside them should not break a publish.

The alternative considered and rejected was a separate Quartz build per record, nested into the output directory. It gives each example a genuinely independent site, at the cost of N more builds, N base_url values to keep correct, and — decisively — no shared link graph: a link from examples/README into an example would be a raw URL the generator knows nothing about, and the search index and graph view would stop at each boundary. The examples exist to be read from the documentation that cites them, so one vault is the shape that serves the reader.

This also means an adopter can publish a monorepo’s several records as one site, which is the general case this repository happened to hit first.

ADR-045’s consequence — “examples/** joins template/** in the site’s exclusions so a sample record is not published beside the real one” — is no longer true. Its body stands as written, which is what a record is for, and this decision is where a reader learns the state changed: the examples are published, under their own configs, precisely so a sample record is not rendered as if it were part of this one. The other half of that paragraph, the two ADR-scheme limits it documented rather than resolved, was already overtaken by ADR-047.