open-standards/scripts/check-frozen-rules.sh
Transaction Science 679d8f36c8 The repository checks go red while a research record's rule file differs from what first reached main
A rule committed before the runs it judges is worth what it is because it was
fixed before the data, and a rule changed together with every copy of its
digest passes every check that reads the tree alone.

scripts/check-frozen-rules.py walks head's first-parent history from its first
commit, pins each rule file (wai/research/<record>/*-rule*.json) at the mode
and blob the first commit there to add it held, and requires head to hold
that. It compares no single push, so what it finds does not depend on any one
run: a cancelled run hides nothing, and the next run on any later commit finds
the same change. A file restored to its pin passes again. A pull request is
also compared with its base, for a branch made before a rule reached main that
holds another file at the rule's path.

scripts/check-frozen-rules.sh runs scripts/check-frozen-rules.py as it first
reached the history and as head holds it, so a change to that script, in the
rule's commit or an earlier one, or its removal, does not hide a change to a
rule. The repository checks run the runner on every pull request and push to
main, after its self-test.

This is a check after the fact: it stops no commit. The runner and the workflow
step are read from head, so a commit that edits either one silences this check
from then on, until that edit is undone, and no red check follows. The diff in
the history then records it.

A commit reaches main as it is, so a rule file enters the history once: a rule
revised by a later commit of its branch fails, and the branch is rewritten so
that one commit adds it in its final form.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 03:19:08 -05:00

48 lines
1.8 KiB
Shell
Executable file

#!/usr/bin/env bash
#
# check-frozen-rules.sh <head-sha> [<base-sha>]
#
# Runs scripts/check-frozen-rules.py twice over head: as it first reached head's first-parent
# history, and as head holds it. The check reads the history, so what it finds does not depend
# on any one run; the first copy means a change that weakens the script, or removes it,
# together with a rule file does not hide the rule's change, and neither does a change to the
# script made earlier than the rule's, in a push whose run was cancelled. The copy as head
# holds it is the one that later rules and later record layouts can extend.
#
# A branch made before the check reached main holds no copy of it: with a base, both copies are
# then the base's.
#
# Exit 0 when both pass, 1 when either fails or a copy cannot be read, 2 on a wrong command line.
set -uo pipefail
if [ $# -lt 1 ] || [ $# -gt 2 ] || [ -z "$1" ]; then
echo "usage: check-frozen-rules.sh <head-sha> [<base-sha>]"
exit 2
fi
py=scripts/check-frozen-rules.py
first_add() { git log --first-parent -m --diff-filter=A --format=%H "$1" -- "$py" | tail -n 1; }
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
holder=$1
first=$(first_add "$holder")
if [ -z "$first" ] && [ $# -eq 2 ]; then
holder=$2
first=$(first_add "$holder")
fi
if [ -z "$first" ] || ! git show "$first:$py" > "$tmp/first.py"; then
echo "::error::frozen rules: no commit of the first-parent history of $* adds $py, so the check cannot run from it"
exit 1
fi
rc=0
echo "frozen rules: the check as it first reached this history, in ${first:0:12}"
python3 -I "$tmp/first.py" "$@" || rc=1
echo "frozen rules: the check as ${holder:0:12} holds it"
if git show "$holder:$py" > "$tmp/head.py"; then
python3 -I "$tmp/head.py" "$@" || rc=1
else
echo "::error::frozen rules: $holder holds no $py"
rc=1
fi
exit $rc