feat(11.1-02): check links, commands, forbidden names and fence policy

- relative links and anchors resolve against the renderer's heading IDs
- summer and ./bin/<app> command names come from the real command
  constructors through docsite.Options.Commands; a nil set is a problem
- consuming-application names fail in page sources and built outputs
- go fences in docs/ pages need src=, callouts are NOTE, TIP or WARNING,
  docs/ headings are plain ASCII
- gate gains --claude and self-test plants for each new rule
This commit is contained in:
Jakub Zych
2026-09-30 21:40:46 +02:00
parent f4605292b5
commit 5d4c1e3046
12 changed files with 808 additions and 14 deletions

View File

@@ -29,6 +29,7 @@ usage:
check-phase11.1.sh --deps
check-phase11.1.sh --docs
check-phase11.1.sh --forbidden
check-phase11.1.sh --claude
check-phase11.1.sh --self-test
check-phase11.1.sh --go
check-phase11.1.sh --all
@@ -118,6 +119,24 @@ run_forbidden() {
echo "phase11.1 forbidden passed"
}
# The D-13 / DOCS-08 rules CLAUDE.md's Documentation section must carry.
CLAUDE_RULES=(
'also updates the affected pages under `docs/` in the same change'
'`go test ./cmd/summer -run TestDocsTree` and `summer docs:build --check` check identifiers'
'Every identifier named in a README or a docs page must exist in the package.'
'Config keys named in README or docs pages are not checked automatically yet'
)
run_claude() {
local section rule
section="$(awk '/^## Documentation$/{on=1; next} /^## /{on=0} on' "$ROOT/CLAUDE.md")"
[ -n "$section" ] || refuse "CLAUDE.md has no Documentation section"
for rule in "${CLAUDE_RULES[@]}"; do
grep -Fq -- "$rule" <<<"$section" || refuse "CLAUDE.md Documentation section is missing: $rule"
done
echo "phase11.1 claude passed"
}
run_go() {
(cd "$ROOT" && go vet ./...)
(cd "$ROOT" && go test ./...)
@@ -176,6 +195,27 @@ run_self_test() {
expect_refusal 'frontmatter typo' 'frontmatter: unknown field' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/setup/installation.md
printf '\nSee [nowhere](#no-such-anchor).\n' >>"$scratch/docs/index.md"
expect_refusal 'broken anchor' 'link: #no-such-anchor not found in' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/index.md
printf '\nRun `summer no:such`.\n' >>"$scratch/docs/index.md"
expect_refusal 'unknown command' '"no:such" is not a summer or application command' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/index.md
# Built from two halves so this script's plant is not itself a hit.
printf '\nThe %s%s application.\n' 'fono' 'teka' >>"$scratch/docs/index.md"
expect_refusal 'forbidden name' 'forbidden: consuming-application name in output' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/index.md
printf '\n```go\nx := 1\n```\n' >>"$scratch/docs/index.md"
expect_refusal 'go fence without src=' 'snippet: go code block has no src= reference' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/index.md
printf '\n> [!DANGER]\n> Planted.\n' >>"$scratch/docs/index.md"
expect_refusal 'unknown callout' 'callout: unknown type DANGER (use NOTE, TIP or WARNING)' "$summer" "$scratch"
restore "$pristine" "$scratch" docs/index.md
echo "phase11.1 self-test passed"
}
@@ -184,6 +224,7 @@ case "${1:-}" in
--deps) run_deps ;;
--docs) run_docs ;;
--forbidden) run_forbidden ;;
--claude) run_claude ;;
--self-test) run_self_test ;;
--go) run_go ;;
--all)
@@ -192,6 +233,7 @@ case "${1:-}" in
run_self_test
run_docs
run_forbidden
run_claude
run_go
echo "phase11.1 all passed"
;;