Files
serverAppConfigs/tests/docs_completeness.bats
T
Frank 846f81ddb8 docs(vault): the work log keeps incidents and laws; the numbers move to the page that owns them
log.md drops 466 lines of per-swap ledger prose (1,169 lines out, 703 back) and
keeps the causal stories: why the host went down, why a knob resets at boot, why
a stale drop-in served a different model for 24 minutes, why the RAM was the
fault. Date sections are unchanged (65 before, 65 after) -- this is compression
inside sections, not deletion of days.

Every number the compression would have orphaned was ported to its owner first,
and a census of the deleted lines against the whole vault is what found them:

- frank-zealot: the two boots that priced non-KV (20,190/KV 12,800 => 7,390
  without the projector; 22,972/KV 14,113 => 8,859 with it, so the vision tower
  costs ~1.4 GiB for a 918 MB file), the 1,153 MiB-free 3-slot boot that made
  the seam price non-KV at 9 GiB, and the f16 wall's own figures (fit 33,198 vs
  23,558 free on a 25,088.00 MiB KV request).
- frank-archon: the pool-cut-is-headroom-not-arena law (2.75 GiB/rank bought
  zero slots; d(reserve) = d(arena) = +248 slots; 14.87 GiB / 6,496 slots
  against a 398,658-token pool), the MNBT compile-RANGE vs SEQS+1 law, and the
  2 x 196,919 prefix-cache proof (393,837 tokens resident above the pool's
  386,904; 94.1/102.3/117.6 t/s, acceptance 0.7284/0.7525).
- frank-dragoon: the KL arm of the 2026-10-17 A/B (mean 0.155 / median 0.057,
  top-1 agreement 85.1 %) joins the PPL and NIAH figures already on the era row.
- Payload and Disk Reclaim: the 121 GB layer census lesson -- a huge image layer
  can be the engine image, not a payload.

Also fixes a wikilink the rewrite had hard-wrapped across two lines, which the
link checker reads as a target that does not exist.

New seam: 'one page per live LLM endpoint'. The live set is derived from
scripts/ (an endpoint has both an env and a unit), and any <endpoint>-*.md page
in the vault fails it -- the enforcement of the one-page-per-endpoint law, so a
re-created era page cannot pass tests.
2026-10-19 01:05:32 -07:00

77 lines
3.6 KiB
Bash

#!/usr/bin/env bats
# Seam: documentation completeness.
# Every service defined in a compose.yaml must have a matching documentation
# page in serverAppConfigs-docs/ and must be reachable from the index. This is the "docs first"
# contract of this repo: no service ships without documentation.
# The vault's second law, added 2026-10-18: ONE page per live LLM endpoint.
# A payload swap is an Eras row on that endpoint's page, never a page of its
# own -- a second file holding the same shape is the next thing to go stale.
load helpers
@test "every compose service has a docs page" {
while IFS= read -r f; do
while IFS= read -r svc; do
# service name is the docs slug: RomM -> serverAppConfigs-docs/Dankserver/RomM.md
# matched case-insensitively (vault uses Title Case)
local doc
doc=$(find "$REPO_ROOT/serverAppConfigs-docs" -iname "${svc}.md" 2>/dev/null | head -1)
if [ -z "$doc" ]; then
echo "service '$svc' (from $f) has no docs page: expected serverAppConfigs-docs/**/${svc}.md"
return 1
fi
done < <(services_in "$f")
done < <(find "$REPO_ROOT" -name 'compose.yaml' -not -path '*/.git/*' | sort)
}
@test "docs index links every docs page" {
local index="$REPO_ROOT/serverAppConfigs-docs/index.md"
[ -f "$index" ] || { echo "missing $index"; return 1; }
while IFS= read -r page; do
local base
base=$(basename "$page" .md)
grep -qF "[[$base]]" "$index" || {
echo "docs page $base is not linked from $index"
return 1
}
done < <(find "$REPO_ROOT/serverAppConfigs-docs" -name '*.md' -not -name 'index.md' -not -path '*/.obsidian/*' | sort)
}
@test "no unresolved links in the docs vault" {
# A wikilink to a page that does not exist is a promise the repo cannot
# keep. Fixing the three that were dangling (2026-09-16) also meant
# retiring a reference to dankclaw/compose.yaml, which no longer exists.
# The checker models Obsidian's resolution rules; see its docstring for
# the three false-positive classes a naive version produces.
run "$REPO_ROOT/scripts/check-vault-links.py" "$REPO_ROOT/serverAppConfigs-docs"
[ "$status" -eq 0 ] || { echo "$output"; false; }
}
@test "one page per live LLM endpoint" {
# The live set is derived, not hardcoded: an endpoint is live if scripts/
# holds both its env and its unit (frank-tts has an env but no unit, so it
# is not an inference endpoint; homepage-status is the reverse).
local vault="$REPO_ROOT/serverAppConfigs-docs" derived=0 name extra
for envf in "$REPO_ROOT"/scripts/frank-*.env; do
name=$(basename "$envf" .env)
[ -f "$REPO_ROOT/scripts/$name.service" ] || continue
derived=$((derived + 1))
[ -f "$vault/LLM/$name.md" ] || {
echo "live endpoint '$name' has no canonical page: serverAppConfigs-docs/LLM/$name.md"
return 1
}
extra=$(find "$vault" -name "${name}-*.md" -not -path '*/.AGENTTRASH/*' | sort)
if [ -n "$extra" ]; then
echo "endpoint '$name' owns exactly one page; these files re-create a second owner of its shape:"
echo "$extra"
echo "Fold them into LLM/$name.md (an Eras row plus, if needed, a Law) and trash the page."
return 1
fi
done
# Guard against the derivation going vacuous -- an empty loop passes silently.
[ "$derived" -ge 3 ] || {
echo "expected at least 3 live endpoints derived from scripts/*.env + scripts/*.service, got $derived"
return 1
}
}