Files
khosra/scripts/surface.sh
T
bdeshiandClaude Opus 5 ec6e9838f0 rename docs/ to harness/, and reserve docs/ for the reader
docs/content-model.md opens with "Engine specification". It is also where the
rule lives that a leading underscore makes a file unaddressable — and the human
who owns this site did not know that rule, because nothing in this repository is
addressed to an author. Twelve documents named docs/ while being exclusively
about building the parser is a signpost pointing at the wrong room.

Naming the directory for its audience makes the gap visible instead of hiding it.
docs/ is now reserved and deliberately absent: an empty docs/ is an honest
statement that end-user documentation does not exist, where docs/ full of parser
specs was a claim that it did.

HARNESS.md stays at the root. Root holds the three entry points — README.md for a
human, CLAUDE.md for an agent, HARNESS.md for whoever maintains the machine — and
harness/README.md is the map of the directory, so moving the guide inside would
have collided with it for nothing.

Mechanical and wide: 100 path references across 24 files. Every verify.sh gate
that names a doc by path, the directory lists the dangling-path and ADR-number
gates scan, surface.sh's output target, the Makefile, CLAUDE.md's read order, the
skill, four commands, and two Go package comments. A first pass with a shell loop
silently edited only four files and the rest still said docs/; the fix was to
write the file list out and check the remaining count was zero rather than trust
the loop's exit status.

No rule, threshold, gate or obligation moved — this is a rename, and the gates
demonstrated it twice: they stayed green on the new paths, and the ADR-number gate
caught ADR-0082 before the entry existed.

Deferred, both on the human's call: the end-user documentation site itself, which
wants its own decision about where it lives and whether its claims are gated; and
moving examples/ under docs/, since demo-site is a live site root that verify.sh,
the coverage test and make demo all point at, and moving it would couple a rename
to a design nobody has made.

31 files, +146/-106.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 20:11:06 +06:00

56 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Generates the compressed form of the code: every package, its size, and every top-level declaration
# with the line to jump to.
#
# Usage: scripts/surface.sh print it
# scripts/surface.sh --write regenerate harness/surface.md (`make surface`)
#
# Why this exists: reading a 400-line file to learn what is in it costs forty times what reading its
# surface costs, and the answer to "where does X live" is almost never in the bodies. `go doc` already
# does this for *exported* identifiers; this also covers unexported ones, which is where most of khosra
# lives — nothing outside cmd/ has many exported names by design.
#
# Generated, never hand-edited, and gated: verify.sh regenerates and compares, so a stale surface fails
# the build rather than misleading a reader. Purposes and intent stay in harness/state.md — this file is
# mechanical and says only what is there.
set -uo pipefail
cd "$(dirname "$0")/.." || exit 1
emit() {
printf '# Surface\n\n'
printf 'Generated by `scripts/surface.sh` — do not edit. Regenerate with `make surface`.\n\n'
printf 'Every top-level declaration in the engine, with its line. Read this before opening a source\n'
printf 'file: it answers "where does X live" and "what is in this package" without the bodies. What each\n'
printf 'file is *for* lives in `state.md`; why it is that way lives in `decisions.md`.\n'
git ls-files '*.go' | grep -v '_test\.go$' | xargs -n1 dirname | sort -u | while read -r dir; do
files=$(git ls-files "$dir/*.go" | grep -v '_test\.go$' | sort)
[ -z "$files" ] && continue
tests=$(git ls-files "$dir/*_test.go" | sort)
code=$(echo "$files" | xargs wc -l | awk '$2!="total"{t+=$1} END{print t+0}')
testloc=0
[ -n "$tests" ] && testloc=$(echo "$tests" | xargs wc -l | awk '$2!="total"{t+=$1} END{print t+0}')
printf '\n## %s — %s lines' "$dir" "$code"
[ "$testloc" -gt 0 ] && printf ' + %s test' "$testloc"
printf '\n\n'
# One manifest line per package, so the cost of opening any file is visible before you open it.
echo "$files" | while read -r f; do printf '%s %s · ' "$(basename "$f")" "$(wc -l <"$f" | tr -d ' ')"; done |
sed 's/ · $//'
printf '\n\n'
for f in $files; do
# Top-level declarations only: in gofmt'd Go those are exactly the lines starting in column one.
# The trailing brace and any body opener go, so a signature reads as one line.
grep -nE '^(func|type|const|var) ' "$f" |
sed -e 's/ {$//' -e 's/ ($//' -e 's/[[:space:]]*$//' |
awk -F: -v n="$(basename "$f")" '{ line = $1; $1 = ""; sub(/^:/, ""); sub(/^ +/, ""); printf "- %s:%s %s\n", n, line, $0 }'
done
done
}
if [ "${1:-}" = "--write" ]; then
emit >harness/surface.md
printf 'wrote harness/surface.md (%s lines)\n' "$(wc -l <harness/surface.md | tr -d ' ')"
else
emit
fi