Audit Qt echo-only parity commands

ober

69ce4de1e3cf71c3ee600388be6d1a6144fc1449

diff --git a/scripts/audit-command-registry.sh b/scripts/audit-command-registry.sh
index 7c49c78..307ba0d 100755
--- a/scripts/audit-command-registry.sh
+++ b/scripts/audit-command-registry.sh
@@ -11,6 +11,9 @@ docs="$TMPDIR/docs.txt"
 defs="$TMPDIR/defs.txt"
 covered="$TMPDIR/covered.txt"
 duplicates="$TMPDIR/duplicates.txt"
+echo_only="$TMPDIR/echo-only.txt"
+real_impls="$TMPDIR/real-impls.txt"
+echo_unresolved="$TMPDIR/echo-unresolved.txt"
 
 cd "$ROOT"
 
@@ -154,6 +157,94 @@ if [ "$hard_errors" -eq 0 ]; then
   echo "ok"
 fi
 
+echo "--- echo-only parity registrations ---"
+{
+  awk '
+    /\(def \*parity3-toggle-names\*/ { in_list=1 }
+    in_list {
+      while (match($0, /toggle-[A-Za-z0-9_+*\/<>=!?$%&~.^:-]+/)) {
+        print substr($0, RSTART, RLENGTH)
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_list && /\)\)/ { in_list=0 }
+  ' src/jerboa-emacs/qt/commands-parity3.ss
+  awk '
+    /\(def \(qt-register-parity4-toggles!\)/ { in_form=1 }
+    in_form {
+      while (match($0, /toggle-[A-Za-z0-9_+*\/<>=!?$%&~.^:-]+/)) {
+        print substr($0, RSTART, RLENGTH)
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_form && /\)\)\)/ { in_form=0 }
+  ' src/jerboa-emacs/qt/commands-parity4.ss
+  awk '
+    /\(def \*parity3-mode-toggle-names\*/ { in_list=1 }
+    in_list {
+      while (match($0, /[A-Za-z0-9_+*\/<>=!?$%&~.^:-]+-mode/)) {
+        print substr($0, RSTART, RLENGTH)
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_list && /\)\)/ { in_list=0 }
+  ' src/jerboa-emacs/qt/commands-parity3.ss
+  awk '
+    /\(def \(qt-register-parity5-mode-toggles!\)/ { in_form=1 }
+    in_form {
+      while (match($0, /[A-Za-z0-9_+*\/<>=!?$%&~.^:-]+-mode/)) {
+        print substr($0, RSTART, RLENGTH)
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_form && /\)\)\)/ { in_form=0 }
+  ' src/jerboa-emacs/qt/commands-parity5.ss
+  awk '
+    /\(def \*parity3-stub-commands\*/ { in_list=1 }
+    in_list {
+      while (match($0, /\([A-Za-z0-9_+*\/<>=!?$%&~.^:-]+[[:space:]]+\./)) {
+        token = substr($0, RSTART + 1, RLENGTH - 3)
+        sub(/[[:space:]]+$/, "", token)
+        print token
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_list && /\)\)/ { in_list=0 }
+  ' src/jerboa-emacs/qt/commands-parity3.ss
+  awk '
+    /\(def \(qt-register-parity5-stubs!\)/ { in_form=1 }
+    in_form {
+      while (match($0, /\([A-Za-z0-9_+*\/<>=!?$%&~.^:-]+[[:space:]]+\./)) {
+        token = substr($0, RSTART + 1, RLENGTH - 3)
+        sub(/[[:space:]]+$/, "", token)
+        print token
+        $0 = substr($0, RSTART + RLENGTH)
+      }
+    }
+    in_form && /\)\)\)/ { in_form=0 }
+  ' src/jerboa-emacs/qt/commands-parity5.ss
+} \
+  | grep -E '^[A-Za-z0-9][A-Za-z0-9_+*/<>=!?$%&~.^:-]+$' \
+  | grep -Ev '^(name|toggle-\*|toggle-command|qt-register-parity5-mode)$' \
+  | sort -u > "$echo_only"
+{
+  rg --no-filename -o "\\(cons '[^[:space:])]+ cmd-[^[:space:])]+\\)" src/jerboa-emacs/qt/commands*.ss \
+    | sed -E "s/.*\\(cons '([^[:space:])]+) cmd-[^[:space:])]+\\).*/\\1/"
+} | sort -u > "$real_impls"
+comm -23 "$echo_only" "$real_impls" > "$echo_unresolved"
+echo_only_count="$(wc -l < "$echo_only" | tr -d ' ')"
+echo_unresolved_count="$(wc -l < "$echo_unresolved" | tr -d ' ')"
+echo "echo-only parity source registrations: $echo_only_count"
+echo "echo-only parity registrations without later Qt moved-command override: $echo_unresolved_count"
+if [ "$echo_unresolved_count" -eq 0 ]; then
+  echo "ok"
+else
+  head -120 "$echo_unresolved" | sed 's/^/WARN unresolved echo-only parity command: /'
+  if [ "$echo_unresolved_count" -gt 120 ]; then
+    echo "WARN unresolved echo-only parity command report truncated: $echo_unresolved_count total"
+  fi
+fi
+
 echo "--- registry coverage summary ---"
 total="$(wc -l < "$commands" | tr -d ' ')"
 covered_count="$(comm -12 "$commands" "$covered" | wc -l | tr -d ' ')"