From b1aee82f4a59fb2f518788853010a95bcd6b9ce0 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 2 Oct 2026 04:45:29 +0100 Subject: [PATCH] fix(canon): deed_canon ignores inline ";" comments DEED comments run from any ";" outside a string to line-end (deed.abnf `comment`), but deed_canon stripped only whole-line comments. A clause written `(canon ; :version "2.1.2"` followed by an active stale `:version` returned the commented value, so Gate A assertion 3 could pass a spine that is out of lockstep. The reader now drops each line's comment tail with a quote-aware awk scan (a ";" inside a string, including after an escaped quote, is kept). It is backslash-free, so the byte-identical copies in rsr-template-repo's dogfood-gate.yml and repo-init.just stay safe. Two new cases in check-canon-lockstep-deed-test.sh: an inline decoy cannot mask a stale version, and an inline decoy is ignored when the active pin matches. Both failed before the fix (9/11), 11/11 after. Raised by CodeRabbit on rsr-template-repo#222. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Hw7qg3u9PAP6b2oKyVTSVC --- scripts/check-canon-lockstep.sh | 5 +++-- scripts/tests/check-canon-lockstep-deed-test.sh | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/check-canon-lockstep.sh b/scripts/check-canon-lockstep.sh index d91d8d81..c4e98ef8 100644 --- a/scripts/check-canon-lockstep.sh +++ b/scripts/check-canon-lockstep.sh @@ -269,11 +269,12 @@ echo # deed_canon : print the value of : from the # deed's one (canon …) clause, or nothing when the clause or key is -# absent or the clause is not unique. The SAME function is in +# absent or the clause is not unique. A ";" outside a string starts a +# comment that runs to line-end (deed.abnf), whole-line or inline. The SAME function is in # rsr-template-repo .github/workflows/dogfood-gate.yml and # build/just/repo-init.just; keep the three identical. deed_canon() { - _clauses="$(grep -vE '^[[:space:]]*;' "$2" | awk '{ printf "%s ", $0 }' | grep -oE '[(]canon[[:space:]][^()]*[)]')" || true + _clauses="$(awk 'BEGIN { bs = sprintf("%c", 92); dq = sprintf("%c", 34) } { o = ""; q = 0; for (i = 1; i <= length($0); i++) { c = substr($0, i, 1); if (q && c == bs) { o = o c substr($0, i + 1, 1); i++; continue } if (c == dq) q = !q; else if (!q && c == ";") break; o = o c } printf "%s ", o }' "$2" | grep -oE '[(]canon[[:space:]][^()]*[)]')" || true _n="$(echo "$_clauses" | grep -c '(canon' || true)" if [ "$_n" != "1" ]; then echo "deed_canon: $2 carries ${_n:-0} (canon …) clauses, need exactly 1" >&2 diff --git a/scripts/tests/check-canon-lockstep-deed-test.sh b/scripts/tests/check-canon-lockstep-deed-test.sh index 10b522f9..371bc3a8 100755 --- a/scripts/tests/check-canon-lockstep-deed-test.sh +++ b/scripts/tests/check-canon-lockstep-deed-test.sh @@ -84,6 +84,16 @@ mkdir -p "$WORK/two-deeds"; deed "$WORK/two-deeds" "$WANT_VER" "$WANT_CRIT" "$WA cp "$WORK/two-deeds/spine_chora.deed" "$WORK/two-deeds/other_chora.deed" expect "two deeds fail" "$WORK/two-deeds" FAIL "one-deed-per-repo" +# An inline comment (deed.abnf: ";" to line-end, anywhere outside a string) +# is not part of the clause: a decoy :version there must never be read. +deed "$WORK/inline-stale" "0.0.1" "$WANT_CRIT" "$WANT_GATES" +sed -i 's/^ (canon$/ (canon ; :version "'"$WANT_VER"'"/' "$WORK/inline-stale/spine_chora.deed" +expect "inline-comment decoy cannot mask a stale version" "$WORK/inline-stale" FAIL "(version)" + +deed "$WORK/inline-ok" "$WANT_VER" "$WANT_CRIT" "$WANT_GATES" +sed -i 's/^ (canon$/ (canon ; :version "0.0.1" -- a ";" here too/' "$WORK/inline-ok/spine_chora.deed" +expect "inline-comment decoy is ignored when the active pin matches" "$WORK/inline-ok" PASS + mkdir -p "$WORK/legacy/.machine_readable" printf '[canon]\nversion = "0.0.1"\ncriteria_sha256 = "%s"\n' "$WANT_CRIT" > "$WORK/legacy/.machine_readable/rsr-profile.a2ml" expect "legacy a2ml fallback still passes on criteria" "$WORK/legacy" PASS "LEGACY"