forked from heavy-duty/ceremony
the two flags mean one thing by unblocked, and a key set is a set
B1: deliverable_keys answered a multiset, so a `+` title whose segments normalize to one key made collision_flags find the issue adjacent to itself and chain it to its own number — the comment asked an issue to declare `Blocked by` itself, and two such carriers corrupted the chain between them. The keys are deduped where the set property belongs. B2: window_in_scope excluded only blocked/epic/post-merge, admitting `needs-triage` and label-less issues, so the sweep could add `needs-triage` to an issue and then tell it about a mint-time membership call in the same pass. Both flags now call one unblocked_claimable predicate — #293 D2 corrected gives one gloss on `unblocked` and D3b says D3 uses it. The window log line says "unblocked", not "ready": D3b corrected exactly that wording, and the flag fires on `claimed` too.
This commit is contained in:
parent
5d13573c53
commit
919135db12
2 changed files with 48 additions and 16 deletions
|
|
@ -469,28 +469,56 @@ deliverable_keys() { # title on stdin -> its deliverable keys, one per line
|
|||
# segment: `TRIAGE.md + RELEASES.md` carries both keys.
|
||||
local segments=()
|
||||
IFS='+' read -r -a segments <<<"$prefix"
|
||||
for segment in "${segments[@]}"; do
|
||||
key="$(deliverable_key "$segment")"
|
||||
[ -z "$key" ] || printf '%s\n' "$key"
|
||||
done
|
||||
# An issue answers a SET of keys, never a multiset. Normalization is
|
||||
# many-to-one by design — `issueflow-reconcile.sh + issueflow-reconcile.test.sh`
|
||||
# is one deliverable spelled twice, which is exactly the `+` shape D2 wrote
|
||||
# the segment rule for — and a repeated key makes `collision_flags`' scan
|
||||
# find the issue adjacent to itself, chaining it to its own number: the
|
||||
# comment would ask #402 to declare `Blocked by #402`. It corrupts the chain
|
||||
# between two such issues too, since each contributes two rows to one key.
|
||||
# Deduping here rather than in the index keeps the set property with the
|
||||
# function whose contract it is.
|
||||
{ for segment in "${segments[@]}"; do
|
||||
key="$(deliverable_key "$segment")"
|
||||
[ -z "$key" ] || printf '%s\n' "$key"
|
||||
done
|
||||
} | awk '!seen[$0]++'
|
||||
}
|
||||
|
||||
collision_in_scope() { # $1 = comma-joined labels -> 0 in the collision set
|
||||
unblocked_claimable() { # $1 = comma-joined labels -> 0 when the issue is unblocked
|
||||
# THE one definition of `unblocked`, because #293 gives both flags one word
|
||||
# and one gloss on it: D2 as corrected reads "`unblocked` means open and not
|
||||
# `blocked` — carrying `ready` or `claimed`, with or without an open PR",
|
||||
# and D3b's first line says D3 uses D2's corrected `unblocked` and names the
|
||||
# domain as the claimable set. Two spellings of one spec word is how the
|
||||
# flags came to disagree about `needs-triage`, so there is one predicate and
|
||||
# both flags call it.
|
||||
#
|
||||
# `blocked` is out: a chained issue is the GOAL state of #288's rule, and
|
||||
# flagging it would report the fix as the defect. `epic` and `post-merge`
|
||||
# are out by #288 D6 — neither is picked by a builder — and they carry no
|
||||
# queue label to admit them here anyway.
|
||||
# flagging it would report the fix as the defect. Anything else without
|
||||
# `ready` or `claimed` is out because it is not claimable — `needs-triage`
|
||||
# and a label-less issue are not states a builder can pick up, and an
|
||||
# unlabeled one is getting `needs-triage` from this very pass. `epic` and
|
||||
# `post-merge` are out by #288 D6 and #292 D1 alike — neither is picked by a
|
||||
# builder — and they carry no queue label to admit them here anyway.
|
||||
case ",$1," in *,blocked,*) return 1 ;; esac
|
||||
case ",$1," in *,ready,*|*,claimed,*) return 0 ;; esac
|
||||
return 1
|
||||
}
|
||||
|
||||
collision_in_scope() { # $1 = comma-joined labels -> 0 in the collision set
|
||||
unblocked_claimable "$1"
|
||||
}
|
||||
|
||||
window_in_scope() { # $1 = comma-joined labels -> 0 subject to the window rule
|
||||
# `epic` and `post-merge` are outside the claimable set and exempt by name
|
||||
# (#292 D1); `blocked` is already placed behind something and is what the
|
||||
# non-member leg of the mint-time call writes.
|
||||
case ",$1," in *,blocked,*|*,epic,*|*,post-merge,*) return 1 ;; esac
|
||||
return 0
|
||||
# The same `unblocked`, not a second reading of it. Excluding only
|
||||
# `blocked`/`epic`/`post-merge` here admitted `needs-triage` and a
|
||||
# label-less issue, which left the sweep adding `needs-triage` to an
|
||||
# unlabeled issue and then, in the same pass, telling it about a membership
|
||||
# call made at mint time. Neither is claimable; #292's invariant is stated
|
||||
# over the claimable set (D3b), and its exemptions say why — `epic` and
|
||||
# `post-merge` are exempt *because neither is claimable*.
|
||||
unblocked_claimable "$1"
|
||||
}
|
||||
|
||||
collision_key_index() { # board records on stdin -> "key<TAB>number" in scope
|
||||
|
|
@ -760,7 +788,11 @@ same parse every \`blocked\` issue is gated on, echoed on that issue.
|
|||
|
||||
*Comment only: nothing on this path writes a label or changes a state. The
|
||||
marker carries the window itself, so an unchanged one never re-posts.*" >/dev/null
|
||||
log "#$n: window flag — a ready non-member under $state"
|
||||
# "unblocked", not "ready": the flag fires on `claimed` too, PR in
|
||||
# flight or not, which is the one wording #293 D3b went out of its way
|
||||
# to correct. The log line is read by a human deciding whether the
|
||||
# sweep understood the board, so it says what the predicate says.
|
||||
log "#$n: window flag — an unblocked non-member under $state"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2218,8 +2218,8 @@ check "the morning board draws exactly three collision flags" 0 "3" \
|
|||
flag_count collision "$morning_out"
|
||||
# D3's corpus: the six `ready` non-members that raced the emptying gate.
|
||||
for nonmember in 257 264 266 276 281 284; do
|
||||
check "#$nonmember is flagged as a ready non-member under #249" 0 \
|
||||
"issueflow: #$nonmember: window flag — a ready non-member under #249" \
|
||||
check "#$nonmember is flagged as an unblocked non-member under #249" 0 \
|
||||
"issueflow: #$nonmember: window flag — an unblocked non-member under #249" \
|
||||
printf '%s\n' "$morning_out"
|
||||
done
|
||||
check "the morning board draws exactly six window flags" 0 "6" \
|
||||
|
|
|
|||
Loading…
Reference in a new issue