A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
test/cases/10_site_data.sh
An object of kind test
What it is
- URI
majordomus://test/test/cases/10_site_data.sh- Kind
test- Identity
test/cases/10_site_data.sh- Path
test/cases/10_site_data.sh- Provenance
- declared
- Media type
text/plain- As a capability
- test.test/cases/10_site_data.sh
Front matter
{}Content
# The site data normaliser: canonical files in, stable JSON out, and --check detects drift.
. "$ROOT/test/lib.sh"
command -v jq >/dev/null || skip "jq absent"
fixture_repo "$T" AGENTS.md docs site/data/marketing.toml site/content-src test/cases
git -C "$T" add -A >/dev/null; git -C "$T" commit -qm fixture
expect_exit 0 "$T/scripts/generate-site-data"
for f in project profiles policy capabilities lifecycle docs diagrams source context; do [ -f "$T/site/data/generated/$f.json" ]; jq -e '.schema == 1' "$T/site/data/generated/$f.json" >/dev/null; done
# version comes from the one place it is authored (read by its one shell reader, never parsed
# here), profiles from the skeleton, claims from CLAIMS.yaml
[ "$(jq -r .version "$T/site/data/generated/project.json")" = "$("$ROOT/scripts/release-version")" ]
[ "$(jq '.profiles | length' "$T/site/data/generated/profiles.json")" = "$(ls "$ROOT"/share/skeleton/profiles/*.yaml | wc -l | tr -d ' ')" ]
# count the claims section only: docs/CLAIMS.yaml also declares its statuses as `- id:` entries
[ "$(jq '.claims | length' "$T/site/data/generated/capabilities.json")" = "$(awk '/^claims:/{c=1;next} c&&/^ - id: /{n++} END{print n+0}' "$ROOT/docs/CLAIMS.yaml")" ]
jq -e '.claims | all(.status == "guaranteed" and .test == null | not)' "$T/site/data/generated/capabilities.json" >/dev/null
jq -e '.principles | length >= 8' "$T/site/data/generated/lifecycle.json" >/dev/null
# the directory contracts: every directory of the layer is present with the verdict
# validation reached, and none of them owes a contract it does not have (ADR 0011)
jq -e '.counts.directories == (.directories | length) and .counts.documented > 0' "$T/site/data/generated/context.json" >/dev/null
jq -e '[.directories[] | select(.document == null and .requires_contract)] | length == 0' "$T/site/data/generated/context.json" >/dev/null
jq -e '[.directories[] | select(.contract != null and .contract.children_require_contract == false)] | length > 0' "$T/site/data/generated/context.json" >/dev/null
jq -e '.diagrams.lifecycle.mermaid | contains("no_match")' "$T/site/data/generated/diagrams.json" >/dev/null
# derived content exists, has front matter, and projected GitHub-native syntax
# CLI.md is projected under a slug of its own: /docs/cli/ is the per-command tree, so the
# specification cannot also live there (doc_slug, CLI_SPEC_SLUG in the generator)
expect_file "$T/site/content/docs/cli-specification.md"
expect_grep '^source = "docs/CLI.md"' "$T/site/content/docs/cli-specification.md"
# the table wrapper scrolls, so it is in the tab order: a scrolling region only a pointer can
# reach is what project.ui-conformance refuses (WCAG 2.1.1)
expect_grep '<div class="overflow-x-auto" tabindex="0">' "$T/site/content/docs/cli-specification.md"
# --check passes when in sync, fails after a canonical edit
expect_exit 0 "$T/scripts/generate-site-data" --check
sed -i.bak 's/^effort: high$/effort: xhigh/' "$T/share/skeleton/profiles/debugging.yaml"; rm -f "$T/share/skeleton/profiles/debugging.yaml.bak"
expect_exit 10 "$T/scripts/generate-site-data" --check
expect_grep 'STALE site/data/generated/profiles.json'
# a guaranteed claim without a test is refused
git -C "$T" checkout -q -- share
python3 - "$T/docs/CLAIMS.yaml" <<'PY'
import sys,re; p=sys.argv[1]; s=open(p).read()
s=s.replace(" test: test/cases/01_init.sh\n status: guaranteed"," test: '-'\n status: guaranteed",1); open(p,'w').write(s)
PY
expect_exit 10 "$T/scripts/generate-site-data"
expect_grep 'guaranteed claim .* has no test'
# a claim whose status is not one the file declares under `statuses` is refused, by id and word
git -C "$T" checkout -q -- docs
python3 - "$T/docs/CLAIMS.yaml" <<'PY'
import sys; p=sys.argv[1]; s=open(p).read()
s=s.replace(" test: test/cases/01_init.sh\n status: guaranteed"," test: test/cases/01_init.sh\n status: proven",1); open(p,'w').write(s)
PY
expect_exit 10 "$T/scripts/generate-site-data"
expect_grep 'carry a status docs/CLAIMS.yaml does not declare under statuses: .*[(]proven[)]'
# --- doctrines.json: the chain is resolved from the source, not copied from the rule objects
git -C "$T" checkout -q -- docs share
"$T/scripts/generate-site-data" >/dev/null
D="$T/site/data/generated/doctrines.json"
[ "$(jq '.doctrines | length' "$D")" = "$(grep -l '^ validator:' "$ROOT"/share/standard/majordomus/rules/*.md | wc -l | tr -d ' ')" ]
[ "$(jq '.counts.declared' "$D")" = "$(jq '.doctrines | length' "$D")" ]
[ "$(jq '.counts.blocking + .counts.advisory' "$D")" = "$(jq '.counts.declared' "$D")" ]
# every doctrine names the file that actually defines its validator
jq -r '.doctrines[] | [.validator_function, .defined_in] | @tsv' "$D" | while IFS="$(printf '\t')" read -r fn file; do
grep -qE "^$fn\(\)" "$T/$file" || { echo " $file does not define $fn"; exit 1; }
done
# every URL slug is derived from the id, and every class is one of two
jq -e '.doctrines | all(.slug == (.id | ltrimstr("majordomus.")))' "$D" >/dev/null
jq -e '.doctrines | all(.class == "blocking" or .class == "advisory")' "$D" >/dev/null
# a doctrine naming a validator nobody wrote does not reach the site
sed 's/^ validator: scope$/ validator: not_implemented/' "$ROOT/share/standard/majordomus/rules/scope-integrity.v1.md" > "$T/share/standard/majordomus/rules/scope-integrity.v1.md"
expect_exit 10 "$T/scripts/generate-site-data"
expect_grep "names validator 'not_implemented'"
# nor does one declared for a command that never dispatches
git -C "$T" checkout -q -- share
sed 's/^ enforced_by: \[doctor\]$/ enforced_by: [update]/' "$ROOT/share/standard/majordomus/rules/enforcement-wiring.v1.md" > "$T/share/standard/majordomus/rules/enforcement-wiring.v1.md"
expect_exit 10 "$T/scripts/generate-site-data"
expect_grep "declared for 'update', which does not dispatch"
# nor a validator in lib/ that no doctrine declares
git -C "$T" checkout -q -- share
printf '\nmj_validate_unclaimed() { return 0; }\n' >> "$T/lib/check.sh"
expect_exit 10 "$T/scripts/generate-site-data"
expect_grep 'mj_validate_unclaimed, which no doctrine declares'
# ---------------------------------------------------------------- nothing reader-relative
# `session list` labels every record by its divergence from *this* worktree and branch, so
# the same record labels itself `diverged` here and `different_context` on a CI checkout.
# A published projection may only carry what the record says about itself: baked in, the
# label makes the dataset a fact about the machine that generated it, and --check then
# fails on every other one. This is the defect, from the artifact the repository ships.
S="$ROOT/site/data/generated/sessions.json"
if [ "$(jq -r '.count' "$S")" -gt 0 ]; then
"$ROOT/bin/majordomus" --repo "$ROOT" session list --all --json \
| jq -e '.sessions | length > 0 and all(has("label"))' >/dev/null \
|| { echo " session list no longer labels its records; this assertion needs rewriting"; exit 1; }
jq -e '.sessions | all(has("label") | not)' "$S" >/dev/null \
|| { echo " the published sessions dataset carries the reader-relative label"; exit 1; }
fi