Files
khosra/scripts/verify.sh
T
Claude Opus 5andbdeshi 1f168d973b render the HTML an author writes, and narrow the gate to one call site
Dropping raw HTML was silently destructive. H<sub>2</sub>O rendered as "H2O",
10<sup>6</sup> as "106", <kbd>Ctrl</kbd> as "Ctrl", and khosra check reported
nothing — an author lost meaning with no signal anywhere. Measured on the real
binary before and after.

Invariant 2 already says content from the site root is trusted, so the old gate
was defending the half of the boundary that was never in question while the
untrusted half has no code to defend yet. Chemistry, units, exponents and
keystrokes are what a hard-science site needs and what no Markdown dialect
expresses, so html.WithUnsafe() goes on in internal/render/render.go.

The gate does not disappear; it narrows. verify.sh used to fail on WithUnsafe
appearing anywhere and now fails unless it appears in exactly that one file —
watched doing both, accepting one call site and naming both files when a second
appears. A second pipeline trusting its input is the failure ADR-0003 exists to
prevent, and when comments arrive they get their own goldmark without it. The
gate is the reminder that the split has to be built rather than assumed.

The security test that asserted "raw HTML must still be dropped" now asserts the
property that actually holds and matters more: a shortcode argument stays data
whatever the page around it is allowed to do. ::figure{alt=<b>bold</b>} still
arrives as &lt;b&gt; while the <span> beside it renders.

core 2793/2800, ext 1077/2000, 34 gates green, 0 warnings.
2026-08-01 21:08:06 +06:00

468 lines
22 KiB
Bash
Executable File

#!/usr/bin/env bash
# The objective gate. No opinions, only exit codes.
# Usage: ./scripts/verify.sh [--quiet|--list]
set -uo pipefail
# --list answers "does this gate actually exist?" without reading the script. Docs that claim a gate are
# checkable against it. The pattern is written pas[s] so this grep does not match its own source line.
if [ "${1:-}" = "--list" ]; then
printf 'gates in %s:\n' "$0"
grep -oE 'pas[s] "[^"]+"' "$0" | awk -F'"' '{print $2}' |
sed 's/\$([^)]*)/…/g; s/\$[A-Za-z_][A-Za-z_0-9]*/…/g; s/^/ /' | sort -u
exit 0
fi
cd "$(dirname "$0")/.." || exit 1
[ -f scripts/budgets.env ] && . scripts/budgets.env
CORE_LOC_MAX=${CORE_LOC_MAX:-2000}
EXT_LOC_MAX=${EXT_LOC_MAX:-2000}
FILE_LOC_WARN=${FILE_LOC_WARN:-500}
FUNC_LOC_WARN=${FUNC_LOC_WARN:-60}
DEPS_MAX=${DEPS_MAX:-6}
CLAUDE_LOC_MAX=${CLAUDE_LOC_MAX:-150}
fail=0
warn=0
# --quiet prints only what needs acting on: failures, warnings, and the verdict. A green run is two
# lines instead of forty-three, which matters because this is the most-run command in the repo and its
# output is read far more often by an agent's context window than by a person. Passing gate names are
# never information — `--list` answers "does this gate exist?" and does it without running anything.
quiet=0
[ "${1:-}" = "--quiet" ] && quiet=1
pass() { [ "$quiet" -eq 1 ] || printf ' ok %s\n' "$1"; }
bad() { printf ' FAIL %s\n' "$1"; fail=1; }
note() { printf ' warn %s\n' "$1"; warn=$((warn + 1)); }
head_() { [ "$quiet" -eq 1 ] || printf '\n%s\n' "$1"; }
if ! command -v go >/dev/null 2>&1 || ! command -v gofmt >/dev/null 2>&1; then
echo "FAIL go toolchain not found on PATH — cannot verify anything"
exit 1
fi
# --- documentation coupling -------------------------------------------------
# Runs before the Go gates so it still applies while the repo is harness-only.
# Code and the docs describing it move together, or they drift apart silently.
head_ "documentation"
if [ -d .git ] && command -v git >/dev/null 2>&1; then
# -uall matters: the default collapses untracked directories to "dir/", which would hide a
# brand-new internal/ext/feeds/feeds.go from the .go check below.
changed=$(git status --porcelain -uall 2>/dev/null | sed 's/^...//' | sed 's/.* -> //')
if [ -z "$changed" ]; then
pass "working tree clean — nothing to couple"
else
if echo "$changed" | grep -qE '\.go$' && ! echo "$changed" | grep -qx 'docs/state.md'; then
bad "*.go changed but docs/state.md did not — inventory, counters and latent items move with the code"
else
pass "code/state.md coupling"
fi
if echo "$changed" | grep -qE '^(cmd|internal)/.*\.go$' && ! echo "$changed" | grep -qE '_test\.go$'; then
# A comment-only or gofmt-only diff ships no behaviour, so it owes no test. Compare the added and
# removed lines with comments, blanks and indentation stripped: equal sets mean nothing happened.
gochanged=$(echo "$changed" | grep -E '^(cmd|internal)/.*\.go$')
godiff=$(git diff HEAD -- $gochanged 2>/dev/null)
# strip the marker, comments, blanks, and *all* whitespace runs — gofmt realignment then compares
# equal, while any real edit still differs.
strip() { grep -E "^[$1]" | grep -vE '^(\+\+\+|---)' | sed "s/^[$1]//" |
grep -vE '^[[:space:]]*(//|/\*|\*/|\* )' | tr -s ' \t' ' ' |
sed 's/^ //; s/ $//' | grep -v '^$' | sort; }
newgo=$(git ls-files --others --exclude-standard -- $gochanged 2>/dev/null)
if [ -z "$newgo" ] && [ "$(echo "$godiff" | strip '+')" = "$(echo "$godiff" | strip '-')" ]; then
pass "code/test coupling (comment- or format-only)"
else
bad "cmd/ or internal/ .go changed but no _test.go did — behaviour ships with a test (conventions.md)"
fi
else
pass "code/test coupling"
fi
if echo "$changed" | grep -qE '^internal/.*templates/.*\.html$' && ! echo "$changed" | grep -qx 'docs/theme-contract.md'; then
bad "embedded templates changed but docs/theme-contract.md did not — they drift together (ADR-0023)"
else
pass "templates/theme-contract coupling"
fi
# One exemption, and it is about the agent tooling rather than this project: .claude/settings.json is
# Claude Code's own permission list, which HARNESS.md calls a convenience, so editing it explains
# nothing about khosra. khosra's own configuration is not exempt from anything — the engine's settings
# live in the site root (content-model.md) and the engine validates them itself. Everything else under
# .claude/, and all of scripts/ including budgets.env, changes how the machine behaves and is gated.
harnesschanged=$(echo "$changed" | grep -E '^(CLAUDE\.md$|scripts/|\.claude/)' | grep -v '^\.claude/settings\.json$' || true)
if [ -n "$harnesschanged" ] && ! echo "$changed" | grep -qx 'HARNESS.md'; then
bad "the harness changed (CLAUDE.md, scripts/ or .claude/) but HARNESS.md did not — the guide to the machine is part of the machine"
else
pass "harness/HARNESS.md coupling"
fi
fi
# The reference theme is a contract demonstration, not a design: zero JavaScript (ADR-0026).
themefiles=$(find internal -path '*templates*' -name '*.html' 2>/dev/null || true)
if [ -n "$themefiles" ]; then
scripted=$(echo "$themefiles" | xargs grep -ln '<script' 2>/dev/null || true)
if [ -n "$scripted" ]; then
bad "<script> in the reference theme — it is a contract demonstration, not a design (ADR-0026): $(echo "$scripted" | tr '\n' ' ')"
else
pass "reference theme is script-free"
fi
fi
# Invariant 2, as mechanism rather than memory. Content from the site root is trusted, so raw HTML renders
# there (ADR-0060) — but the *trusted* half is the whole claim, and this is what holds it to one place.
# A second call site means some other input has been handed the pipeline that trusts its author, which is
# the failure ADR-0003 exists to prevent; when comments arrive they get their own goldmark without it.
# Matched by file rather than by line, so the rule can still be explained next to the code it governs.
unsafe=$(grep -rl 'html\.WithUnsafe()' --include='*.go' cmd internal 2>/dev/null | sort || true)
if [ "$unsafe" != "internal/render/render.go" ]; then
bad "html.WithUnsafe belongs in internal/render/render.go and nowhere else (ADR-0003, ADR-0060); found in: $(echo "${unsafe:-nothing}" | tr '\n' ' ')"
else
pass "raw HTML is enabled in exactly one renderer"
fi
# The example site is a demonstration that has to stay true (ADR-0051). `check` over it catches the class of
# rot a test cannot: a content rule that changed while the example kept the old shape. Findings are allowed —
# the example carries one on purpose — but nothing fatal is.
if [ -d examples/demo-site ]; then
if go run ./cmd/khosra check -site examples/demo-site >/tmp/example-check.log 2>&1; then
pass "the example site still checks out"
else
bad "examples/demo-site has a fatal finding — the demo must stay a site the engine accepts"
sed 's/^/ /' /tmp/example-check.log
fi
fi
# Dangling references. Every one of these found a real stale pointer when run by hand.
refs=$(grep -rhoE '`(docs|scripts|ideas|reference|\.claude)/[A-Za-z0-9_./-]+`' \
docs CLAUDE.md HARNESS.md ideas reference .claude scripts 2>/dev/null | tr -d '`' | sort -u)
dangling=""
for f in $refs; do [ -e "$f" ] || dangling="$dangling $f"; done
[ -n "$dangling" ] && bad "reference to a path that does not exist:$dangling"
adrs=$(grep -rhoE 'ADR-[0-9]{4}' docs CLAUDE.md HARNESS.md ideas reference .claude scripts cmd internal 2>/dev/null | sort -u)
missingadr=""
for a in $adrs; do
# the log registers every number ever used — as an entry, or in the withdrawn line
grep -q "$a" docs/decisions.md 2>/dev/null || missingadr="$missingadr $a"
done
[ -n "$missingadr" ] && bad "reference to an ADR with no entry in decisions.md:$missingadr"
secs=$(grep -rhoE 'CLAUDE\.md`? §[0-9]+' docs HARNESS.md ideas reference .claude scripts 2>/dev/null |
grep -oE '§[0-9]+' | tr -d '§' | sort -u)
missingsec=""
for s in $secs; do
grep -q "^## $s\. " CLAUDE.md || missingsec="$missingsec §$s"
done
[ -n "$missingsec" ] && bad "reference to a CLAUDE.md section that does not exist:$missingsec"
[ -z "$dangling$missingadr$missingsec" ] && pass "references resolve"
# Index rot: a folder of files nobody lists is a folder nobody reads.
for d in ideas reference; do
[ -d "$d" ] || continue
files=$(find "$d" -name '*.md' -not -name 'README.md' | wc -l | tr -d ' ')
listed=$(grep -c '^- \[' "$d/README.md" 2>/dev/null || true)
if [ "$files" != "${listed:-0}" ]; then
note "$d: $files file(s), $listed index line(s) — index out of date"
fi
if [ "$d" = "ideas" ]; then
unstatused=$(grep -L '^Status:' ideas/*.md 2>/dev/null | grep -v 'README.md' || true)
[ -n "$unstatused" ] && note "ideas: no Status line: $(echo "$unstatused" | tr '\n' ' ')"
fi
done
# True staleness: was state.md updated no earlier than the last commit that touched Go?
#
# Compared, never declared. A hand-written sha cannot do this job: a commit cannot name itself, so the
# doc update had to trail the code in a commit of its own, and folding the two together then left the
# sha naming a commit that no longer existed (ADR-0057).
lastgo=$(git log -1 --format=%H -- '*.go' 2>/dev/null)
laststate=$(git log -1 --format=%H -- docs/state.md 2>/dev/null)
if [ -n "$lastgo" ]; then
if [ -n "$laststate" ] && git merge-base --is-ancestor "$lastgo" "$laststate" 2>/dev/null; then
pass "docs/state.md is current with the code"
else
note "docs/state.md was last updated in ${laststate:-no commit}, older than the .go change in $(git log -1 --format=%h -- '*.go')"
fi
fi
# The generated surface is only worth reading if it cannot be wrong. Regenerate and compare rather
# than trusting that whoever added a function also ran the script.
if [ -x scripts/surface.sh ]; then
if ! scripts/surface.sh | cmp -s - docs/surface.md; then
bad "docs/surface.md is stale — run 'make surface'"
else
pass "docs/surface.md matches the code"
fi
fi
# CLAUDE.md is re-sent on every single turn, which makes it the most expensive file per byte in the
# repo. A ceiling here is not tidiness; it is the only budget that bills per turn.
claudeloc=$(wc -l <CLAUDE.md | tr -d ' ')
if [ "$claudeloc" -gt "$CLAUDE_LOC_MAX" ]; then
bad "CLAUDE.md is $claudeloc lines, over CLAUDE_LOC_MAX=$CLAUDE_LOC_MAX (move detail to the owning doc)"
else
pass "CLAUDE.md $claudeloc / $CLAUDE_LOC_MAX lines"
fi
else
note "not a git repo — doc coupling unenforceable"
fi
result_and_exit() {
head_ "result"
if [ "$fail" -eq 0 ]; then
printf ' PASS %s warning(s)\n' "$warn"
else
printf ' FAIL fix the above before reporting success\n'
fi
[ "$quiet" -eq 1 ] || printf '\n'
exit "$fail"
}
if [ ! -f go.mod ]; then
head_ "go"
note "no go.mod — nothing to verify yet. Run 'go mod init' as part of the first feature."
result_and_exit
fi
mod=$(awk '/^module /{print $2; exit}' go.mod)
# Engine source only. The site root is outside this repo (ADR-0011); ideas/ and reference/ may hold
# exploratory scratch code, which is not the engine and is never formatted, vetted, built or budgeted.
gofiles=$(find . -name '*.go' -not -path './vendor/*' -not -path './.git/*' \
-not -path './ideas/*' -not -path './reference/*' -not -path './.scratch/*' 2>/dev/null)
if [ -z "$gofiles" ]; then
head_ "go"
note "go.mod present but no .go files yet — nothing to verify."
result_and_exit
fi
head_ "correctness"
pkgs=$(go list ./... 2>/dev/null | grep -vE "^$mod/(ideas|reference|\.scratch)(/|$)")
if [ -z "$pkgs" ]; then
head_ "go"; note "no engine packages yet — nothing to verify."
result_and_exit
fi
unformatted=$(echo "$gofiles" | xargs gofmt -l 2>/dev/null || true)
if [ -n "$unformatted" ]; then bad "gofmt: $(echo "$unformatted" | tr '\n' ' ')"; else pass "gofmt"; fi
if go vet $pkgs >/tmp/vet.log 2>&1; then pass "go vet"; else bad "go vet"; sed 's/^/ /' /tmp/vet.log; fi
if go build $pkgs >/tmp/build.log 2>&1; then pass "go build"; else bad "go build"; sed 's/^/ /' /tmp/build.log; fi
# The working tree building says nothing about what is being committed. Staging a subset — a changed
# signature without its caller — lands a commit that does not compile, which `git bisect` then trips over
# forever. So when something is staged, build the staged tree itself, from a throwaway checkout of the index
# so nothing here can touch the real one.
if ! git diff --cached --quiet 2>/dev/null; then
staged=$(mktemp -d)
if git archive "$(git write-tree)" 2>/dev/null | tar -x -C "$staged" 2>/dev/null &&
(cd "$staged" && go build ./... >/tmp/staged-build.log 2>&1); then
pass "the staged tree builds"
else
bad "what is staged does not build on its own — a partial stage, most likely a caller left behind"
sed 's/^/ /' /tmp/staged-build.log 2>/dev/null
fi
rm -rf "$staged"
fi
if echo "$gofiles" | grep -q '_test\.go$'; then
if go test -race $pkgs >/tmp/test.log 2>&1; then
pass "go test ($(grep -c '^ok' /tmp/test.log) packages)"
else
bad "go test"; sed 's/^/ /' /tmp/test.log
fi
else
note "no tests exist yet"
fi
head_ "dependencies"
reqs=$(awk '
/^require[ \t]*\(/ { inb = 1; next }
inb && /^\)/ { inb = 0; next }
{
ln = $0
ind = (ln ~ /\/\/[ \t]*indirect/) ? "indirect" : "direct"
sub(/\/\/.*/, "", ln)
gsub(/^[ \t]+|[ \t]+$/, "", ln)
if (ln == "") next
if (!inb) { if (ln !~ /^require[ \t]/) next; sub(/^require[ \t]+/, "", ln) }
split(ln, a, /[ \t]+/)
if (a[1] != "") print a[1], ind
}' go.mod)
direct=$(echo "$reqs" | awk '$2=="direct" {print $1}' | grep -v '^$' || true)
total=$(echo "$reqs" | grep -cv '^$' || true)
if [ -f scripts/allowed-deps.txt ]; then
# the file documents "# starts a comment", so strip trailing ones too, not just whole-line
allowed=$(sed 's/#.*//' scripts/allowed-deps.txt | sed 's/[[:space:]]*$//' | grep -v '^$' || true)
unlisted=""
for d in $direct; do
echo "$allowed" | grep -qxF "$d" || unlisted="$unlisted $d"
done
if [ -n "$unlisted" ]; then
bad "dependency not on allowlist:$unlisted (needs an ADR + scripts/allowed-deps.txt)"
else
directcount=$(echo "$direct" | grep -c . || true)
pass "allowlist ($directcount direct)"
fi
fi
# An untidy go.mod misreports what is direct, so the allowlist check above would silently skip a
# dependency added by `go get` before anything imported it.
if go mod tidy -diff >/tmp/tidy.log 2>&1; then
pass "go.mod is tidy"
else
bad "go.mod is untidy — run go mod tidy; until then a direct dependency can hide as indirect"
fi
if [ "$total" -gt "$DEPS_MAX" ]; then
bad "module count $total exceeds DEPS_MAX=$DEPS_MAX"
else
pass "module count $total / $DEPS_MAX"
fi
head_ "architecture"
# The layering in conventions.md, enforced. Dependencies point inward; a sibling import here is
# what turns a layered engine into a ball of mud, and it always looks locally reasonable.
# One line per package: "importpath imp1 imp2 …". go list is authoritative; grepping source is not.
pkgimports=$(go list -f '{{.ImportPath}}{{range .Imports}} {{.}}{{end}}' ./... 2>/dev/null)
pairs=$(echo "$pkgimports" | awk '{for (i=2; i<=NF; i++) print $1, $i}')
layer() { # $1 = importing layer, $2..$n = layers it may not import
local from="$1"; shift
for to in "$@"; do
echo "$pairs" | awk -v f="$mod/internal/$from" -v t="$mod/internal/$to" \
'index($1,f)==1 && index($2,t)==1 {print $1" → "$2}'
done
}
violations=$(
layer content render web ext
layer render web ext
layer web ext
echo "$pairs" | awk -v c="$mod/cmd" 'index($2,c)==1 && index($1,c)!=1 {print $1" → "$2}'
)
# Sibling imports between features are what make an agent's read set compound (ADR-0027).
siblings=$(echo "$pairs" | awk -v e="$mod/internal/ext/" '
index($1,e)==1 && index($2,e)==1 && $1!=$2 {print $1" → "$2}')
if [ -n "$violations$siblings" ]; then
bad "import boundary violated (conventions.md layering): $(echo "$violations$siblings" | tr '\n' ' ')"
else
pass "import boundaries"
fi
nopkgdoc=""
for dir in $(echo "$gofiles" | grep -v '_test\.go$' | xargs -n1 dirname 2>/dev/null | sort -u); do
documented=$(awk 'prev ~ /^\/\// && /^package /{print FILENAME} {prev=$0}' "$dir"/*.go 2>/dev/null | head -1)
[ -z "$documented" ] && nopkgdoc="$nopkgdoc $dir"
done
if [ -n "$nopkgdoc" ]; then
bad "package without a package comment (conventions.md Documentation):$nopkgdoc"
else
pass "every package documented"
fi
undocumented=$(echo "$gofiles" | grep -v '_test\.go$' | xargs awk '
/^(func|type|var|const) [A-Z]/ { if (prev !~ /^\/\//) printf "%s:%d ", FILENAME, FNR }
{ prev = $0 }' 2>/dev/null)
if [ -n "$undocumented" ]; then
note "exported identifier without a doc comment: $undocumented"
else
pass "exported identifiers documented"
fi
missingdoc=""
for dir in $(echo "$gofiles" | grep '^\./internal/ext/' | xargs -n1 dirname 2>/dev/null | sort -u); do
[ -f "$dir/doc.go" ] || missingdoc="$missingdoc $dir"
done
if [ -n "$missingdoc" ]; then
bad "internal/ext package without doc.go — contributes / cascade keys / contract fields / not doing (ADR-0027):$missingdoc"
else
pass "every feature has a doc.go"
fi
head_ "budgets"
# Two trees, two ceilings: the core must stop growing after Arc 2, ext is where growth belongs.
loc() { [ -z "$1" ] && { echo 0; return; }; echo "$1" | xargs wc -l 2>/dev/null | awk '$2!="total"{t+=$1} END{print t+0}'; }
nontest=$(echo "$gofiles" | grep -v '_test\.go$' || true)
extfiles=$(echo "$nontest" | grep '^\./internal/ext/' || true)
corefiles=$(echo "$nontest" | grep -v '^\./internal/ext/' || true)
coreloc=$(loc "$corefiles")
extloc=$(loc "$extfiles")
if [ "$coreloc" -gt "$CORE_LOC_MAX" ]; then
bad "core is $coreloc lines, over CORE_LOC_MAX=$CORE_LOC_MAX (shrink it, or raise it in an ADR)"
else
pass "core $coreloc / $CORE_LOC_MAX lines"
fi
if [ "$extloc" -gt "$EXT_LOC_MAX" ]; then
bad "internal/ext is $extloc lines, over EXT_LOC_MAX=$EXT_LOC_MAX (a template may have done it)"
else
pass "ext $extloc / $EXT_LOC_MAX lines"
fi
oversized=$(echo "$gofiles" | xargs wc -l 2>/dev/null | awk -v m="$FILE_LOC_WARN" '$2!="total" && $1>m {print $2"("$1")"}')
if [ -n "$oversized" ]; then
note "files over FILE_LOC_WARN=$FILE_LOC_WARN: $(echo "$oversized" | tr '\n' ' ')"
else
pass "no file over $FILE_LOC_WARN lines"
fi
longfuncs=$(echo "$gofiles" | xargs awk -v m="$FUNC_LOC_WARN" '
/^func / { start = FNR; name = $0; inf = 1; next }
inf && /^}/ { if (FNR - start > m) printf "%s:%d(%d)\n", FILENAME, start, FNR - start; inf = 0 }
' 2>/dev/null)
[ -n "$longfuncs" ] && note "functions over $FUNC_LOC_WARN lines: $(echo "$longfuncs" | tr '\n' ' ')"
if [ -f Dockerfile ] && [ "${VERIFY_DOCKER:-0}" = "1" ]; then
head_ "container (VERIFY_DOCKER=1)"
if command -v docker >/dev/null 2>&1; then
if docker build -q -t khosra:verify . >/tmp/docker.log 2>&1; then
pass "docker build"
else
bad "docker build"; tail -20 /tmp/docker.log | sed 's/^/ /'
fi
else
note "docker not on PATH"
fi
fi
head_ "style floor"
# conventions.md states these absolutely, so they fail. A rule enforced as a suggestion teaches
# the agent to read every rule as a suggestion.
badpkg=$(find ./cmd ./internal -type d 2>/dev/null | grep -Ei '/(utils?|helpers?|common|shared|misc|manager|base|impl|core)$' || true)
if [ -n "$badpkg" ]; then bad "package name says nothing (CLAUDE.md rule 3.6): $(echo "$badpkg" | tr '\n' ' ')"; else pass "package names"; fi
inits=$(echo "$gofiles" | xargs grep -ln '^func init()' 2>/dev/null || true)
if [ -n "$inits" ]; then bad "init() found — wire explicitly in cmd/: $(echo "$inits" | tr '\n' ' ')"; else pass "no init()"; fi
badlog=$(echo "$pairs" | awk '$2=="log" {print $1}' | sort -u)
if [ -n "$badlog" ]; then bad "imports log, not log/slog: $(echo "$badlog" | tr '\n' ' ')"; else pass "log/slog only"; fi
clocks=$(echo "$gofiles" | grep -v '_test\.go$' | grep -v '/clock\.go$' | xargs grep -ln 'time\.Now(' 2>/dev/null || true)
if [ -n "$clocks" ]; then bad "time.Now() outside a clock.go — a render that reads the clock is only true for a while (conventions.md): $(echo "$clocks" | tr '\n' ' ')"; else pass "clock accessed through clock.go"; fi
panics=$(echo "$gofiles" | grep -v '_test\.go$' | grep -v '^\./cmd/' | xargs grep -ln 'panic(' 2>/dev/null || true)
if [ -n "$panics" ]; then bad "panic() outside cmd/ — request-time failure degrades (conventions.md): $(echo "$panics" | tr '\n' ' ')"; else pass "no panic outside cmd"; fi
head_ "smells (advisory)"
# Only calls that actually wrap: fmt.Errorf without an err argument is creating an error, not losing one.
nowrap=$(echo "$gofiles" | xargs grep -hn 'fmt\.Errorf(' 2>/dev/null |
grep -v '%w' | grep -cE '\berr\b' || true)
[ "${nowrap:-0}" -gt 0 ] && note "$nowrap fmt.Errorf without %w (wrap at package boundaries)"
# Only exported signatures: conventions.md bans interface{} as an API escape hatch, but ADR-0002 mandates
# an open page object, so unexported code reading Extra legitimately takes any and always will.
anyuse=$(echo "$gofiles" | grep -v '_test\.go$' |
xargs grep -HnE '^func (\([^)]*\) )?[A-Z][A-Za-z0-9_]*\(.*(\bany\b|interface\{\})' 2>/dev/null |
cut -d: -f1 | sort -u || true)
[ -n "$anyuse" ] && note "interface{} or any present (no empty interface for flexibility): $(echo "$anyuse" | tr '\n' ' ')"
deep=$(echo "$gofiles" | xargs awk '/^\t\t\t\t\t[^\t}]/ {print FILENAME; nextfile}' 2>/dev/null | sort -u || true)
[ -n "$deep" ] && note "nesting past 4 (conventions.md): $(echo "$deep" | tr '\n' ' ')"
deadexp=$(echo "$gofiles" | grep '^\./internal/' | grep -v '_test\.go$' | xargs grep -hoE '^func [A-Z][A-Za-z0-9_]*' 2>/dev/null | awk '{print $2}' | sort -u |
while read -r sym; do
n=$(echo "$gofiles" | xargs grep -c "\b$sym\b" 2>/dev/null | awk -F: '{s+=$2} END{print s+0}')
[ "${n:-0}" -le 1 ] && printf '%s ' "$sym"
done)
[ -n "$deadexp" ] && note "exported but referenced once — unexport or delete: $deadexp"
todos=$(echo "$gofiles" | xargs grep -c 'TODO\|FIXME\|XXX' 2>/dev/null | awk -F: '{s+=$2} END{print s+0}')
[ "${todos:-0}" -gt 0 ] && note "$todos TODO/FIXME markers (latent items belong in docs/state.md)"
result_and_exit