First real commit of site/. Until now outreach/.git tracked exactly one file
(README.md) and every content pack stamped git_sha=5619a40 regardless of what it
shipped — a signature with no provenance behind it. The site had no witness, which
is why a deploy could erase two sessions of work with nothing to diff against and
nothing to restore from.
Tracked here (authored): site/content, site/config, site/i18n, site/public/images,
justfile, scripts/, .just/, run*.sh, rustelo.manifest.toml.
Ignored (reproducible, or secret):
.k, .env real keys — outreach mirrors to a PUBLIC remote
site/r, site/public/r content indexes, rebuilt by `just content`
provisioning/.content-packs 228 MB of deploy tarballs
cache, data, logs_*.out runtime droppings
Three trees are deliberately NOT ignored despite looking generated, because their
declared source cannot currently reproduce them — ignoring them would delete the
only copy:
site/public/images 196 of 209 images exist nowhere else (assets/site is empty)
site/content/{adr,catalog} projections whose generators are unwired (gen-adr-pages)
site/content/domains or failing (`just graph`)
They become ignorable when an audit proves regeneration is a no-op, not before.
Fixes carried in this import
---------------------------
content: the mirror ran one way and reverted its own work. content_processor writes
site/r, but the recipe ended with `rsync -a site/public/r/ -> site/r/`, so each fresh
index was clobbered by the stale deploy-tree copy: the tool reported "index.json with
69 posts" while the disk kept 58. Meanwhile public/r is the tree the deploy pack ships,
so no new content could ever reach production. The two trees own different files, so
the mirror now runs both ways: content indexes r -> public/r (with --delete, or a
renamed slug survives as a live URL), and the four nu artifacts (about, adr-map,
taglines, content_graph) back public/r -> r, excluded from the outbound leg so stale
copies cannot overwrite the fresh originals.
templates: the assembler has two layers (framework defaults, source-project templates)
but the level chain has three (rustelo -> website-htmx-rustelo -> outreach/site). The
site level had no overlay slot, so its template work had nowhere legitimate to live and
ended up in htmx-templates/ — the one tree `just templates` rm -rf's. That is how the
nav submenus were lost. site/templates-overlay/ is the missing third slot; 214 lines
(nav submenus, subscribe CTA, post engagement block) now live in a declared source and
survive regeneration byte-identical.
adr: projected ADR-059..069 into the content tree. They were written months ago and
never reached the site because gen-adr-pages.nu is wired into no recipe — a generator
outside the dependency chain is a generator that does not run.
Gates added
-----------
templates-check reassembles into a temp tree and asserts an empty diff against the
live one: any drift means htmx-templates/ holds work that exists
live one: any drift means htmx-templates/ holds work that exists
nowhere else and the next run deletes it.
Both gates run before the destructive operation, not after. A check you can only run
afterwards is not a gate, it is an autopsy.
Refs: ADR-062 (projection-not-own-repo: site is a Projection of outreach, not its own
repo — different deploy target is not a different visibility boundary), ADR-048
(materialization), ADR-066 (the check decides, never the reporter — which the content
pipeline, the surface that publishes ontoref, was the last place not to honour).
84 lines
3.4 KiB
Text
84 lines
3.4 KiB
Text
#!/usr/bin/env nu
|
|
|
|
# Linkify ADR mentions in outreach/web/src/*.html.
|
|
#
|
|
# Two passes per file:
|
|
# 1. Fix href format: absolute https://ontoref.dev/adr/adr-NNN → site-relative /adr/NNN
|
|
# 2. Wrap plain ADR-NNN text (not already inside <a ...>...</a>) with a link
|
|
#
|
|
# All hrefs use site-relative paths (/adr/NNN) so links work in both localhost
|
|
# and production without domain changes.
|
|
# Single-quotes are used for injected href/title/class attributes so the link
|
|
# is safe inside both text nodes and double-quoted data-en/data-es attributes.
|
|
#
|
|
# Usage (from outreach/site):
|
|
# nu scripts/build/linkify-adrs.nu
|
|
# nu scripts/build/linkify-adrs.nu --map site/public/r/adr-map.json --web ../../outreach/web --daemon https://ontoref.dev
|
|
|
|
def escape-attr [s: string] {
|
|
$s
|
|
| str replace --all '&' '&'
|
|
| str replace --all '<' '<'
|
|
| str replace --all '>' '>'
|
|
| str replace --all "'" '''
|
|
| str replace --all '"' '"'
|
|
}
|
|
|
|
def main [
|
|
--map: string = "site/public/r/adr-map.json"
|
|
--web: string = "../../outreach/web"
|
|
--daemon: string = "https://ontoref.dev" # used only to recognise existing absolute hrefs to fix
|
|
] {
|
|
let adr_map = (open $map)
|
|
let web_dir = ($web | path expand)
|
|
let src_dir = ($web_dir | path join "src")
|
|
|
|
if not ($src_dir | path exists) {
|
|
error make { msg: $"src dir not found: ($src_dir)" }
|
|
}
|
|
|
|
let files = (glob $"($src_dir)/*.html" | sort)
|
|
mut total_files = 0
|
|
mut total_changes = 0
|
|
|
|
for f in $files {
|
|
mut content = (open --raw $f)
|
|
let original = $content
|
|
|
|
# Sort ADRs longest-id-first so adr-010 doesn't shadow adr-0100 (hypothetical),
|
|
# and to process higher numbers first (safer for text replacement ordering).
|
|
let adrs = ($adr_map | transpose key val | sort-by key --reverse)
|
|
|
|
for entry in $adrs {
|
|
let id = $entry.key # "adr-009"
|
|
let val = $entry.val
|
|
let num = ($id | str replace 'adr-' '') # "009"
|
|
let adr_upper = $"ADR-($num)" # "ADR-009"
|
|
let path = $"/adr/($num)" # "/adr/009" — site-relative, works everywhere
|
|
let safe_name = (escape-attr ($val.name? | default ""))
|
|
|
|
# Pass 1: fix existing absolute hrefs to the canonical site-relative path.
|
|
# Handles double-quoted (original manual links) and single-quoted (injected links).
|
|
$content = ($content | str replace --all $"href=\"($daemon)/adr/($id)\"" $"href=\"($path)\"")
|
|
$content = ($content | str replace --all $"href=\"($daemon)/adr/($num)\"" $"href=\"($path)\"")
|
|
$content = ($content | str replace --all $"href='($daemon)/adr/($id)'" $"href='($path)'")
|
|
$content = ($content | str replace --all $"href='($daemon)/adr/($num)'" $"href='($path)'")
|
|
|
|
# Pass 2: linkify plain ADR-NNN not already followed by </a>
|
|
# Uses single-quote attrs: safe inside double-quoted HTML attribute values.
|
|
let link = $"<a href='($path)' title='($safe_name)' class='adr-ref' target='_blank' rel='noopener'>($adr_upper)</a>"
|
|
let pattern = $"ADR-($num)\(?!</a>\)"
|
|
$content = ($content | str replace --all --regex $pattern $link)
|
|
}
|
|
|
|
if $content != $original {
|
|
$content | save -f $f
|
|
let linked_after = ($content | find --regex "ADR-[0-9]{3}</a>" | length)
|
|
print $" ($f | path basename): updated"
|
|
$total_files = ($total_files + 1)
|
|
$total_changes = ($total_changes + 1)
|
|
}
|
|
}
|
|
|
|
print $"linkify-adrs: ($total_files) files updated"
|
|
}
|