forgedock 1.15.0 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env bash
2
+ # review-delta-mode.sh: sourced helper for commands/review-pr.md (the review-delta mode functions).
3
+ # SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios
4
+ # SPDX-License-Identifier: AGPL-3.0-or-later
5
+ #
6
+ # Source it, never exec it; the spec resolves it with `forge_resolve lib/review-delta-mode.sh` (install roots only, never the
7
+ # working directory or the PR checkout). When it is unresolved the spec defines FULL-only fallbacks, so a missing helper
8
+ # can only cause a full review, never a skipped one.
9
+ is_sha() { case "${1}" in *[!0-9a-f]*|"") return 1 ;; esac; [ "${#1}" -eq 40 ] || [ "${#1}" -eq 64 ]; }
10
+ # Prints "<MODE> <ARG> <FULL_ROUNDS>" from scripts/review-delta.sh: "FULL - n", "DELTA <reviewed-sha> n" or "BASE_SYNC_ONLY <reviewed-sha> n".
11
+ # Needs REPO PR_NUMBER REVIEW_SHA BASE_BRANCH TRUSTED_SCRIPT REVIEW_DELTA_SCRIPT in scope. Every failure (unresolved script, bad output, bad SHA, empty delta) prints FULL, never a skipped review.
12
+ review_delta_mode() {
13
+ local out l1 l2 kind arg from to rounds=0 top
14
+ is_sha "$REVIEW_SHA" || { echo "FULL - 0"; return 0; }
15
+ if [ -z "$TRUSTED_SCRIPT" ] || [ -z "$REVIEW_DELTA_SCRIPT" ] || [ -z "$BASE_BRANCH" ]; then echo "FULL - 0"; return 0; fi
16
+ top=$(git rev-parse --show-toplevel 2>/dev/null) || top=""
17
+ [ -n "$top" ] || { echo "FULL - 0"; return 0; }
18
+ out=$(bash "$REVIEW_DELTA_SCRIPT" --pr "$PR_NUMBER" --head "$REVIEW_SHA" --base "$BASE_BRANCH" --trusted-script "$TRUSTED_SCRIPT" --repo "$REPO" --repo-path "$top" 2>/dev/null) || out=""
19
+ l1=$(printf '%s\n' "$out" | sed -n 1p); l2=$(printf '%s\n' "$out" | sed -n 2p)
20
+ case "$l2" in FULL_ROUNDS=*) rounds="${l2#FULL_ROUNDS=}" ;; esac
21
+ case "$rounds" in ''|*[!0-9]*) echo "FULL - 0"; return 0 ;; esac
22
+ kind="${l1%% *}"; arg="${l1#* }"
23
+ if [ "$kind" = "BASE_SYNC_ONLY" ] && is_sha "$arg" && [ "$arg" != "$REVIEW_SHA" ]; then echo "BASE_SYNC_ONLY $arg $rounds"; return 0; fi
24
+ if [ "$kind" = "DELTA" ]; then
25
+ from="${arg%%..*}"; to="${arg##*..}"
26
+ if is_sha "$from" && [ "$to" = "$REVIEW_SHA" ] && [ "$from" != "$to" ]; then echo "DELTA $from $rounds"; return 0; fi
27
+ fi
28
+ echo "FULL - $rounds"
29
+ }
30
+ # Prints the Carried-From-SHA only when a TRUSTED FORGE:REVIEW-CARRIED record for this head names it AND the resolver
31
+ # still answers BASE_SYNC_ONLY from that same reviewed SHA right now. Needs COMMENTS_JSON as well. Marker text alone never counts.
32
+ carry_verified_from() {
33
+ local kind from rounds n
34
+ if [ -z "$TRUSTED_SCRIPT" ] || [ -z "$COMMENTS_JSON" ]; then return 0; fi
35
+ read -r kind from rounds <<< "$(review_delta_mode)"
36
+ [ "$kind" = "BASE_SYNC_ONLY" ] || return 0
37
+ n=$(printf '%s' "$COMMENTS_JSON" | bash "$TRUSTED_SCRIPT" count "\\A(?=[\\s\\S]*\\nReviewed-SHA: ${REVIEW_SHA}\\r?(\\n|$))(?=[\\s\\S]*\\nCarried-From-SHA: ${from}\\r?(\\n|$))<!-- FORGE:REVIEW-CARRIED -->" 2>/dev/null || echo "")
38
+ case "$n" in ''|*[!0-9]*) return 0 ;; esac
39
+ [ "$n" -ge 1 ] && printf '%s' "$from"
40
+ return 0
41
+ }
@@ -227,10 +227,10 @@ bash "$LINT" --expect nokey "$T/p27" >/dev/null 2>&1; [ $? -eq 2 ] && PASS=$((PA
227
227
  check "mid-line CR not stripped" 1 "$T/p25"
228
228
 
229
229
  # 10. Spec snippet enforcement (forge#3070): extract the lint gate from the spec and run it in a loop.
230
- # Gate = from the bootstrap marker to the end of its fenced code block (not a hard-coded count of
230
+ # Gate = from the forge_resolve stub locator line to the end of its fenced code block (not a hard-coded count of
231
231
  # top-level fi lines, which breaks whenever the bootstrap gains or loses a conditional).
232
- # Several spec blocks carry the bootstrap marker (e.g. the recovery-claim gate, forge#3172); pick the one holding the lint gate.
233
- awk '/^# FORGE_ROOT bootstrap/{f=1;buf=""} f&&/^```/{if(buf ~ /LINT_REFUSED_ISSUES/){printf "%s",buf;exit} f=0} f{buf=buf $0 "\n"}' "$SPEC" > "$T/gate"
232
+ # Several spec blocks carry the stub locator (e.g. the recovery-claim gate, forge#3172); pick the one holding the lint gate.
233
+ awk '/^type forge_resolve >\/dev\/null/{f=1;buf=""} f&&/^```/{if(buf ~ /LINT_REFUSED_ISSUES/){printf "%s",buf;exit} f=0} f{buf=buf $0 "\n"}' "$SPEC" > "$T/gate"
234
234
  [ -s "$T/gate" ] || { FAILN=$((FAILN+1)); echo "FAIL: could not extract spec lint gate"; }
235
235
  gate_refused() { # prompt-file home -> prints refusal entries or LAUNCHED
236
236
  ( LINT_REFUSED_ISSUES=(); RENDERED_PROMPT="$(cat "$1")"; FORGEDOCK_HOME="$2"; unset FORGE_HOME; reset_vals
@@ -92,15 +92,32 @@ fence_file() { # name pattern -> $TMP/<name>.sh (placeholders filled)
92
92
  }
93
93
 
94
94
  # ---- 0. structure ---------------------------------------------------------------------------------------------------
95
- n=$(count_blocks review-pr-delta-mode)
96
- [ "$n" -ge 6 ] && ok || bad "expected the review-delta mode snippet in every consuming fence (3C mode, carry post, Phase 4, 5, 6A, 9), found $n"
97
- distinct=$(awk '/^# BEGIN review-pr-delta-mode$/ {on=1; buf=""} on {buf = buf $0 "\n"} /^# END review-pr-delta-mode$/ && on {on=0; print buf "\0"}' "$SPEC" | tr -d '\n' | sed 's/\x0/\n/g' | sort -u | grep -c . || true)
98
- [ "$distinct" = 1 ] && ok || bad "review-delta mode snippet copies differ ($distinct distinct)"
95
+ # The mode functions live in ONE sourced helper (scripts/lib/review-delta-mode.sh); every consuming fence sources it through forge_resolve
96
+ # with a FULL-only fallback, so an unresolved helper can only mean a full review.
97
+ HELPER="$ROOT/scripts/lib/review-delta-mode.sh"
98
+ [ -f "$HELPER" ] && ok || bad "scripts/lib/review-delta-mode.sh must exist"
99
+ n=$(grep -c '^_dm=$(forge_resolve lib/review-delta-mode.sh)' "$SPEC")
100
+ [ "$n" -ge 6 ] && ok || bad "expected the review-delta helper source line in every consuming fence (3C mode, carry post, Phase 4, 5, 6A, 9), found $n"
101
+ distinct=$(grep '^_dm=$(forge_resolve lib/review-delta-mode.sh)' "$SPEC" | sort -u | grep -c . || true)
102
+ [ "$distinct" = 1 ] && ok || bad "review-delta helper source lines differ ($distinct distinct)"
103
+ [ "$(count_blocks review-pr-delta-mode)" = 0 ] && ok || bad "inline review-delta mode copies must not remain in the spec"
104
+ grep -q '^_dm=.*review_delta_mode() { echo "FULL - 0"; }' "$SPEC" && ok || bad "the helper source line must carry a FULL-only fallback"
105
+ # every source line is preceded by a locator in the same fence (a fresh shell has no forge_resolve)
106
+ miss=$(awk '/^```/{loc=0} /^type forge_resolve >\/dev\/null/{loc=1} /^_dm=\$\(forge_resolve lib\/review-delta-mode.sh\)/&&!loc{b++} END{print b+0}' "$SPEC")
107
+ [ "$miss" = 0 ] && ok || bad "$miss helper source line(s) lack a forge_resolve locator in the same fence"
108
+ # unresolved helper: the fallback answers FULL and carries nothing
109
+ fb=$(grep -m1 '^_dm=.*review_delta_mode() { echo "FULL - 0"; }' "$SPEC")
110
+ got=$(bash -c "forge_resolve() { :; }; $fb; review_delta_mode; printf 'carry=[%s]' \"\$(carry_verified_from)\"")
111
+ [ "$got" = "FULL - 0
112
+ carry=[]" ] && ok || bad "an unresolved helper must fall back to FULL (got '$got')"
113
+ # resolved helper: the real functions load
114
+ got=$(bash -c "forge_resolve() { echo '$HELPER'; }; $fb; type -t is_sha")
115
+ [ "$got" = "function" ] && ok || bad "a resolved helper must define the mode functions (got '$got')"
99
116
  grep -qF 'scripts/review-delta.sh' "$SPEC" && ok || bad "spec does not name scripts/review-delta.sh"
100
117
 
101
118
  # ---- 1. resolver block: trusted install only -------------------------------------------------------------------------
102
119
  mkrepo; HEAD=$(sha HEAD)
103
- awk '/^[ ]*# HELPER_SCRIPT resolver \(/ && index($0, "(REVIEW_DELTA_SCRIPT;") {inb=1} inb {print} inb && /^done <<< "\$_tc"$/ {exit}' "$SPEC" > "$TMP/rd_resolver.sh"
120
+ fence_with 'REVIEW_DELTA_SCRIPT=$(forge_resolve review-delta.sh)' | grep -E '^type forge_resolve >/dev/null|^REVIEW_DELTA_SCRIPT=\$\(forge_resolve ' > "$TMP/rd_resolver.sh"
104
121
  [ -s "$TMP/rd_resolver.sh" ] && ok || bad "no canonical REVIEW_DELTA_SCRIPT resolver block in the spec"
105
122
  mkdir -p "$W/scripts"; printf '#!/usr/bin/env bash\necho "BASE_SYNC_ONLY %s"\necho FULL_ROUNDS=9\n' "$HEAD" > "$W/scripts/review-delta.sh"
106
123
  got=$(cd "$W" && HOME="$TMP/home" FORGE_ROOT="$ROOT" CLAUDE_CONFIG_DIR="" bash -c "$(cat "$TMP/rd_resolver.sh"); printf %s \"\$REVIEW_DELTA_SCRIPT\"")
@@ -191,8 +208,8 @@ W=$BS_W; R=$BS_R; HEAD=$BS_HEAD
191
208
  fence_file carry "CARRY_RECORD: POSTED" || exit 1
192
209
  run_carry() { subst "$TMP/carry.raw" > "$TMP/carry.sh"; run_fence "$TMP/carry.sh" "$@"; }
193
210
  verified() { # prints the verified Carried-From-SHA for the current $FAKE_COMMENTS using the real snippet
194
- { marked_block review-pr-delta-mode; echo 'COMMENTS_JSON=$(cat "$FAKE_COMMENTS"); carry_verified_from'; } > "$TMP/cv_body.sh"
195
- { cat "$TMP/carry.raw" | awk '/^# BEGIN review-pr-delta-mode$/ {exit} {print}'; cat "$TMP/cv_body.sh"; } | subst /dev/stdin > "$TMP/cv.sh"
211
+ { cat "$HELPER"; echo 'COMMENTS_JSON=$(cat "$FAKE_COMMENTS"); carry_verified_from'; } > "$TMP/cv_body.sh"
212
+ { cat "$TMP/carry.raw" | awk '/^_dm=\$\(forge_resolve lib\/review-delta-mode\.sh\)/ {exit} {print}'; cat "$TMP/cv_body.sh"; } | subst /dev/stdin > "$TMP/cv.sh"
196
213
  run_fence "$TMP/cv.sh" FAKE_COMMENTS="$FAKE_COMMENTS"
197
214
  }
198
215
  panel_items "$R" | jq -s '.' > "$FAKE_COMMENTS"
@@ -96,9 +96,13 @@ for _s in "$SPEC" "$SPEC_MAIN"; do
96
96
  if grep -qE 'BLOCKED.*classifier unavailable' "$_s" && ! grep -qF 'echo script || echo manual' "$_s" && ! grep -qF 'classifier=manual' "$_s" && ! grep -qF 'classifier-unavailable' "$_s"; then ok; else bad "$(basename "$_s") must fail closed with BLOCKED classifier unavailable and have no manual fallback"; fi
97
97
  done
98
98
  # (8) fresh-shell reload (forge#3654): the FENCE_BOOTSTRAP lines must reload PR_NUMBER / ALL_PR_NUMBERS from the scratchpad, stay empty (with a warning) when nothing was persisted, and reject a tampered number
99
- awk '/^[^ `#].* # FENCE_BOOTSTRAP/ && !seen[$0]++' "$SPEC" > "$TMP/boot.sh"
100
- [ "$(wc -l < "$TMP/boot.sh")" -eq 8 ] && ok || bad "FENCE_BOOTSTRAP block expected 8 distinct lines (got $(wc -l < "$TMP/boot.sh"))"
101
- [ "$(grep -c '^# Fence bootstrap' "$SPEC")" -ge 3 ] && ok || bad "bootstrap must be carried by 0B.1 and both 7B.5 fences"
99
+ # (forge#3778) the spec carries a byte-identical stub per fence; the body lives in scripts/lib/fence-bootstrap.sh, which is SOURCED
100
+ # in a fresh shell (the stub's locator + source line is executed for real, so the stub itself is covered too).
101
+ [ "$(grep '# FENCE_BOOTSTRAP$' "$SPEC" | sort -u | wc -l | tr -d ' ')" -eq 1 ] && ok || bad "FENCE_BOOTSTRAP stubs must be byte-identical"
102
+ [ "$(grep -c '# FENCE_BOOTSTRAP$' "$SPEC")" -ge 3 ] && ok || bad "bootstrap must be carried by 0B.1 and both 7B.5 fences"
103
+ grep '^type forge_resolve >/dev/null' "$SPEC" | sed 1q > "$TMP/boot.sh"
104
+ grep '# FENCE_BOOTSTRAP$' "$SPEC" | sed 1q >> "$TMP/boot.sh"
105
+ [ "$(wc -l < "$TMP/boot.sh")" -eq 2 ] && ok || bad "bootstrap stub (locator + source line) not found"
102
106
  # forge#3681: EVERY bash fence after Phase 0B that reads cross-fence state must carry the bootstrap (a fresh Bash call loses it)
103
107
  UNCOVERED=$(awk '
104
108
  /^```bash/ { infence=1; body=""; start=NR; next }
@@ -113,13 +117,41 @@ grep -q 'test_gate_verdict' "$SPEC" && grep -q 'launched_review_agents' "$SPEC"
113
117
  if grep -qE '\$_SD/(test_gate_verdict|test_gate_reason|launched_review_agents)|\.forge-scratch\}/launched_review_agents' "$SPEC"; then bad "gate/launched-agent scratch files must be keyed by \${PR_NUMBER}_"; else ok; fi
114
118
  grep -qF ': > "$_SD/${PR_NUMBER}_launched_review_agents"' "$SPEC" && grep -qF 'rm -f "$_SD/${PR_NUMBER}_test_gate_verdict" "$_SD/${PR_NUMBER}_test_gate_reason"' "$SPEC" && ok || bad "Phase 2 must truncate and Phase 6.5 must rm -f the PR-keyed scratch files in executable commands"
115
119
  if awk '/^### 7E:/,/^### 7F:/' "$SPEC" | grep -qF '{GH_REPO}'; then bad "7E must not use the {GH_REPO} template token"; else ok; fi
120
+ # (8b) forge#3733: Phase 6.75 fails closed on an empty/absent launched-agent list or empty PR_NUMBER; Phase 6 fails closed on a bad SELECTED_AGENT_COUNT
121
+ F675=$(awk '/^### Phase 6.75/,/^### 7A/' "$SPEC" | awk '/^```bash/{f=1;next} /^```/{if(f)exit} f')
122
+ GUARD_LN=$(printf '%s\n' "$F675" | grep -n 'launched-agent list is empty or unreadable' | head -1 | cut -d: -f1)
123
+ LOOP_LN=$(printf '%s\n' "$F675" | grep -n '^for AGENT_DOMAIN in' | head -1 | cut -d: -f1)
124
+ [ -n "$GUARD_LN" ] && [ -n "$LOOP_LN" ] && [ "$GUARD_LN" -lt "$LOOP_LN" ] && ok || bad "6.75 empty-list guard must precede the for AGENT_DOMAIN loop"
125
+ printf '%s\n' "$F675" | sed -n "1,$((LOOP_LN-1))p" | grep -v '^[[:space:]]*gh ' > "$TMP/f675.sh"
126
+ mkdir -p "$TMP/sd9/empty" "$TMP/sd9/full" "$TMP/bin9"
127
+ printf '#!/bin/sh\necho stub-value\n' > "$TMP/bin9/yq"; printf '#!/bin/sh\nexit 0\n' > "$TMP/bin9/gh"; chmod +x "$TMP/bin9/yq" "$TMP/bin9/gh"
128
+ : > "$TMP/sd9/empty/42_launched_review_agents"
129
+ printf 'security\n' > "$TMP/sd9/full/42_launched_review_agents"
130
+ run675() { ( unset LAUNCHED_REVIEW_AGENTS REVIEW_SHA_FULL; export PATH="$TMP/bin9:$PATH" FORGE_SCRATCHPAD="$1" HOME="$TMP/nohome" FORGEDOCK_HOME="$ROOT"; [ -n "$2" ] && export PR_NUMBER="$2"; bash "$TMP/f675.sh" 2>&1; echo "rc=$?" ); }
131
+ for _case in "$TMP/sd9/empty|42" "$TMP/sd9/none|42" "$TMP/sd9/full|"; do
132
+ OUT9=$(run675 "${_case%%|*}" "${_case##*|}")
133
+ case "$OUT9" in *"REVIEW DELIVERY FAILURE: launched-agent list is empty or unreadable"*"rc=1"*) ok ;; *) bad "6.75 must exit 1 for case '$_case' (got '$OUT9')" ;; esac
134
+ done
135
+ OUT9=$(run675 "$TMP/sd9/full" 42)
136
+ case "$OUT9" in *"launched-agent list is empty"*) bad "6.75 guard must not fire for a non-empty list (got '$OUT9')" ;; *) ok ;; esac
137
+ # Phase 6 SELECTED_AGENT_COUNT validation: static order + behaviour of the reload/validate lines
138
+ F6=$(awk '/Selected isolated reviewers/{exit} {print}' "$SPEC" | awk '/^```bash/{b=""; f=1; next} /^```/{f=0; next} f{b=b $0 "\n"; last=b} END{printf "%s", last}')
139
+ printf '%s' "$F6" | grep -qF 'SELECTED_COUNT_INVALID' && ok || bad "Phase 6 fence must validate SELECTED_AGENT_COUNT (SELECTED_COUNT_INVALID)"
140
+ printf '%s' "$F6" | grep -F 'SELECTED_AGENT_COUNT=' | grep -F 'launched_review_agents' > "$TMP/sel.sh"
141
+ printf '%s\n' 'SELECTED_COUNT_INVALID=false' "$(printf '%s' "$F6" | grep -F 'case "${SELECTED_AGENT_COUNT:-}"')" > "$TMP/selcase.sh"
142
+ for _c in "$TMP/sd9/empty|42" "$TMP/sd9/none|42" "$TMP/sd9/full|42"; do
143
+ OUT9=$( ( unset SELECTED_AGENT_COUNT; _SD="${_c%%|*}"; PR_NUMBER="${_c##*|}"; . "$TMP/sel.sh"; . "$TMP/selcase.sh"; echo "$SELECTED_COUNT_INVALID|$SELECTED_AGENT_COUNT" ) 2>&1 )
144
+ case "${_c%%|*}" in */full) [ "$OUT9" = "false|1" ] && ok || bad "Phase 6: one launched agent must give SELECTED_AGENT_COUNT=1 (got '$OUT9')" ;; *) [ "$OUT9" = "true|0" ] && ok || bad "Phase 6: empty/absent list must be invalid (got '$OUT9')" ;; esac
145
+ done
146
+ OUT9=$( ( SELECTED_AGENT_COUNT="abc"; . "$TMP/selcase.sh"; echo "$SELECTED_COUNT_INVALID" ) 2>&1 )
147
+ [ "$OUT9" = "true" ] && ok || bad "Phase 6: non-integer SELECTED_AGENT_COUNT must be invalid (got '$OUT9')"
116
148
  mkdir -p "$TMP/sd8/full" "$TMP/sd8/empty" "$TMP/sd8/bad" "$TMP/bin"
117
149
  printf '#!/bin/sh\necho stub-value\n' > "$TMP/bin/yq"; chmod +x "$TMP/bin/yq"
118
150
  printf '42\n' > "$TMP/sd8/full/staging_pr_number"; printf '7\n8\n' > "$TMP/sd8/full/42_bundle-prs.txt"
119
151
  printf '42; rm -rf /\n' > "$TMP/sd8/bad/staging_pr_number"
120
152
  boot() { # scratch-dir -> prints "PR_NUMBER|ALL_PR_NUMBERS(joined)|GH_REPO" then any warning
121
153
  ( unset PR_NUMBER ALL_PR_NUMBERS GH_REPO DEFAULT_BRANCH STAGING_BRANCH; export PATH="$TMP/bin:$PATH" FORGE_SCRATCHPAD="$1"
122
- . "$TMP/boot.sh" 2>&1; echo "PR=${PR_NUMBER:-}|ALL=$(echo ${ALL_PR_NUMBERS:-})|REPO=${GH_REPO:-}|BR=${STAGING_BRANCH:-}" ) 2>&1; }
154
+ export FORGEDOCK_HOME="$ROOT"; . "$TMP/boot.sh" 2>&1; echo "PR=${PR_NUMBER:-}|ALL=$(echo ${ALL_PR_NUMBERS:-})|REPO=${GH_REPO:-}|BR=${STAGING_BRANCH:-}" ) 2>&1; }
123
155
  OUT8=$(boot "$TMP/sd8/full")
124
156
  [ "$OUT8" = "PR=42|ALL=7 8|REPO=stub-value|BR=stub-value" ] && ok || bad "fresh shell must reload staging_pr_number and bundle-prs from the scratchpad (got '$OUT8')"
125
157
  OUT8=$(boot "$TMP/sd8/empty")
@@ -127,7 +159,7 @@ case "$OUT8" in *"WARNING: PR_NUMBER is empty"*"PR=|ALL=|"*) ok ;; *) bad "empty
127
159
  OUT8=$(boot "$TMP/sd8/bad")
128
160
  case "$OUT8" in *"PR=|"*) ok ;; *) bad "non-numeric staging_pr_number must be rejected (got '$OUT8')" ;; esac
129
161
  # an already-set PR_NUMBER wins over a stale scratch file
130
- OUT8=$( ( unset ALL_PR_NUMBERS; PR_NUMBER=99; export PATH="$TMP/bin:$PATH" FORGE_SCRATCHPAD="$TMP/sd8/full"; . "$TMP/boot.sh" >/dev/null 2>&1; echo "PR=$PR_NUMBER|ALL=${ALL_PR_NUMBERS:-}" ) )
162
+ OUT8=$( ( unset ALL_PR_NUMBERS; PR_NUMBER=99; export PATH="$TMP/bin:$PATH" FORGE_SCRATCHPAD="$TMP/sd8/full" FORGEDOCK_HOME="$ROOT"; . "$TMP/boot.sh" >/dev/null 2>&1; echo "PR=$PR_NUMBER|ALL=${ALL_PR_NUMBERS:-}" ) )
131
163
  [ "$OUT8" = "PR=99|ALL=" ] && ok || bad "in-shell PR_NUMBER must not be overridden by the scratch file (got '$OUT8')"
132
164
  # producers persist, and 0B.1 / 7B.5 no longer use the unsubstituted-template repo token or a bare unquoted PR number in gh pr comment
133
165
  grep -q 'staging_pr_number' "$SPEC" && grep -q '_bundle-prs.txt' "$SPEC" && ok || bad "Phase -1 / 0A must persist staging_pr_number and _bundle-prs.txt"
@@ -250,7 +282,10 @@ OUT9=$(credit9 "$H"); N9=$(printf '%s' "${OUT9#*|}" | wc -w)
250
282
  grep -q 'review-delta.sh' "$SPEC" && grep -q 'REVIEW-CARRIED' "$SPEC" && ok || bad "spec must call review-delta.sh and accept the REVIEW-CARRIED record"
251
283
  if grep -qE 'merge-base --is-ancestor.*REVIEWED_SHA_STALE|diff_shape\(\)' "$SPEC"; then bad "spec must not carry a second copy of the resolver logic"; else ok; fi
252
284
  grep -qF 'printf '"'"'%s\n'"'"' "$_FILES" | sort -u | sed "s|^|$pr |" >> "$_PF"' "$SPEC" && grep -qF 'git diff-tree --no-commit-id --name-only -r --cc "$c"' "$SPEC" && ok || bad "CROSS_PR_FILES accumulation and --cc merge scoping must stay intact"
253
- [ "$(grep -c '# FENCE_BOOTSTRAP' "$SPEC" | head -1)" -ge 8 ] && ok || bad "FENCE_BOOTSTRAP lines must remain"
285
+ [ "$(grep -c '# FENCE_BOOTSTRAP$' "$SPEC" | head -1)" -ge 3 ] && ok || bad "FENCE_BOOTSTRAP stubs must remain"
286
+ # an unresolvable helper fails the fence closed (exit 1), never an unsourced bootstrap
287
+ OUT8=$( ( unset FORGEDOCK_HOME; export HOME="$TMP/nohome"; cd "$TMP" && bash -c "$(cat "$TMP/boot.sh"); echo reached" ) 2>&1 )
288
+ case "$OUT8" in *BLOCKED*) case "$OUT8" in *reached*) bad "unresolved bootstrap helper must stop the fence" ;; *) ok ;; esac ;; *) bad "unresolved bootstrap helper must print BLOCKED (got '$OUT8')" ;; esac
254
289
  # a stale-head PR must not credit its own merge commit (it contains the post-review commits): the DELTA branch only appends DELTA_COMMITS
255
290
  if awk '/^bundle_delta_credit\(\)/,/^\}/' "$SPEC" | grep -q 'mergeCommit'; then bad "the DELTA path must not credit the PR merge commit"; else ok; fi
256
291
  else echo "review-pr-staging-scope.test.sh: git missing, delta section skipped"; fi
@@ -32,7 +32,7 @@ chk commands/quality-gate.md 'VALIDATOR="${FORGE_ROOT:+$FORGE_ROOT/scripts/valid
32
32
  chk commands/quality-gate.md 'CONFLICT_CHECKER="${FORGE_ROOT:+$FORGE_ROOT/scripts/check-native-conflicts.sh}"'
33
33
  chk commands/quality-gate.md 'SPEC_BASH_CHECKER="${FORGE_ROOT:+$FORGE_ROOT/scripts/check-spec-bash.sh}"'
34
34
  chk commands/quality-gate.md 'CLASSIFIER="${FORGE_ROOT:+$FORGE_ROOT/scripts/flaky-quarantine.sh}"'
35
- chk commands/review-pr.md 'CLASSIFIER="${FORGE_ROOT:+$FORGE_ROOT/scripts/flaky-quarantine.sh}"'
35
+ chk commands/review-pr.md 'CLASSIFIER=$(forge_resolve flaky-quarantine.sh)'
36
36
  # validate.md must not name the worktree scripts dir at all (ac-1)
37
37
  grep -qF '{WORKTREE_PATH}/scripts' "$ROOT/commands/work-on/build/validate.md" && bad "validate.md references {WORKTREE_PATH}/scripts" || ok
38
38