- SourceRefs trigger whitelist aligned to the /source/ serving
whitelist (drops content/, yaml-source/, broad static//tools//data
prefixes; adds .bib); existsCached no longer memoizes non-existence,
so files created under make watch are picked up (§2.5, §2.16)
- fill/stroke hex replacement is boundary-aware: #000080 and 8-digit
RGBA forms can no longer be corrupted into currentColor80 (§2.12)
- Wikilinks/Transclusion/EmbedPdf skip fenced code blocks (shared
CommonMark fence tracker), and wikilinks additionally skip inline
code spans — the syntax-documentation essay now renders its own
examples literally while live wikilinks still convert (verified both
ways in output) (§2.13)
- domainIcon matches the extracted host by label suffix instead of
substring-of-URL; extractHost also strips userinfo (§2.14)
- webpSrc escaped in srcset; internal PDF links no longer double-
classified; Smallcaps/Archive header-skip now holds at every nesting
depth via protect/restore walks (§2.17)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The filter consumes every Pandoc Note, so the "standard Pandoc-
generated section.footnotes" its doc claimed as the no-JS fallback
never existed — below 1500px with JS disabled, footnote content was
simply invisible (AUDIT §2.3). The filter now collects consumed notes
and appends the section itself: letter labels, jump targets for the
in-text refs (which now point at the visible fallback item), and
doc-backlink returns. sidenotes.js pairs ref/note by element id and
preventDefaults clicks, so behavior with JS is unchanged.
Verified in output: per-page item count matches inline sidenote count;
refs target #fn-<label>; backlinks target #snref-<label>.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Backlinks: handle Plain blocks (tight list items) and DefinitionList
in link extraction — links in ordinary bullet lists were invisible to
the backlinks system (AUDIT §3.3)
- Sidenotes: render note bodies with a KaTeX writer so footnote math
reaches the client-side KaTeX pass instead of degrading to italics
(§2.4)
- Archive: join manifest to provenance on normalised URLs like every
other comparison in the system — an equivalent-form URL edit silently
unpublished the page while links kept pointing at it (§3.6)
- Photography: flat singles get their basename as slug and root-level
asset paths in map.json (§3.7); geo-precision now fails closed — an
unrecognised value (typo'd "hidden") suppresses the pin instead of
publishing rounded coordinates (§3.8)
- Stability: age is measured first-commit -> today, not the commit
span, so quiet time stabilises a piece as documented (§3.4);
history: entries are sorted newest-first by date regardless of
authored order (§3.5); pinned pages format last-reviewed like the
git branch (§3.10)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Preserve external works the site cites against link rot, host them at
permanent /archive/<slug>/ URLs in site chrome, and treat them as
first-class citizens of the backlinks and similar-pages indexes.
Curated, not crawled: the author adds one line to archive/manifest.yaml
and the build fetches, hashes, snapshots, and indexes the work.
* archive/manifest.yaml + tools/archive.py (fetch / refresh / wayback /
check / gc) — PDFs downloaded directly, HTML pages snapshotted with a
vendored monolith (tools/bin/monolith @ 2.10.1) into a single
self-contained file with the archive CSP and a noarchive robots meta
injected. Per-entry PROVENANCE.json committed; gitignored .txt
sidecars regenerated from the artifact's SHA-256.
* build/Archive.hs + build/ArchiveIndex.hs + build/Filters/Archive.hs
— Hakyll rules for /archive/ and /archive/<slug>/, a body Pandoc
filter that appends an archive affordance to live citations and
flips dead ones to the local copy on archive.py check's asymmetric
hysteresis (rotted needs 3 fails over >= 14 days; one ok recovers).
* build/Backlinks.hs — keeps archived external URLs through pass 1 and
canonicalises them to /archive/<slug>/ in pass 2, producing a
"Referenced by" section grouped by the fragment each citation
targets. build/Stats.hs gains a "Link archive" telemetry block on
/build/ (count, total size, median age, by-status / by-quality /
by-visibility, orphans).
* Integrity: archive.py fetch and build/Archive.hs (via sha256sum)
both re-hash every committed artifact, so a tampered file halts the
build even with cabal invoked directly or no .venv present. refresh
refuses to replace an uncommitted prior snapshot and rolls back
atomically on any exit path. removed.yaml is honoured by fetch,
wayback, and check using canonical-form (tracking-stripped,
arXiv-canonicalised) comparison.
* visibility: private keeps an entry in-repo but undeployed.
nginx/archive.conf emits X-Robots-Tag: noindex, noarchive for raw
artifacts that cannot carry meta directives.
The full design, phase plan (1-5), and three refinement passes live
in ARCHIVE.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>