CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/coding-policy

General-purpose coding policy for Baruch's AI agents

74

Quality

93%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

test_dismiss_ruled_review.shskills/release/tests/

#!/usr/bin/env bash
# Outcome-based tests for dismiss-ruled-review.sh.
#
# The policy-review body is GOLDEN: each fixture runs the real
# .github/codex-review/post-review.sh against a PATH-stubbed gh that captures
# the posted payload, so a change to post-review.sh's finding format breaks
# these tests instead of silently breaking the parser. dismiss-ruled-review.sh
# is sourced (its main() guard prevents auto-run) and `gh` is overridden with a
# shell function serving fixtures and logging, in order, every follow-up
# comment POST and dismissal PUT. No network.
#
# Run: bash skills/release/tests/test_dismiss_ruled_review.sh
# Exit 0 on all-pass; non-zero with a per-test diagnostic on failure.

# shellcheck disable=SC2329  # test cases run indirectly via run() ("$@" dispatch)
set -uo pipefail

RELEASE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
REPO_ROOT="$(cd "${RELEASE_DIR}/../.." && pwd)"
SCRIPT="${RELEASE_DIR}/dismiss-ruled-review.sh"
POSTER="${REPO_ROOT}/.github/codex-review/post-review.sh"
[[ -f "$SCRIPT" && -r "$SCRIPT" ]] || { echo "fatal: dismiss-ruled-review.sh not readable at $SCRIPT" >&2; exit 2; }
[[ -f "$POSTER" && -r "$POSTER" ]] || { echo "fatal: post-review.sh not readable at $POSTER" >&2; exit 2; }
command -v jq >/dev/null 2>&1 || { echo "fatal: jq is required to run these tests" >&2; exit 2; }

# shellcheck disable=SC1090  # ShellCheck cannot resolve the dynamically constructed source path.
source "$SCRIPT"
set +e

# Tests run standalone unless a case sets HERDR_ENV in its own subshell.
unset HERDR_ENV
TMPDIR_TEST=$(mktemp -d -t dismiss-ruled-test.XXXXXX) || { echo "fatal: mktemp -d failed" >&2; exit 2; }
cleanup_tmp() {
  if ! rm -rf "$TMPDIR_TEST"; then
    echo "warning: could not remove temp dir ${TMPDIR_TEST} — remove it by hand" >&2
  fi
  return 0
}
trap cleanup_tmp EXIT

PASS_COUNT=0
FAIL_COUNT=0
HEAD_SHA="1111111111111111111111111111111111111111"
OLD_SHA="2222222222222222222222222222222222222222"
EVENTS="${TMPDIR_TEST}/events"            # "comment" / "dismiss <message>", in call order
COMMENT_BODY="${TMPDIR_TEST}/comment.md"  # last posted follow-up comment body
COMPARE_LOG="${TMPDIR_TEST}/compares"
RULING="${TMPDIR_TEST}/ruling"
ISSUE=12

assert_eq() {
  local label="$1" expected="$2" actual="$3"
  [[ "$expected" == "$actual" ]] && return 0
  echo "    FAIL: ${label}: expected '${expected}', got '${actual}'" >&2
  return 1
}

assert_unmet() { # <substring> <label>
  jq -r '.unmet[]' <<<"$OUT" | grep -qF -- "$1" && return 0
  echo "    FAIL: unmet names $2 (got $(jq -c .unmet <<<"$OUT"))" >&2
  return 1
}

run() {
  local name="$1"; shift
  : > "$EVENTS" || { echo "fatal: cannot reset ${EVENTS} — check ${TMPDIR_TEST} is writable, then rerun" >&2; exit 2; }
  : > "$COMPARE_LOG" || { echo "fatal: cannot reset ${COMPARE_LOG} — check ${TMPDIR_TEST} is writable, then rerun" >&2; exit 2; }
  rm -f "$COMMENT_BODY" || { echo "fatal: cannot remove ${COMMENT_BODY} — check ${TMPDIR_TEST} is writable, then rerun" >&2; exit 2; }
  MOCK_CHECKS='[{"name":"tests","bucket":"pass"}]'
  MOCK_CHECKS_RC=0
  MOCK_COMPARE='{"status":"ahead","files":[]}'
  MOCK_ISSUE_COMMENTS='[]'
  MOCK_COMMENT_RC=0
  MOCK_BINDING=""
  if "$@"; then
    PASS_COUNT=$((PASS_COUNT + 1)); echo "  pass: $name" >&2
  else
    FAIL_COUNT=$((FAIL_COUNT + 1)); echo "  FAIL: $name" >&2
  fi
}

# Golden body: post the Codex result JSON through the real post-review.sh with
# a gh stub on PATH that captures the review payload, then read its body.
STUB_DIR="${TMPDIR_TEST}/stub"
mkdir -p "$STUB_DIR" || { echo "fatal: cannot create $STUB_DIR" >&2; exit 2; }
cat > "${STUB_DIR}/gh" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
cat > "$GH_CAPTURE"
SH
chmod +x "${STUB_DIR}/gh"

golden_body() { # <codex-result-json>
  local result="${TMPDIR_TEST}/final.json" capture="${TMPDIR_TEST}/payload.json"
  printf '%s' "$1" > "$result"
  if ! GH_CAPTURE="$capture" PATH="${STUB_DIR}:${PATH}" bash "$POSTER" owner repo 9 "$result" >/dev/null; then
    echo "fatal: post-review.sh failed to build the golden body" >&2
    return 1
  fi
  jq -r '.body' "$capture"
}

BODY_TWO=$(golden_body '{"summary":"Policy loaded: 26 rule files. Two violations.","findings":[
  {"path":"skills/x/run.sh","line":3,"rule":"error-handling","severity":"blocking","message":"missing set -euo pipefail; add it"},
  {"path":"rules/b.md","line":7,"rule":"context-writing-style","severity":"blocking","message":"colon attaches a rationale"},
  {"path":"rules/c.md","line":2,"rule":"context-writing-style","severity":"advisory","message":"prefer a synonym"}]}') \
  || exit 2
BODY_FLOOR=$(golden_body '{"summary":"Policy loaded: 26 rule files. Secret.","findings":[
  {"path":"a.sh","line":1,"rule":"no-secrets","severity":"blocking","message":"hardcoded token"}]}') \
  || exit 2
BODY_DUPLICATE=$(golden_body '{"summary":"Policy loaded: 26 rule files. Same anchor.","findings":[
  {"path":"rules/b.md","line":7,"rule":"context-writing-style","severity":"blocking","message":"colon attaches a rationale"},
  {"path":"rules/b.md","line":7,"rule":"context-writing-style","severity":"blocking","message":"semicolon attaches another"}]}') \
  || exit 2

# One policy review fixture. Args: <state> <commit> <body>
set_review() {
  MOCK_REVIEWS=$(jq -cn --arg state "$1" --arg commit "$2" --arg body "$3" \
    '[{"id":7,"user":{"login":"github-actions[bot]"},"state":"COMMENTED","commit_id":"0000","submitted_at":"2026-01-01T00:00:00Z","body":"older"},
      {"id":8,"user":{"login":"github-actions[bot]"},"state":$state,"commit_id":$commit,"submitted_at":"2026-01-02T00:00:00Z","body":$body}]')
}

# A complete schema_version 2 operator ruling. Args: <head> <finding-line>...
write_ruling() {
  local head="$1"; shift
  {
    echo "RULING: weighed"
    echo "schema_version: 2"
    echo "AUTHORITY: operator"
    echo "HEAD: ${head}"
    echo "ANSWER: decline the error-handling one, the harness sets it; b.md is presentation only"
    printf '%s\n' "$@"
    echo "ACTION: none"
    echo "UNVERIFIED: none"
  } > "$RULING"
}

gh() {
  case "$1" in
    pr)
      case "$2" in
        view)   echo "$HEAD_SHA" ;;
        checks) echo "$MOCK_CHECKS"; return "$MOCK_CHECKS_RC" ;;
        *) echo "mock gh pr: unsupported: $*" >&2; return 2 ;;
      esac
      ;;
    api)
      shift
      local method="GET" path="" message="" body_file="" saw_paginate=0
      while [[ $# -gt 0 ]]; do
        case "$1" in
          -X) method="$2"; shift 2 ;;
          --paginate) saw_paginate=1; shift ;;
          -f) [[ "$2" == message=* ]] && message="${2#message=}"; shift 2 ;;
          -F) [[ "$2" == body=@* ]] && body_file="${2#body=@}"; method="POST"; shift 2 ;;
          repos/*) path="$1"; shift ;;
          *) shift ;;
        esac
      done
      if [[ "$method" == "PUT" && "$path" == */reviews/8/dismissals ]]; then
        printf 'dismiss %s\n' "$message" >> "$EVENTS"; echo '{}'; return 0
      fi
      if [[ "$method" == "POST" && "$path" == "repos/owner/repo/issues/${ISSUE}/comments" ]]; then
        [[ "$MOCK_COMMENT_RC" -eq 0 ]] || { echo "mock gh: comment POST failed" >&2; return "$MOCK_COMMENT_RC"; }
        cp "$body_file" "$COMMENT_BODY"; echo "comment" >> "$EVENTS"; echo '{}'; return 0
      fi
      case "$path" in
        */compare/*) echo "$path" >> "$COMPARE_LOG"; echo "$MOCK_COMPARE" ;;
        */issues/"${ISSUE}"/comments*)
          [[ $saw_paginate -eq 1 ]] || { echo "mock gh api: comments fetch missing --paginate" >&2; return 99; }
          echo "$MOCK_ISSUE_COMMENTS" ;;
        *reviews*)
          [[ $saw_paginate -eq 1 ]] || { echo "mock gh api: reviews fetch missing --paginate" >&2; return 99; }
          echo "$MOCK_REVIEWS" ;;
        *) echo "mock gh api: unsupported: $method $path" >&2; return 2 ;;
      esac
      ;;
    *) echo "mock gh: unsupported: $*" >&2; return 2 ;;
  esac
}

# The pinned judge's weighing report as a ruling file: judge authority, no
# ANSWER. Args: <head> <finding-line>...
write_judge_ruling() {
  local head="$1"; shift
  {
    echo "RULING: weighed"
    echo "schema_version: 2"
    echo "AUTHORITY: judge"
    echo "HEAD: ${head}"
    printf '%s\n' "$@"
    echo "ACTION: none"
    echo "UNVERIFIED: none"
    echo ""
    echo "1. Reachability cited at run.sh:3; the harness sets the flag."
  } > "$RULING"
}

# Run main in a subshell (it exits); capture stdout and rc.
OUT=""; RC=0
invoke() { RC=0; OUT=$( (main owner repo 5 "$@") 2>"${TMPDIR_TEST}/stderr") || RC=$?; }
invoke_ruled() { invoke --ruling "$RULING" --followup-issue "$ISSUE"; }
# The same runs inside a Herdr team round: HERDR_ENV set for main alone.
main_team() { HERDR_ENV=1 main owner repo 5 "$@"; }
invoke_team() { RC=0; OUT=$( (main_team "$@") 2>"${TMPDIR_TEST}/stderr") || RC=$?; }
invoke_team_ruled() { invoke_team --ruling "$RULING" --followup-issue "$ISSUE" --task t-632; }

# The real binding check, kept under another name before the stub replaces it.
eval "real_$(declare -f verify_judge_ruling)"

# The owner-records binding, stubbed: "ok" unless a case sets MOCK_BINDING to a
# refusal. Records the task and ruling it was asked about.
verify_judge_ruling() {
  printf '%s %s\n' "$1" "$2" > "${TMPDIR_TEST}/binding-call"
  printf '%s' "${MOCK_BINDING:-ok $(python3 -c 'import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],"rb").read()).hexdigest())' "$2")}" > "$3"
}
dismissals() { grep -c '^dismiss ' "$EVENTS"; }
comments() { grep -c '^comment$' "$EVENTS"; }
digest_of_ruling() { python3 -c 'import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],"rb").read()).hexdigest()[:16])' "$RULING"; }

DECLINE_ONE="FINDING: policy skills/x/run.sh:3 error-handling — decline — rule text misread; the harness sets it"
DECLINE_TWO="FINDING: policy rules/b.md:7 context-writing-style — decline — presentation only"
DEFER_TWO="FINDING: policy rules/b.md:7 context-writing-style — defer — reword the bullet"

t_all_covered_posts_followup_then_dismisses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DEFER_TWO"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "dismissed" "$(jq -r .result <<<"$OUT")" || return 1
  local digest; digest=$(digest_of_ruling)
  assert_eq "comment then dismissal" \
    "comment|dismiss JUDGE-RULED: ${digest} covers 2 blocking findings at ${HEAD_SHA}; tracked in #${ISSUE}" \
    "$(paste -sd'|' "$EVENTS")" || return 1
  grep -qF "judge ruling ${digest}" "$COMMENT_BODY" || { echo "    FAIL: comment cites the digest" >&2; return 1; }
  grep -qF "skills/x/run.sh:3\` **error-handling** — declined, won't-fix: rule text misread" "$COMMENT_BODY" \
    || { echo "    FAIL: decline entered as won't-fix" >&2; return 1; }
  grep -qF "rules/b.md:7\` **context-writing-style** — deferred: reword the bullet" "$COMMENT_BODY" \
    || { echo "    FAIL: defer entered" >&2; return 1; }
  assert_eq "no compare at head" "0" "$(wc -l < "$COMPARE_LOG" | tr -d ' ')"
}

t_existing_followup_comment_is_reused() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled   # first run posts the generated entry; capture it
  assert_eq "first run exit" "0" "$RC" || return 1
  MOCK_ISSUE_COMMENTS=$(jq -cn --rawfile b "$COMMENT_BODY" '[{"id":1,"body":("\n" + $b + "\n")}]')
  : > "$EVENTS"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "no second comment" "0" "$(comments)" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_partial_comment_citing_digest_is_not_reused() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_ISSUE_COMMENTS=$(jq -cn --arg b "judge ruling $(digest_of_ruling) — nothing listed" '[{"id":1,"body":$b}]')
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "comment then dismissal" "comment" "$(head -1 "$EVENTS")" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_failed_followup_post_dismisses_nothing() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_COMMENT_RC=1
  invoke_ruled
  assert_eq "exit" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_one_uncovered_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "uncovered" "rules/b.md" "$(jq -r '.uncovered[].path' <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_fix_ruling_leaves_finding_uncovered() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "FINDING: policy rules/b.md:7 context-writing-style — fix"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "uncovered" "rules/b.md" "$(jq -r '.uncovered[].path' <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_different_line_does_not_cover() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "FINDING: policy rules/b.md:9 context-writing-style — decline — other line"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "uncovered" "rules/b.md" "$(jq -r '.uncovered[].path' <<<"$OUT")" || return 1
  assert_unmet "naming no blocking finding" "the unmatched FINDING line" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_same_path_different_rule_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "FINDING: policy rules/b.md:7 review-severity — decline — other rule"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "uncovered" "rules/b.md" "$(jq -r '.uncovered[].path' <<<"$OUT")" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_duplicate_finding_line_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO" "$DEFER_TWO"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "duplicate FINDING" "the duplicate" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_unmatched_finding_line_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO" "FINDING: policy gone.sh:1 error-handling — decline — fixed already"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "gone.sh:1" "the unmatched FINDING line" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_duplicate_review_finding_needs_matching_count() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_DUPLICATE"
  write_ruling "$HEAD_SHA" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "one uncovered" "1" "$(jq '.uncovered | length' <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_duplicate_review_findings_with_same_verdict_dismiss() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_DUPLICATE"
  write_ruling "$HEAD_SHA" "$DECLINE_TWO" \
    "FINDING: policy rules/b.md:7 context-writing-style — decline — second presentation finding"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "dismissed" "dismissed" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "two findings" "2" "$(jq '.findings | length' <<<"$OUT")" || return 1
  assert_eq "two follow-up entries" "2" "$(grep -c 'rules/b.md:7' "$COMMENT_BODY")" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_duplicate_review_findings_with_mixed_verdicts_refuse() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_DUPLICATE"
  write_ruling "$HEAD_SHA" "$DECLINE_TWO" \
    "FINDING: policy rules/b.md:7 context-writing-style — defer — track the second finding"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "different verdicts" "the ambiguous outcomes" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_floor_rule_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_FLOOR"
  write_ruling "$HEAD_SHA" "FINDING: policy a.sh:1 no-secrets — decline — test token"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "floor rule" "the floor" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_failing_check_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_CHECKS='[{"name":"tests","bucket":"fail"},{"name":"lint","bucket":"pending"}]'
  MOCK_CHECKS_RC=8
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "failing check" "the failing check" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_pending_checks_do_not_refuse() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_CHECKS='[{"name":"tests","bucket":"pending"}]'
  MOCK_CHECKS_RC=8
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_not_on_head_is_noop() {
  set_review CHANGES_REQUESTED "$OLD_SHA" "$BODY_TWO"
  write_ruling "$OLD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "noop" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_not_changes_requested_is_noop() {
  set_review COMMENTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "noop" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_idempotent_rerun_is_noop() {
  set_review DISMISSED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "noop" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_unparseable_body_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" $'Summary\n\n## Blocking findings (gate the merge)\n- free text the parser cannot read'
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "Blocking findings" "the unparseable section" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_carry_over_unchanged_path_dismisses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$OLD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_COMPARE='{"status":"ahead","files":[{"filename":"README.md"}]}'
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "compare base...head" "repos/owner/repo/compare/${OLD_SHA}...${HEAD_SHA}" "$(cat "$COMPARE_LOG")" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_carry_over_changed_path_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$OLD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_COMPARE='{"status":"ahead","files":[{"filename":"rules/b.md"}]}'
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_eq "uncovered" "rules/b.md" "$(jq -r '.uncovered[].path' <<<"$OUT")" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_carry_over_diverged_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$OLD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_COMPARE='{"status":"diverged","files":[]}'
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "diverged" "the diverged compare" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_missing_answer_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  grep -v '^ANSWER:' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit without ANSWER" "1" "$RC" || return 1
  assert_unmet "ANSWER:" "the missing answer" || return 1
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  sed 's/^ANSWER:.*/ANSWER:   /' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit with empty ANSWER" "1" "$RC" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_schema_missing_or_other_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  grep -v '^schema_version:' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit without schema_version" "1" "$RC" || return 1
  assert_unmet "schema_version: 2" "the schema" || return 1
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  sed 's/^schema_version: 2$/schema_version: 3/' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit with schema_version 3" "1" "$RC" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

# Args: <invoke-fn> <writer-fn>. A ruling one schema above RULING_SCHEMA.
check_newer_schema_refused_unmodified() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  "$2" "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  local newer=$((RULING_SCHEMA + 1)) before after
  sed "s/^schema_version: ${RULING_SCHEMA}\$/schema_version: ${newer}/" "$RULING" > "${RULING}.tmp" \
    && mv "${RULING}.tmp" "$RULING"
  before=$(digest_of_ruling) || { echo "    FAIL: could not digest the ruling before the run" >&2; return 1; }
  [[ -n "$before" ]] || { echo "    FAIL: empty digest of the ruling before the run" >&2; return 1; }
  "$1"
  after=$(digest_of_ruling) || { echo "    FAIL: could not digest the ruling after the run" >&2; return 1; }
  [[ -n "$after" ]] || { echo "    FAIL: empty digest of the ruling after the run" >&2; return 1; }
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "schema ${newer}, newer than this script accepts (${RULING_SCHEMA}) — update the coding-policy plugin" "the newer schema" || return 1
  assert_eq "ruling bytes unchanged" "$before" "$after" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}
t_standalone_newer_schema_refuses_unmodified() { check_newer_schema_refused_unmodified invoke_ruled write_ruling; }
t_team_round_newer_schema_refuses_unmodified() { check_newer_schema_refused_unmodified invoke_team_ruled write_judge_ruling; }

t_version_1_ruling_is_upgraded_then_read() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  grep -v '^AUTHORITY:' "$RULING" | sed 's/^schema_version: 2$/schema_version: 1/' > "${RULING}.tmp" \
    && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "dismissed" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "upgraded lines" "schema_version: 2|AUTHORITY: operator" \
    "$(grep -E '^(schema_version|AUTHORITY):' "$RULING" | paste -sd'|' -)" || return 1
  grep -qF "$DECLINE_ONE" "$RULING" || { echo "    FAIL: the upgrade kept the FINDING lines" >&2; return 1; }
}

t_team_round_version_1_ruling_refuses_unmodified() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  grep -v '^AUTHORITY:' "$RULING" | sed 's/^schema_version: 2$/schema_version: 1/' > "${RULING}.tmp" \
    && mv "${RULING}.tmp" "$RULING"
  local before after
  before=$(digest_of_ruling) || { echo "    FAIL: could not digest the ruling before the run" >&2; return 1; }
  [[ -n "$before" ]] || { echo "    FAIL: empty digest of the ruling before the run" >&2; return 1; }
  invoke_team_ruled
  after=$(digest_of_ruling) || { echo "    FAIL: could not digest the ruling after the run" >&2; return 1; }
  [[ -n "$after" ]] || { echo "    FAIL: empty digest of the ruling after the run" >&2; return 1; }
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "is malformed — re-dispatch the pinned judge" "the team-round schema" || return 1
  assert_eq "ruling bytes unchanged" "$before" "$after" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_unreadable_ruling_bytes_exit_2_without_traceback() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  printf 'RULING: weighed\nschema_version: 1\nANSWER: \xff\xfe\n' > "$RULING"
  invoke_ruled
  assert_eq "exit" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT" || return 1
  grep -q "rewrite the ruling" "${TMPDIR_TEST}/stderr" || { echo "    FAIL: no actionable diagnostic" >&2; return 1; }
  if grep -q "Traceback" "${TMPDIR_TEST}/stderr"; then echo "    FAIL: traceback on stderr" >&2; return 1; fi
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_malformed_ruling_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  sed '1s/.*/RULING: insufficient — need the call path/' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "insufficient ruling exit" "1" "$RC" || return 1
  assert_unmet "RULING: weighed" "the ruling line" || return 1
  write_ruling "$HEAD_SHA" "FINDING: policy skills/x/run.sh:3 error-handling — decline" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "decline without reason exit" "1" "$RC" || return 1
  assert_unmet "unparseable FINDING" "the FINDING line" || return 1
  write_ruling "${HEAD_SHA:0:12}" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "short HEAD sha exit" "1" "$RC" || return 1
  assert_unmet "HEAD: <40-hex sha>" "the HEAD line" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_list_mode_emits_findings() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  invoke
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "findings" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "blocking only" "skills/x/run.sh:3:error-handling,rules/b.md:7:context-writing-style" \
    "$(jq -r '.findings | map("\(.path):\(.line):\(.rule)") | join(",")' <<<"$OUT")" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_usage_errors_exit_2() {
  RC=0; ( main owner repo ) >/dev/null 2>&1 || RC=$?
  assert_eq "missing pr" "2" "$RC" || return 1
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke --ruling "$RULING"
  assert_eq "ruling without --followup-issue" "2" "$RC" || return 1
  invoke --ruling "${TMPDIR_TEST}/does-not-exist" --followup-issue "$ISSUE"
  assert_eq "unreadable ruling" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT"
}

t_team_round_judge_report_dismisses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DEFER_TWO"
  invoke_team_ruled
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "binding asked about" "t-632 ${RULING}" "$(cat "${TMPDIR_TEST}/binding-call")" || return 1
  assert_eq "result" "dismissed" "$(jq -r .result <<<"$OUT")" || return 1
  assert_eq "comment then dismissal" "comment" "$(head -1 "$EVENTS")" || return 1
  assert_eq "one dismissal" "1" "$(dismissals)"
}

t_team_round_operator_ruling_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_team_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "pinned judge weighs" "the team-round authority" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_unbound_judge_ruling_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_BINDING="not the report supervision enrolled for judge dispatch d1"
  invoke_team_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "not the pinned judge's enrolled weighing report" "the unbound ruling" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

# The real check reaches the sibling foreman and turns its refusal into a
# reason: empty XDG homes hold no pinned judge and no dispatch state.
t_real_binding_reports_the_foreman_refusal() {
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE"
  local out="${TMPDIR_TEST}/real-binding" rc=0
  XDG_CONFIG_HOME="${TMPDIR_TEST}/xdg-config" XDG_STATE_HOME="${TMPDIR_TEST}/xdg-state" \
    real_verify_judge_ruling t-632 "$RULING" "$out" 2>"${TMPDIR_TEST}/stderr" || rc=$?
  assert_eq "check ran" "0" "$rc" || return 1
  [[ -s "$out" && "$(cat "$out")" != "ok" ]] || { echo "    FAIL: expected a refusal reason, got '$(cat "$out")'" >&2; return 1; }
}

# A hostile CDPATH must not redirect the script-dir resolver (#637): a
# relative `cd` would land in the decoy and print its path, so the team-round
# binding would look for a foreman that is not the sibling one.
t_hostile_cdpath_keeps_the_sibling_foreman() {
  local decoy="${TMPDIR_TEST}/decoy" stage="${TMPDIR_TEST}/stage" out
  mkdir -p "${decoy}/release" "${stage}/release" "${stage}/herdr-foreman" \
    || { echo "    FAIL: cannot build the CDPATH fixture" >&2; return 1; }
  cp "$SCRIPT" "${stage}/release/dismiss-ruled-review.sh" || { echo "    FAIL: cannot stage the script" >&2; return 1; }
  printf '#!/usr/bin/env bash\necho "sibling $*" > "%s"\necho "{\\"sha256\\": \\"%s\\"}"\nexit 0\n' "${TMPDIR_TEST}/foreman-called" "$(printf 'a%.0s' {1..64})" \
    > "${stage}/herdr-foreman/foreman.sh" || { echo "    FAIL: cannot stage the foreman stub" >&2; return 1; }
  rm -f "${TMPDIR_TEST}/foreman-called"
  out="${TMPDIR_TEST}/hostile-binding"
  ( cd "$stage" && CDPATH="$decoy" bash -c 'source release/dismiss-ruled-review.sh; set +e; verify_judge_ruling t-632 /r/x.md "$1"' _ "$out" ) \
    2>"${TMPDIR_TEST}/stderr" || { echo "    FAIL: the staged binding check exited non-zero: $(cat "${TMPDIR_TEST}/stderr")" >&2; return 1; }
  assert_eq "binding result" "ok $(printf 'a%.0s' {1..64})" "$(cat "$out")" || return 1
  assert_eq "sibling foreman ran" "sibling verify-ruling --task t-632 --ruling /r/x.md" "$(cat "${TMPDIR_TEST}/foreman-called")"
}

t_ruling_changed_since_verification_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  MOCK_BINDING="ok $(printf '0%.0s' {1..64})"
  invoke_team_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "ruling changed since verification — re-run" "the digest mismatch" || return 1
  assert_eq "zero comments" "0" "$(comments)" || return 1
  assert_eq "zero dismissals" "0" "$(dismissals)"
}

# The real binding against a staged foreman stub. Args: <stub-exit> <stub-stderr>.
stage_foreman() {
  local stage="${TMPDIR_TEST}/foreman-stage"
  mkdir -p "${stage}/release" "${stage}/herdr-foreman" || { echo "fatal: cannot stage the foreman" >&2; exit 2; }
  printf '%s' "$2" > "${stage}/stderr" || { echo "fatal: cannot stage the foreman stderr" >&2; exit 2; }
  printf '#!/usr/bin/env bash\ncat "%s" >&2\nexit %s\n' "${stage}/stderr" "$1" > "${stage}/herdr-foreman/foreman.sh" \
    || { echo "fatal: cannot stage the foreman stub" >&2; exit 2; }
  STAGED_DIR="${stage}/release"
}
invoke_team_real_binding() {
  RC=0
  # shellcheck disable=SC2034,SC2317  # DISMISS_DIR is read by the sourced real_verify_judge_ruling; the override runs indirectly via main_team.
  OUT=$( (DISMISS_DIR="$STAGED_DIR"; verify_judge_ruling() { real_verify_judge_ruling "$@"; }
          main_team --ruling "$RULING" --followup-issue "$ISSUE" --task t-632) 2>"${TMPDIR_TEST}/stderr") || RC=$?
}

t_foreman_refusal_is_unmet() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  stage_foreman 1 $'foreman: a warning line first\n{\n  "error": "usage_error",\n  "message": "not the weighing brief",\n  "details": {}\n}\n'
  invoke_team_real_binding
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "not the weighing brief" "the foreman refusal" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_foreman_usage_exit_is_a_tool_error() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  stage_foreman 2 $'usage: foreman [-h] COMMAND\nforeman: error: unrecognized arguments\n'
  invoke_team_real_binding
  assert_eq "exit" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_foreman_exit_1_with_garbage_is_a_tool_error() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  stage_foreman 1 $'Traceback (most recent call last):\n  boom\n'
  invoke_team_real_binding
  assert_eq "exit" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT" || return 1
  grep -q "reinstall the coding-policy plugin" "${TMPDIR_TEST}/stderr" || { echo "    FAIL: no actionable message" >&2; return 1; }
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_team_round_ruling_without_task_is_usage() {
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_team --ruling "$RULING" --followup-issue "$ISSUE"
  assert_eq "exit" "2" "$RC" || return 1
  assert_eq "stdout empty" "" "$OUT"
}

t_standalone_judge_ruling_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_judge_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "operator is the judge" "the standalone authority" || return 1
  assert_eq "nothing posted" "0" "$(wc -l < "$EVENTS" | tr -d ' ')"
}

t_missing_authority_refuses() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  grep -v '^AUTHORITY:' "$RULING" > "${RULING}.tmp" && mv "${RULING}.tmp" "$RULING"
  invoke_ruled
  assert_eq "exit" "1" "$RC" || return 1
  assert_unmet "AUTHORITY:" "the missing authority" || return 1
  assert_eq "no dismissal" "0" "$(dismissals)"
}

t_team_round_list_mode_emits_findings() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  invoke_team
  assert_eq "exit" "0" "$RC" || return 1
  assert_eq "result" "findings" "$(jq -r .result <<<"$OUT")"
}

# End to end on the marker: the dismissal message this script actually sends
# is what poll-pr-reviews.sh must read as RULED and dismiss-stale-reviews.sh
# must accept as an all-clear. Each consumer runs in its own process against a
# PATH-stubbed gh serving the review list and a timeline carrying that message.
READER_STUB="${TMPDIR_TEST}/reader-stub"
mkdir -p "$READER_STUB" || { echo "fatal: cannot create $READER_STUB" >&2; exit 2; }
cat > "${READER_STUB}/gh" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
args="$*"
case "$1" in
  pr)
    case "$2" in
      view)   printf '{"mergeStateStatus":"CLEAN","mergeable":"MERGEABLE","headRefOid":"%s"}\n' "$STUB_HEAD" ;;
      checks) echo '[]' ;;
      *) echo "reader stub: unsupported: $args" >&2; exit 2 ;;
    esac ;;
  api)
    if [[ "$2" == "graphql" ]]; then echo '[]'; exit 0; fi
    if [[ "$args" == *"-X PUT"* ]]; then echo "$args" >> "$STUB_LOG"; echo '{}'; exit 0; fi
    case "$args" in
      *timeline*) cat "$STUB_TIMELINE" ;;
      *reviews*)  cat "$STUB_REVIEWS" ;;
      *comments*) echo '[]' ;;
      *) echo "reader stub: unsupported: $args" >&2; exit 2 ;;
    esac ;;
  *) echo "reader stub: unsupported: $args" >&2; exit 2 ;;
esac
SH
chmod +x "${READER_STUB}/gh"

t_sent_marker_reads_ruled_and_sweeps() {
  set_review CHANGES_REQUESTED "$HEAD_SHA" "$BODY_TWO"
  write_ruling "$HEAD_SHA" "$DECLINE_ONE" "$DECLINE_TWO"
  invoke_ruled
  assert_eq "writer exit" "0" "$RC" || return 1
  local sent; sent=$(sed -n 's/^dismiss //p' "$EVENTS")
  [[ -n "$sent" ]] || { echo "    FAIL: no dismissal message captured" >&2; return 1; }
  jq -cn --arg head "$HEAD_SHA" \
    '[{"id":7,"user":{"login":"github-actions[bot]"},"state":"CHANGES_REQUESTED","commit_id":"0000","submitted_at":"2026-01-01T00:00:00Z","body":"older"},
      {"id":8,"user":{"login":"github-actions[bot]"},"state":"DISMISSED","commit_id":$head,"submitted_at":"2026-01-02T00:00:00Z","body":"ruled"}]' \
    > "${TMPDIR_TEST}/reader-reviews.json"
  jq -cn --arg m "$sent" '[{"event":"review_dismissed","dismissed_review":{"review_id":8,"state":"changes_requested","dismissal_message":$m}}]' \
    > "${TMPDIR_TEST}/reader-timeline.json"
  : > "${TMPDIR_TEST}/reader-log"
  local stub_env=(STUB_HEAD="$HEAD_SHA" STUB_REVIEWS="${TMPDIR_TEST}/reader-reviews.json"
                  STUB_TIMELINE="${TMPDIR_TEST}/reader-timeline.json" STUB_LOG="${TMPDIR_TEST}/reader-log"
                  PATH="${READER_STUB}:${PATH}")
  local snap swept
  snap=$(env "${stub_env[@]}" bash "${RELEASE_DIR}/poll-pr-reviews.sh" owner repo 5) \
    || { echo "    FAIL: poll exited non-zero" >&2; return 1; }
  assert_eq "poll reads RULED" "RULED" "$(jq -r '.reviews.codex.state' <<<"$snap")" || return 1
  swept=$(env "${stub_env[@]}" bash "${RELEASE_DIR}/dismiss-stale-reviews.sh" owner repo 5) \
    || { echo "    FAIL: dismiss-stale exited non-zero" >&2; return 1; }
  assert_eq "older CR swept" "7" "$(jq -r '.dismissed | map(.review_id) | join(",")' <<<"$swept")" || return 1
  grep -q "reviews/7/dismissals" "${TMPDIR_TEST}/reader-log" || { echo "    FAIL: sweep PUT not sent" >&2; return 1; }
}

# `run_suite`, not `main`: the sourced script under test owns `main`.
# Progress goes to stderr; stdout carries one JSON result.
run_suite() {
  echo "test_dismiss_ruled_review.sh" >&2
  run "covered: follow-up comment posted, then dismissal" t_all_covered_posts_followup_then_dismisses
  run "an existing follow-up comment is reused"       t_existing_followup_comment_is_reused
  run "a partial comment citing the digest is not reused" t_partial_comment_citing_digest_is_not_reused
  run "a failed follow-up post dismisses nothing"     t_failed_followup_post_dismisses_nothing
  run "one uncovered finding refuses"                 t_one_uncovered_refuses
  run "a fix ruling leaves the finding uncovered"     t_fix_ruling_leaves_finding_uncovered
  run "a different line does not cover"               t_different_line_does_not_cover
  run "same path, different rule refuses"             t_same_path_different_rule_refuses
  run "a duplicate FINDING line refuses"              t_duplicate_finding_line_refuses
  run "an unmatched FINDING line refuses"             t_unmatched_finding_line_refuses
  run "same-line findings need matching ruling count" t_duplicate_review_finding_needs_matching_count
  run "same-line findings with one verdict dismiss"   t_duplicate_review_findings_with_same_verdict_dismiss
  run "same-line findings with mixed verdicts refuse"  t_duplicate_review_findings_with_mixed_verdicts_refuse
  run "a floor rule refuses"                          t_floor_rule_refuses
  run "a failing check refuses"                       t_failing_check_refuses
  run "pending checks do not refuse"                  t_pending_checks_do_not_refuse
  run "a review not on the head is a noop"            t_not_on_head_is_noop
  run "a non-CHANGES_REQUESTED review is a noop"      t_not_changes_requested_is_noop
  run "an idempotent re-run is a noop"                t_idempotent_rerun_is_noop
  run "an unparseable body refuses"                   t_unparseable_body_refuses
  run "carry-over with the path unchanged dismisses"  t_carry_over_unchanged_path_dismisses
  run "carry-over with the path changed refuses"      t_carry_over_changed_path_refuses
  run "carry-over across a diverged compare refuses"  t_carry_over_diverged_refuses
  run "a missing or empty ANSWER refuses"             t_missing_answer_refuses
  run "a missing or other schema_version refuses"             t_schema_missing_or_other_refuses
  run "standalone: a newer schema refuses, unmodified" t_standalone_newer_schema_refuses_unmodified
  run "team round: a newer schema refuses, unmodified" t_team_round_newer_schema_refuses_unmodified
  run "a version-1 ruling is upgraded, then read"     t_version_1_ruling_is_upgraded_then_read
  run "team round: a version-1 ruling refuses, unmodified" t_team_round_version_1_ruling_refuses_unmodified
  run "non-UTF-8 ruling bytes exit 2, no traceback"   t_unreadable_ruling_bytes_exit_2_without_traceback
  run "a malformed ruling refuses"                    t_malformed_ruling_refuses
  run "list mode emits the blocking findings"         t_list_mode_emits_findings
  run "usage errors exit 2"                           t_usage_errors_exit_2
  run "team round: the judge's report dismisses"      t_team_round_judge_report_dismisses
  run "team round: an operator ruling refuses"        t_team_round_operator_ruling_refuses
  run "team round: an unbound judge ruling refuses"   t_unbound_judge_ruling_refuses
  run "team round: a ruling without --task is usage"  t_team_round_ruling_without_task_is_usage
  run "a foreman refusal is unmet"                    t_foreman_refusal_is_unmet
  run "a foreman usage exit is a tool error"          t_foreman_usage_exit_is_a_tool_error
  run "foreman exit 1 with garbage is a tool error"   t_foreman_exit_1_with_garbage_is_a_tool_error
  run "a ruling changed since verification refuses"   t_ruling_changed_since_verification_refuses
  run "a hostile CDPATH keeps the sibling foreman"    t_hostile_cdpath_keeps_the_sibling_foreman
  run "the real binding reports the foreman refusal"  t_real_binding_reports_the_foreman_refusal
  run "standalone: a judge ruling refuses"            t_standalone_judge_ruling_refuses
  run "a missing AUTHORITY line refuses"              t_missing_authority_refuses
  run "team round: list mode emits the findings"      t_team_round_list_mode_emits_findings
  run "the sent marker reads RULED and sweeps"        t_sent_marker_reads_ruled_and_sweeps
  printf '{"suite":"test_dismiss_ruled_review.sh","passed":%d,"failed":%d}\n' "$PASS_COUNT" "$FAIL_COUNT"
  [[ $FAIL_COUNT -eq 0 ]]
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
  run_suite
fi

skills

README.md

tile.json