Commit graph

23 commits

Author SHA1 Message Date
cndgrr
374005ef77 feat(issueflow): echo the parsed blocker set when it changes
The clause parse is exact and unforgiving, and its output was invisible:
every incident in this class was found by a human running the parser by
hand, hours or days late. The sweep now states what it read — one marker
comment per distinct parsed set, comment-only, no label writes.

Refs #252
2026-08-03 19:24:59 +00:00
cndgrr
6217798e14 fix(issueflow): a per-issue pass commits its whole effect, or none of it
The per-read guards closed the reported class — a failed read never reaches
a decision function — and left one layer standing. A pass could mutate and
only THEN reach a guarded read, fail it, and report the issue as skipped:
`stale` removed, or `needs-triage` minted, under a log line saying the
sweep had touched nothing. That is the same false report #247 exists to
close, told from the other end, and the panel reproduced it on four
separate compositions.

Fixed as the ordering invariant rather than per site. Inside
reconcile_issue_pass's subshell, run() and log() stage their effects, and
commit_staged_effects replays them in order once the pass has completed.
skip_issue emits its own line directly and exits, so the buffer dies with
the subshell. A skip therefore implies zero `gh issue edit`, zero
`gh issue comment`, and no log line about a mutation that never landed —
for compositions nobody has written yet, because reconcile_issue has no way
to mutate directly. Reads stay where they are: they may happen anywhere,
since nothing lands until the end.

Stated per site it would hold until the next composition. Two consequences
worth naming: reconcile_ruling is covered without touching lib/ruling.sh,
because it posts through the sourcing script's run()/log() — the PR surface
keeps its own and is unaffected; and a genuine crash mid-pass now also
lands nothing, where before it left the earlier mutations applied. D4's
handler string, D6's tail and D7's exit 0 are all unchanged, and the
healthy path is byte-identical: every staged write commits under the same
`>/dev/null` its call site already applied.

Refs #247
2026-08-03 18:55:52 +00:00
cndgrr
13e8f54d60 fix(issueflow): a failed read never reaches a decision function
`gh api` prints a 5xx response body to stdout AND exits non-zero, and
GitHub's 5xx body is a JSON object. Inside the per-issue subshell that
payload passed `has("pull_request") | not`, emptied `.labels[]`, and
`queue_decision` — correct on the input it was handed — wrote
`needs-triage` onto a healthy epic. The run then logged `reconciled.`
and exited 0 (crew#329, #247).

errexit could not have caught it: a command whose status is tested by
`||` runs with errexit suppressed, and the suppression extends through
the whole subshell body, so the `|| log` handler is what disables the
errexit that would have aborted at the failed read. Removing the handler
revives errexit and loses #91's resilience, and an inline `set -e` does
not re-arm it. Explicit per-read checks are the mechanism.

Every read inside that subshell is now checked — the issue read on its
status AND on its payload shape (an HTTP 200 whose body is `null` exits
0 and empties the label set just the same), both reads in
`last_issue_activity`, and the comments read in
`issue_comment_has_marker`. On failure the issue is left exactly as it
is, the reason rides its own `#$n:` line, and the subshell exits with a
distinguished status the sweep counts, so a deliberate skip is not
reported as a crash and a genuine crash is still named byte-identically.

`read_failure_reason` moves to lib/read.sh beside a new `guarded_read`,
sourced by both reconcilers: labels-reconcile's copy was the only one,
and the issue surface needs the identical rule.

Refs #247
2026-08-03 18:01:58 +00:00
Andriujose
e133924887 fix: preserve claims linked by open Refs PRs 2026-08-03 17:07:40 +00:00
cndgrr
9c690f02b7 test(issueflow): drive the merge-order selection, and the spent-marker shape end to end
issue_probe's merged-PR argument becomes a spec list — `PR` or `PR@<iso>`
— so a probe can state merge order; the bare form keeps every existing call
site literal.

The direct-drive cases cover crew#176's shape (the lower number merged
later), agreeing orders, interleaved issues, the mergedAt tie broken by
highest PR number under both input orders, and the empty answer. The
end-to-end probe is crew#321's: a marker already standing for the
later-merged, lower-numbered PR must suppress the transition, which
selecting by number could never do.

Two static pins keep the request count honest — the sweep issues exactly two
GraphQL queries, with mergedAt selected on the merged-PR node it already
fetched.

Refs #242
2026-08-03 16:27:43 +00:00
cndgrr
f4afaa1346 fix(issueflow): the deliverable PR is the last merged, not the highest numbered
post_merge_pr_for_issue answered "which merged Refs PR is this issue's
deliverable?" with sort -n | tail -n1. Merge order is not number order:
crew#176's two Refs PRs merged #184 at 19:05:16Z and #182 at 19:05:18Z.

MERGED_REF_PR_RECORDS gains mergedAt as a third column — a field on the
merged-PR node set already fetched, so no additional GraphQL request — and
the selection sorts on it, breaking ties by highest PR number so the answer
never depends on input order.

Refs #242
2026-08-03 16:23:15 +00:00
claude-bot-andresmgsl
0eea112d50 fix: blocked_reference_records unions every Blocked by clause
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 <noreply@anthropic.com>
2026-07-25 13:58:39 +00:00
codex-bot-andresmgsl
5a3d72f09c fix: make post-merge transitions episode-aware 2026-07-25 04:29:37 +00:00
codex-bot-andresmgsl
24dd818b35 test: cover post-merge queue boundaries 2026-07-25 00:14:23 +00:00
codex-bot-andresmgsl
bb7dd51ba7 feat: transition merged refs work to post-merge 2026-07-25 00:11:42 +00:00
claude-bot-andresmgsl
c39b78959d fix: stand down with exit 0 on non-mint issue arrivals
reconcile_opened_issue's two early exits were bare returns, which carry
the failed guard's status into the executed script's set -e — every
triage-authored mint killed the labels run before one issue was
reconciled (#91, 4/4 observed). The stand-downs now say return 0; a
genuine failure on the arrival path still aborts loudly.

The suite sources the script and takes the set -u-only branch, so it
was blind to this by construction. The new arrival section executes the
script as a subprocess behind a fixture-serving gh stub (the house
pattern from test/release-chain.test.sh) and covers all three arrival
outcomes plus the preserved loud-failure path; it fails against
bb37c15 with the production signature — exit 1, empty output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 20:16:20 +00:00
codex-bot-andresmgsl
bc3c1bd5cf feat: nudge resolved offsite claims 2026-07-23 13:17:39 +00:00
codex-bot-andresmgsl
6a9b501e05 feat: exempt offsite claims from reclaim clock 2026-07-23 12:48:04 +00:00
claude-bot-andresmgsl
a40e42544e feat(labels): wire the ruling pass into both reconcilers + lib test suite
Issue side: the claim-reclaim clock stops under a pending ruling (the
decision still sees an unassigned claim), an already-applied stale heals
off, and reconcile_ruling runs for any flagged issue on any queue state.
PR side: reconcile_ruling rides the (#51) stale section's real-activity
computation. test/ruling.test.sh pins the window boundaries, newest-event
anchoring, per-event marker scoping, the markerless nudge reset, the
unreadable-timeline rule, and that no scenario writes a label.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 12:25:05 +00:00
codex-bot-andresmgsl
bc099eb4e2 fix: guard cross-repo issue references 2026-07-23 11:38:14 +00:00
codex-bot-andresmgsl
43092576ef fix: harden issueflow reconciliation edges 2026-07-23 10:49:36 +00:00
codex-bot-andresmgsl
d0f1a43064 test: pin injected staleness boundary 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
1030634b09 test: inject issue-flow staleness clock 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
1532f22eb7 fix: parse live issue dependency shapes 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
a811da8b4f fix: enforce triage author only on issue arrival 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
cbb0fb5eee test: cover stale unassigned claims 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
561b7a99ec fix: read linked issues through GraphQL 2026-07-23 10:31:15 +00:00
codex-bot-andresmgsl
8174080c9d feat: reconcile the issue work queue 2026-07-23 10:31:15 +00:00