From b3fd26b21b4093187e8b0362d4ebbca1caf0b4fd Mon Sep 17 00:00:00 2001 From: cndgrr <59120057+cndgrr@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:06:47 +0000 Subject: [PATCH] =?UTF-8?q?test(issueflow):=20the=20evidence=20nudge's=20f?= =?UTF-8?q?ixtures=20=E2=80=94=20window,=20addressee,=20no=20marker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers the must-nudge pair (8 quiet days; post-merge + needs-ruling both speak), the must-not set (6 days, fresh comment, every other queue state), self-rate-limiting proven by sweeping again a day later rather than by asserting a marker's absence, and zero writes across every probe. Two existing probes move: #36's 'no comment' assertion described the starvation this issue ends, and #67 gets recent activity so its precedence count stays the assertion doing the work. Refs #254 --- test/issueflow-reconcile.test.sh | 132 ++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/test/issueflow-reconcile.test.sh b/test/issueflow-reconcile.test.sh index ec9e83b..3ea95c7 100644 --- a/test/issueflow-reconcile.test.sh +++ b/test/issueflow-reconcile.test.sh @@ -431,7 +431,11 @@ issue_probe() { # $1 issue, $2 labels, $3 assignees, $4 false|closing|refs, $5 m local assignees="${3:-1}" open_pr="${4:-false}" merged_ref_prs="${5:-}" local body="${6:-}" assignee_json='[]' open_pr_records="" spec pr merged_at [ "$assignees" -eq 0 ] || assignee_json='[{"login":"owner-bot"}]' - REPO=owner/repo NOW="$INOW" + # `PROBE_NOW` moves the sweep's clock without moving the fixtures — the + # only way to prove a rule that self-rate-limits on its own comment's + # timestamp (#254): sweep, then sweep again a day later and watch the + # nudge stay silent because the comment it posted is now the activity. + REPO=owner/repo NOW="${PROBE_NOW:-$INOW}" ISSUE_LABELS="$2" ISSUE_JSON="$(jq -n --arg at "$(iso_at $((INOW - 10 * 86400)))" \ --argjson assignees "$assignee_json" --arg body "$body" \ @@ -517,6 +521,13 @@ check "...drawing the #252 parse echo and nothing else" 0 "1" \ grep -c -- '^----$' "$TMP/posted-66" attention_episode 67 "$(iso_at $((INOW - 60)))" +# Recent activity keeps the evidence nudge (#254) off this probe: it is a +# precedence case, and "exactly one comment" is the assertion doing the work. +# The nudge's own coexistence with the post-merge diagnostic is pinned in its +# section below, on a probe that is quiet on purpose. +jq -n --arg at "$(iso_at $((INOW - 60)))" \ + '[{"user":{"login":"triage-one"},"created_at":$at,"html_url":"https://x/c67","body":"still waiting on the tag"}]' \ + >"$(cfix 67)" post_merge_attention="$(issue_probe 67 $'post-merge\nattention' 0)" check "post-merge precedence leaves exactly its existing comment" 0 "1" \ grep -c -- '^----$' "$TMP/posted-67" @@ -617,7 +628,13 @@ printf '[]\n' >"$(cfix 36)" post_merge_quiet="$(issue_probe 36 post-merge 0)" check "quiet unassigned post-merge work is not reclaimed" 1 "" \ grep -q 'reclaimed' <<<"$post_merge_quiet" -check "...and causes no comment or edit" 1 "" test -f "$TMP/posted-36" +# The quiet itself is now visible (#254) — this probe is 10 days old with no +# activity, so it draws the evidence nudge and nothing else. It used to +# assert no comment at all; that assertion described the starvation this +# issue exists to end, and the edit half of it is what still matters. +check "...and causes no edit" 1 "" grep -qF -- 'issue edit 36' "$TMP/issue-edits" +check "...only the evidence nudge speaks" 0 "1" \ + grep -c -- '^----$' "$TMP/posted-36" printf '[]\n' >"$(cfix 37)" issue_probe 37 post-merge 1 >/dev/null @@ -625,6 +642,117 @@ check "assigned post-merge is flagged" 0 "" \ grep -qF '' "$TMP/posted-37" check "...and the hand-assignment is not repaired" 1 "" \ grep -qF -- 'issue edit 37' "$TMP/issue-edits" +# The flag and the nudge answer different questions — a board bug and a +# starved wake condition — so neither suppresses the other (#254). +check "...and the evidence nudge rides beside it, neither suppressed" 0 "2" \ + grep -c -- '^----$' "$TMP/posted-37" + +# -- the post-merge evidence nudge (#254), the ruling nudge's twin ---------- +# The ruling nudge solved "a wait goes quiet and nobody is told" for +# `needs-ruling`; `post-merge` had no equivalent, and crew#181's real-host +# criterion starved four times across two releases for want of one. Same +# 7-day constant (`ruling_nudge_decision`, reused not mirrored), same +# deliberate absence of an idempotency marker, and — unlike the ruling +# nudge — addressed to the triage actor, because `post-merge` is triage's +# completion queue and the operator owes nothing here (#254 D1). +nudge_edits_before="$(wc -l <"$TMP/issue-edits")" + +quiet_comment() { # $1 issue, $2 seconds of quiet — one ordinary comment, then silence + jq -n --arg at "$(iso_at $((INOW - $2)))" \ + '[{"user":{"login":"triage-one"},"created_at":$at,"html_url":"https://x/c","body":"evidence pending"}]' \ + >"$(cfix "$1")" + printf '[]\n' >"$(tfix "$1")" +} + +quiet_comment 80 $((8 * 86400)) +nudged="$(issue_probe 80 post-merge 0)" +check "8 quiet days on a post-merge item draws the evidence nudge" 0 "" \ + grep -q 'post-merge evidence nudge' <<<"$nudged" +# shellcheck disable=SC2016 # expansions belong to the isolated bash -c process +check "...addressed to the triage actor, never the human reviewer" 0 "" \ + bash -c 'grep -qF "@triage-one" "$1" && ! grep -qF "@danmt" "$1"' _ "$TMP/posted-80" +check "...with the issue link as the payload" 0 "" \ + grep -qF 'https://github.com/owner/repo/issues/80' "$TMP/posted-80" +check "...carrying the do-not-add-a-marker warning in the comment" 0 "" \ + grep -qF 'Do not add a marker.' "$TMP/posted-80" +# Asserted directly, not merely omitted: a marker would turn "once per 7 +# quiet days" into "once per issue, forever" — the exact "fix" lib/ruling.sh's +# header records as the thing that breaks this rule. +check "...and no idempotency marker on the path" 1 "" \ + grep -qF '\nrung"}, + {"user":{"login":"sweep-bot"},"created_at":$r24,"html_url":"https://x/r24","body":"\nrung"}]' \ + >"$(cfix 84)" +both="$(issue_probe 84 $'post-merge\nneeds-ruling' 0)" +check "a quiet post-merge item under a pending ruling nudges both waits" 0 "" \ + grep -q 'post-merge evidence nudge' <<<"$both" +check "...and the ruling nudge is not suppressed by it" 0 "" \ + grep -q 'ruling nudge' <<<"$both" +# shellcheck disable=SC2016 # expansions belong to the isolated bash -c process +check "...each addressing its own party" 0 "" \ + bash -c 'grep -qF "@triage-one" "$1" && grep -qF "@danmt" "$1"' _ "$TMP/posted-84" + +# Every other queue state: the nudge is `post-merge`'s alone. Each is equally +# quiet, and `claimed` carries an open PR so its own reclaim clock — the one +# other 10-day rule on this path — stays out of the way. +non_post_merge=(85:ready:0:false 86:claimed:1:true 87:blocked:0:false 88:epic:0:false 89:needs-triage:0:false) +for spec in "${non_post_merge[@]}"; do + IFS=: read -r n state probe_assignees probe_pr <<<"$spec" + printf '[]\n' >"$(cfix "$n")" + printf '[]\n' >"$(tfix "$n")" + check "a 10-day-quiet $state issue draws no evidence nudge" 1 "" \ + grep -q 'post-merge evidence nudge' \ + <<<"$(issue_probe "$n" "$state" "$probe_assignees" "$probe_pr")" +done + +# `post-merge` is the one queue state whose whole meaning is that the machine +# owes nothing (LABELS.md: the sweep never reclaims it). This issue makes the +# quiet visible; it must never make it actionable. +# shellcheck disable=SC2016 # positional parameter belongs to the isolated shell +check "the evidence-nudge probes perform no issue edits" 0 "$nudge_edits_before" \ + bash -c 'wc -l <"$1"' _ "$TMP/issue-edits" # -- non-triggers stay byte-for-byte outside the transition ------------------ recent_timeline() {