issueflow-reconcile — the offsite stale-flag nudge, from cross-referenced timeline events
#69
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#69
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #56. Blocked by #68 (this verifies the flag #68 introduces).
Accepted from discussion #67, open question 3 — "should the sweep verify rather than trust?" — answered by @danmt in the thread: "we can verify, but only if we already trust so we dont have to verify everything." #68 builds the trust half. This is the verify half, and it is deliberately the smaller, later, quieter one.
All line references pinned at
cf69d8c.Context
#68 makes
offsitestop the claim-reclaim clock on the label alone — no proof, no resolution, nothing that can fail closed. That is the right first cut and it has one failure mode, named in the discussion that proposed it: the flag can go stale. The cross-repo PR merges, nobody clears the label, and the issue is exempt from reclamation forever. A permanent exemption is a worse board lie than the bug #68 fixes, because it is silent.The signal to catch it is already being fetched.
last_issue_activityreads the issue timeline on every sweep of everyclaimedissue (L197-L209) to pick upassignedevents. That same timeline carriescross-referencedevents: when a PR in another repo names this issue, GitHub records it, withsource.issue.pull_requestand the referencing repository. Nothing new is asked of the builder, no new body syntax, no second parser — the verification rides a call the sweep already makes.Spec
offsite, never reclaims, never unassigns, never touches a label. That is the literal content of the ruling: trust is the mechanism, verification is a nudge on top of it.dan-claude-bot/incubatoris one — GitHub hides cross-references the viewer cannot see, so ceremony's token will observe zero events for #16), a deleted repo, a permissions error: none of them nudge. This is the reconciler's standing rule — an unreadable fact must never invent a verdict — and #16 is the live case that will exercise the silent path on day one. A test pins it.<!-- issueflow:offsite-resolved -->via the existingensure_comment), so it is said once per issue, not once per sweep tick. Unlike #52's 7-day ruling nudge, there is no repeat: the fact being reported does not decay, and the owner is a named builder rather than a room.offsite_resolved_decision()— cross-referenced PR states on stdin →NUDGE|QUIET— sits above the API divider beside the other pure decisions; the timeline read sits below it. Every branch is fixture-driven with no network, as every decision in this file already is.heavy-duty/rig#112is merged; this issue'soffsiteflag is still up. Clear it and close the issue, or say what is still outstanding." Addressed to the assignee. It reports a fact and asks for a human-or-builder act — it does not perform one.Tasks
actions/issueflow-reconcile/issueflow-reconcile.sh—offsite_cross_referenced_prs()(timeline →owner/repo#Nforcross-referencedevents whose source is a PR),offsite_pr_states()(→OPEN/CLOSED/UNKNOWN, mirroring the existingreference_states), and the pureoffsite_resolved_decision().claimedbranch, after the exemption gate, guarded byhas_issue_label offsite— one extra timeline read only for issues that carry the flag.test/issueflow-reconcile.test.sh— the rows below, plus a fixture timeline JSON exercising the parser.LABELS.md— one sentence inoffsite's paragraph: the sweep will tell you when your flag has outlived its PR, and that it only ever tells you.CHANGELOG.md— one line under## Unreleased, inserted above the heading below it.Acceptance criteria
offsiteissue whose only cross-referenced PR is merged gets exactly one comment, naming that PR — and gets no second comment on the next sweep.offsiteissue with one merged and one open cross-referenced PR gets no comment.offsiteissue with no visible cross-referenced PRs gets no comment and logs nothing alarming (the #16 case).offsite, and none reclaims anoffsiteissue — #68's criterion, re-asserted here because this issue is the one that could break it.offsiteclaimedissue triggers no extra timeline read (assert on the fetch being guarded, not just on the outcome).test/run.shgreen; shellcheck- and actionlint-clean.Test plan
offsite_resolved_decisionagainst fixture state lists:CLOSEDNUDGECLOSED CLOSEDNUDGECLOSED OPENQUIETOPENQUIETQUIETCLOSED UNKNOWNQUIETParser rows against a fixture timeline: a
cross-referencedevent whose source is a PR in another repo is extracted with its qualified reference; one whose source is an issue is ignored; amentioned/assignedevent is ignored; an empty timeline yields nothing.The cases that must fail: (a) flip row 3 to
NUDGEand the suite goes red — "all closed" must not degrade to "any closed"; (b) flip row 6 toNUDGEand it goes red —UNKNOWNmust never be read as resolved.Dependencies
Blocked by #68.Part of #56.Constraint
LABELS.mdis vendored doctrine (the.ceremony/set); this repo is the source, so no re-sync happens here.Every issue named by
Blocked byis closed. The sweep is moving this issue toready.Starting this build now. I will implement the stale
offsitenudge exactly as specified, with fixture-driven parser/decision coverage and guarded failure behavior.