#!/bin/sh # check-escalation — every skill states when it stops and hands back. # # #5 decided this belongs in the body, not the frontmatter: no harness reads # frontmatter beyond name/description, so a `failure_criteria:` key would be a # guarantee nothing honours. The model reads the body. # # #37 then had to define which skills need one, and every obvious answer was # bad: a hardcoded list rots, sniffing the text for "does it write anything" is # unfalsifiable, and a frontmatter flag is the rejected option wearing a hat. # # So there is no acting set. EVERY skill answers the question. A read-only skill # answers it in one line — "read-only; findings are the output, nothing is # handed back" — which turns an absence into a claim someone can disagree with. # # bin/escalation-pending.txt is a ratchet for skills whose real rule has not # been written yet (a stop condition nobody thought about is not worth # enforcing). It is self-cleaning: a listed skill that HAS a section fails, so # the list cannot outlive its reason. # # Usage: check-escalation [checkout-root] set -u ROOT=${1:-$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)} PENDING="$ROOT/bin/escalation-pending.txt" fail=0 listed() { [ -f "$PENDING" ] || return 1 sed 's/#.*//' "$PENDING" | grep -qx "[[:space:]]*$1[[:space:]]*" } for dir in "$ROOT"/skills/*/; do [ -f "$dir/SKILL.md" ] || continue name=$(basename "$dir") if grep -q '^## Escalation' "$dir/SKILL.md"; then if listed "$name"; then echo "ERROR: skills/$name has an Escalation section but is still in bin/escalation-pending.txt — remove it from the list" >&2 fail=1 fi continue fi listed "$name" && continue echo "ERROR: skills/$name has no '## Escalation' section — say when it stops and hands back, or say it never does" >&2 fail=1 done # A pending entry for a skill that no longer exists is a stale exemption, and a # stale exemption is how a gate quietly stops covering something. Looped without # a pipe on purpose: a `while read` on the right of a pipe runs in a subshell, # so `fail=1` would be set in a process that exits before it is read. if [ -f "$PENDING" ]; then entries=$(sed 's/#.*//' "$PENDING" | tr -d '[:blank:]' | grep -v '^$' || true) for entry in $entries; do [ -f "$ROOT/skills/$entry/SKILL.md" ] && continue echo "ERROR: bin/escalation-pending.txt lists '$entry', which has no skills/$entry/SKILL.md" >&2 fail=1 done fi exit $fail