test: cover post-merge queue boundaries

This commit is contained in:
codex-bot-andresmgsl 2026-07-25 00:14:23 +00:00
parent bb7dd51ba7
commit 24dd818b35
4 changed files with 65 additions and 7 deletions

View file

@ -174,7 +174,11 @@ take. It is hand-set doctrine only: nothing in `actions/` sets, clears,
reads, or validates it, and no reconciler enforces the assignee requirement. reads, or validates it, and no reconciler enforces the assignee requirement.
An `attention` issue without an assignee is therefore a board bug, not a An `attention` issue without an assignee is therefore a board bug, not a
demand; anyone may assign it or remove the flag. It never composes with demand; anyone may assign it or remove the flag. It never composes with
`post-merge`, whose released claim has no assignee to answer the demand. `post-merge`, whose released claim has no assignee to answer the demand. The
one machine-clear exception is the derived `claimed``post-merge`
transition: releasing the assignee clears a carried `attention` in the same
edit. A hand-created `post-merge` + `attention` composition is flagged, not
rewritten.
The three signals are mutually distinct: `attention` means an assignee owes The three signals are mutually distinct: `attention` means an assignee owes
a move; `needs-ruling` means a human owes a decision under a move; `needs-ruling` means a human owes a decision under

View file

@ -281,7 +281,7 @@ last_issue_activity() {
reconcile_issue() { reconcile_issue() {
local n="$1" decision refs cross_refs states age assignees open_pr=false label owners local n="$1" decision refs cross_refs states age assignees open_pr=false label owners
local merged_ref=false unchecked="" local merged_ref=false unchecked="" remove_claimed=claimed
decision="$(queue_decision <<<"$ISSUE_LABELS")" decision="$(queue_decision <<<"$ISSUE_LABELS")"
case "$decision" in case "$decision" in
ADD_NEEDS_TRIAGE) ADD_NEEDS_TRIAGE)
@ -307,12 +307,16 @@ $unchecked
The merge releases the claim; no builder owes a draft. Triage owes completion in a follow-up comment that names the owner and wake condition." The merge releases the claim; no builder owes a draft. Triage owes completion in a follow-up comment that names the owner and wake condition."
owners="$(jq -r '[.assignees[].login] | join(",")' <<<"$ISSUE_JSON")" owners="$(jq -r '[.assignees[].login] | join(",")' <<<"$ISSUE_JSON")"
# `attention` is a demand for the assigned builder. The derived
# transition releases that builder, so carrying the demand forward
# would create an impossible parked-for state (#175 D4).
has_issue_label attention && remove_claimed=claimed,attention
if [ -n "$owners" ]; then if [ -n "$owners" ]; then
run gh issue edit "$n" -R "$REPO" --remove-assignee "$owners" \ run gh issue edit "$n" -R "$REPO" --remove-assignee "$owners" \
--remove-label claimed --add-label post-merge >/dev/null --remove-label "$remove_claimed" --add-label post-merge >/dev/null
else else
run gh issue edit "$n" -R "$REPO" \ run gh issue edit "$n" -R "$REPO" \
--remove-label claimed --add-label post-merge >/dev/null --remove-label "$remove_claimed" --add-label post-merge >/dev/null
fi fi
log "#$n: merged Refs PR -> post-merge; claim released" log "#$n: merged Refs PR -> post-merge; claim released"
else else
@ -359,10 +363,10 @@ The merge releases the claim; no builder owes a draft. Triage owes completion in
fi fi
elif has_issue_label post-merge; then elif has_issue_label post-merge; then
assignees="$(jq '.assignees | length' <<<"$ISSUE_JSON")" assignees="$(jq '.assignees | length' <<<"$ISSUE_JSON")"
if [ "$assignees" -gt 0 ]; then if [ "$assignees" -gt 0 ] || has_issue_label attention; then
ensure_comment "$n" post-merge-assigned \ ensure_comment "$n" post-merge-assigned \
'This `post-merge` issue has an assignee. The sweep will not undo a hand-assignment; triage must either clear it or move the issue back into buildable queue state.' 'This `post-merge` issue has an assignee or `attention`. The sweep will not undo hand-set intent; triage must clear the invalid composition or move the issue back into buildable queue state.'
log "#$n: assigned post-merge issue flagged" log "#$n: assigned or attention-bearing post-merge issue flagged"
fi fi
elif has_issue_label blocked; then elif has_issue_label blocked; then
refs="$(blocked_references <<<"$(jq -r '.body // ""' <<<"$ISSUE_JSON")")" refs="$(blocked_references <<<"$(jq -r '.body // ""' <<<"$ISSUE_JSON")")"

View file

@ -314,6 +314,7 @@ printf '[]\n' >"$(cfix 35)"
transition="$(issue_probe 35 claimed 1 false true $'- [x] built\n- [ ] verify dispatch\n * [ ] confirm warning clears')" transition="$(issue_probe 35 claimed 1 false true $'- [x] built\n- [ ] verify dispatch\n * [ ] confirm warning clears')"
check "merged Refs + unchecked criteria transitions in the sweep body" 0 "" \ check "merged Refs + unchecked criteria transitions in the sweep body" 0 "" \
grep -q 'merged Refs PR -> post-merge; claim released' <<<"$transition" grep -q 'merged Refs PR -> post-merge; claim released' <<<"$transition"
# shellcheck disable=SC2016 # positional parameters belong to bash -c
check "...names every remaining criterion verbatim in the comment" 0 "" \ check "...names every remaining criterion verbatim in the comment" 0 "" \
bash -c 'grep -qF -- "- [ ] verify dispatch" "$1" && bash -c 'grep -qF -- "- [ ] verify dispatch" "$1" &&
grep -qF -- " * [ ] confirm warning clears" "$1"' _ "$TMP/posted-35" grep -qF -- " * [ ] confirm warning clears" "$1"' _ "$TMP/posted-35"
@ -337,6 +338,52 @@ check "assigned post-merge is flagged" 0 "" \
check "...and the hand-assignment is not repaired" 1 "" \ check "...and the hand-assignment is not repaired" 1 "" \
grep -qF -- 'issue edit 37' "$TMP/issue-edits" grep -qF -- 'issue edit 37' "$TMP/issue-edits"
# -- non-triggers stay byte-for-byte outside the transition ------------------
recent_timeline() {
jq -n --arg at "$(iso_at $((INOW - 60)))" \
'[{"event":"assigned","created_at":$at}]' >"$(tfix "$1")"
printf '[]\n' >"$(cfix "$1")"
}
edit_count_before="$(wc -l <"$TMP/issue-edits")"
recent_timeline 38
open_refs="$(issue_probe 38 claimed 1 true false '- [ ] verify after merge')"
check "open Refs PR leaves the issue exactly as found" 0 "" \
test -z "$open_refs"
# shellcheck disable=SC2016 # positional parameters belong to bash -c
check "...with no edit or comment" 0 "" \
bash -c 'test "$1" -eq "$(wc -l <"$2")" && test ! -f "$3"' _ \
"$edit_count_before" "$TMP/issue-edits" "$TMP/posted-38"
recent_timeline 39
merged_closes="$(issue_probe 39 claimed 1 false false '- [ ] verify after merge')"
check "merged Closes PR leaves a recent claim exactly as found" 0 "" \
test -z "$merged_closes"
# shellcheck disable=SC2016 # positional parameters belong to bash -c
check "...with no edit or comment" 0 "" \
bash -c 'test "$1" -eq "$(wc -l <"$2")" && test ! -f "$3"' _ \
"$edit_count_before" "$TMP/issue-edits" "$TMP/posted-39"
recent_timeline 40
all_checked="$(issue_probe 40 claimed 1 false true '- [x] verified after merge')"
check "merged Refs with zero unchecked boxes leaves the issue exactly as found" 0 "" \
test -z "$all_checked"
# shellcheck disable=SC2016 # positional parameters belong to bash -c
check "...with no edit or comment" 0 "" \
bash -c 'test "$1" -eq "$(wc -l <"$2")" && test ! -f "$3"' _ \
"$edit_count_before" "$TMP/issue-edits" "$TMP/posted-40"
printf '[]\n' >"$(cfix 41)"
attention_transition="$(issue_probe 41 $'claimed\nattention' 1 false true '- [ ] verify')"
check "derived post-merge transition clears attention with the released claim" 0 "" \
grep -qF -- '--remove-label claimed,attention --add-label post-merge' "$TMP/issue-edits"
check "...still completes the transition" 0 "" \
grep -qF 'merged Refs PR -> post-merge; claim released' <<<"$attention_transition"
printf '[]\n' >"$(cfix 42)"
issue_probe 42 $'post-merge\nattention' 0 >/dev/null
check "hand-created post-merge plus attention is flagged, not rewritten" 0 "" \
grep -qF '<!-- issueflow:post-merge-assigned -->' "$TMP/posted-42"
# -- offsite stops only the reclaim clock ------------------------------------ # -- offsite stops only the reclaim clock ------------------------------------
offsite="$(issue_probe 25 $'claimed\noffsite')" offsite="$(issue_probe 25 $'claimed\noffsite')"
check "a 10-day-quiet offsite claim is not reclaimed" 1 "" \ check "a 10-day-quiet offsite claim is not reclaimed" 1 "" \

View file

@ -77,6 +77,9 @@ expect "a 300-char reason passes through whole" 300 "${#exact_reason}"
# -- a missing core taxonomy row is visible without mutating labels ---------- # -- a missing core taxonomy row is visible without mutating labels ----------
core_rows="$(core_label_rows)" core_rows="$(core_label_rows)"
core_names="$(cut -d'|' -f1 <<<"$core_rows")" core_names="$(cut -d'|' -f1 <<<"$core_rows")"
expect "post-merge core row is byte-exact" \
"post-merge|006B75|Refs-linked PR merged; post-merge criteria remain and triage owns completion" \
"$(grep '^post-merge|' <<<"$core_rows")"
expect "a complete core taxonomy does not warn" "" \ expect "a complete core taxonomy does not warn" "" \
"$(missing_core_labels_warning "$core_rows" "$core_names")" "$(missing_core_labels_warning "$core_rows" "$core_names")"
expect "one missing core label is named exactly" \ expect "one missing core label is named exactly" \