give the author three controls the engine was deciding alone

`include: merge` in frontmatter splices a bundle's includes before the parse, so
a page assembled from several files is one document: one footnote list at its
end, numbered straight through, and an abbreviation defined anywhere reaching
every part. Moving the rendered block afterwards would have meant editing
goldmark's own markup; handing the parser one source gets the right answer from
it instead. Without the flag nothing changes — each fragment stays its own
document with namespaced ids, so no existing content re-renders.

Heading ids are unique under either model. Merging gets that free, because one
parse means one id set, but embedding did not: three `## Description`s across a
page and its fragments produced three identical anchors, and every link to them
landed on the first. A nested parse now shares the parent's id set, so the
second becomes #description-1 — goldmark's own suffixing, reaching across files
because they finally share the set it counts in.

Auditing for other policies the author could not reach found two more.

A heading may declare its anchor: `## Title {#stable-anchor}`. This is the one
that mattered most and nobody had asked for it — a derived id changes when the
text does, so rewording a heading silently broke every link to that anchor,
which is indefensible in an engine whose first value is that published addresses
are permanent.

`::toc{depth=2}` shortens a contents list, because a theme cannot know per page
how deep is useful and the author can.

Deliberately not added: a typographer toggle, a per-picture "do not resample",
icon overrides. No second user for any of them.

The hand-copied wiring in example_test.go drifted for the third time this
session — Compose this time, after the dialect and notation — each caught by a
demo case rather than by the copy. The latent row is now marked due, with what
moving the list would require.
This commit is contained in:
Claude Opus 5
2026-08-01 23:08:49 +06:00
committed by bdeshi
parent d1c9179d6c
commit b5be77498e
14 changed files with 353 additions and 97 deletions
+6 -3
View File
@@ -57,6 +57,7 @@ func exampleSite(t *testing.T) http.Handler {
if err != nil {
t.Fatal(err)
}
r.Compose(shortcodes.Merge)
site := content.NewSite(bundles)
r.Navigation(site.Sections)
return Handler(Fixed(site), r, fsys, nil, settings)
@@ -142,9 +143,11 @@ var exampleFeatures = []featureCase{
expect: []string{`<aside class="admonition warn">`, `<p class="admonition-title">Calibration</p>`, "<em>emphasis</em>"},
absent: []string{":::"}},
{what: "a table of contents links the page's own headings", path: "/writing/notes-on-water/", code: 200,
expect: []string{`<nav class="toc">`, `<a href="#readings">Readings</a>`, `class="toc-2"`}},
{what: "a fragment's footnote ids are namespaced, so the page's own keep working", path: "/writing/notes-on-water/", code: 200,
expect: []string{`id="fn:1"`, `id="_method-fn:1"`, `href="#_method-fn:1"`}},
expect: []string{`<nav class="toc">`, `<a href="#gauge-readings">Readings</a>`, `class="toc-2"`}},
{what: "a merging bundle has one footnote list, numbered straight through", path: "/writing/notes-on-water/", code: 200,
expect: []string{`id="fn:1"`, `id="fn:2"`}, absent: []string{"_method-fn:", `class="footnotes"><hr><ol><li id="fn:2"`}},
{what: "a heading may declare an anchor that outlives its wording", path: "/writing/notes-on-water/", code: 200,
expect: []string{`<h2 id="gauge-readings">`, `href="#gauge-readings"`}},
{what: "a page offers its extras only when it has them", path: "/writing/notes-on-water/", code: 200,
expect: []string{`href="/writing/notes-on-water/extras/"`}},
{what: "the extras tree is classified", path: "/writing/notes-on-water/extras/", code: 200,