From 0eea112d50ab61fd1e33ca3207b88c61f2d13b4a Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Sat, 25 Jul 2026 13:58:39 +0000 Subject: [PATCH] fix: blocked_reference_records unions every Blocked by clause MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding to the first marker occurrence dropped every later sentence of a repeated declaration and let earlier prose hijack the parse — the false ready promotion on rig#154. Each occurrence now contributes its own clause, terminated at its own first ./; (unterminated -> end of input), and the union feeds the unchanged classification and decision table. Closes #184 Co-Authored-By: Claude Fable 5 --- .../issueflow-reconcile.sh | 44 ++++++++++++------- changelog.d/184.md | 6 +++ test/issueflow-reconcile.test.sh | 17 +++++++ 3 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 changelog.d/184.md diff --git a/actions/issueflow-reconcile/issueflow-reconcile.sh b/actions/issueflow-reconcile/issueflow-reconcile.sh index c5ab519..e0b3174 100644 --- a/actions/issueflow-reconcile/issueflow-reconcile.sh +++ b/actions/issueflow-reconcile/issueflow-reconcile.sh @@ -177,27 +177,37 @@ issue_references() { # text on stdin -> LOCAL/CROSSreference } blocked_reference_records() { # body on stdin -> classified reference records - # Dependency declarations sometimes soft-wrap after a comma. Continue - # through the first sentence terminator; if prose omits one, conservatively - # retain later references so ambiguity can keep an issue blocked, never - # promote it prematurely. + # Every occurrence of the marker contributes a clause. Binding to the first + # occurrence alone dropped the later sentences of a repeated declaration + # ("Blocked by #152. Blocked by #153. Blocked by #148 — …") and let earlier + # prose that merely mentioned being blocked hijack the parse — the false + # `ready` promotion on rig#154 (#184). Each clause runs to its own first + # sentence terminator; declarations sometimes soft-wrap after a comma, so + # an open clause continues across lines, and if prose omits the terminator + # it retains to end of input. Unioning can over-retain — prose like "this + # was blocked by #9 before the split" now contributes #9 — and that is the + # correct direction of error: a stale `blocked` is a triage comment away, + # a false `ready` sends a builder into work that cannot merge (#184). awk ' + BEGIN { marker = "blocked by" } { line = $0 - lower = tolower(line) - if (!active) { - marker = "blocked by" - start = index(lower, marker) - if (!start) next - line = substr(line, start + length(marker)) - active = 1 + while (1) { + if (!active) { + start = index(tolower(line), marker) + if (!start) next + line = substr(line, start + length(marker)) + active = 1 + } + if (match(line, /[.;]/)) { + print substr(line, 1, RSTART - 1) + line = substr(line, RSTART + 1) + active = 0 + } else { + print line + next + } } - if (line ~ /[.;]/) { - sub(/[.;].*/, "", line) - print line - exit - } - print line } ' | issue_references } diff --git a/changelog.d/184.md b/changelog.d/184.md new file mode 100644 index 0000000..891f65a --- /dev/null +++ b/changelog.d/184.md @@ -0,0 +1,6 @@ +### Fixed + +- `blocked_reference_records` unions every `Blocked by` clause in the body + instead of binding to the first marker occurrence — a repeated declaration + no longer promotes on its first sentence alone, and earlier prose that + merely mentions being blocked no longer hijacks the parse (#184). diff --git a/test/issueflow-reconcile.test.sh b/test/issueflow-reconcile.test.sh index d1a8f15..a326da9 100644 --- a/test/issueflow-reconcile.test.sh +++ b/test/issueflow-reconcile.test.sh @@ -142,6 +142,23 @@ check "slash-adjacent local references survive" 0 $'14\n15' \ blocked_references <<<"Blocked by #14/#15." check "comma-adjacent local references survive" 0 $'11\n12' \ blocked_references <<<"Blocked by #11, #12." +# A repeated declaration contributes every sentence, not just the first — +# rig#154's body promoted on `#152` alone while #153 and #148 were open (#184). +body="Part of #151. Blocked by #152. Blocked by #153. Blocked by #148 — the registry PR merges under landed governance. Blocks #155." +check "repeated blocker sentences all contribute" 0 "" test \ + "$(blocked_references <<<"$body")" = $'148\n152\n153' +body=$'Note: restored because it is blocked by an operator act. See below.\nBlocked by #152, #153, #148.' +check "earlier blocked-by prose does not hijack the declaration" 0 "" test \ + "$(blocked_references <<<"$body")" = $'148\n152\n153' +body=$'This was blocked by #9 before the split.\nBlocked by #12.' +check "prose refs are retained beside the declaration, never substituted" 0 "" test \ + "$(blocked_references <<<"$body")" = $'9\n12' +repeated_refs="$(blocked_references <<<"Blocked by #152. Blocked by #153.")" +check "repeated declaration with one open blocker keeps issue blocked" 0 "KEEP" \ + blocked_decision "$repeated_refs" $'CLOSED\nOPEN' +check "cross-repo ref in a later clause still flags" 0 "FLAG_CROSS_REPO" \ + blocked_decision "12" "CLOSED" \ + "$(blocked_cross_references <<<"Blocked by #12. Blocked by rig#7.")" check "open blocker keeps issue blocked" 0 "KEEP" blocked_decision "$refs" $'CLOSED\nOPEN' check "all closed blockers release issue" 0 "READY" blocked_decision "$refs" $'CLOSED\nCLOSED' check "missing blocked declaration is flagged" 0 "FLAG_UNPARSEABLE" blocked_decision "" ""