issueflow-reconcile — cross-repo references must not be read as local issue numbers #61
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#61
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 #1. Found in triage hygiene against the live corpus, immediately after #18 shipped in #32 (
66f1c08) — the same class of bug as theBlocked byanchor found on #18, and found the same way: by running the shipped parsers over real bodies instead of fixtures.(Minted directly rather than via a discussion: a defect in shipped machinery with a live instance on the board, not a question — there is nothing to converge on.)
Context
Both reference parsers extract issue numbers with a bare
grep -Eo '#[0-9]+':blocked_referencesepic_referencesA cross-repo reference —
rig#112,heavy-duty/box#9,[rig#112](…)— therefore lands in the same bucket as a local one, and the number is then resolved against this repo:This family is cross-repo by construction — box, rig, cast, incubator — so sibling-repo references in dependency prose are the normal case, not an exotic one.
Live instance, epic #1. Its task list carries
PR [rig#112](https://github.com/heavy-duty/rig/pull/112) is approved…on the #13 row.epic_referencesreads a phantom local#112,reference_states404s it toUNKNOWN, andepic_decisiontreatsUNKNOWNas not-yet-complete. The house epic can never receive its completion nudge — permanently, and silently. This is exactly the failure #18's epic-parser acceptance row was written to prevent ("an open issue cited outside the task list silently suppresses a legitimate nudge"); scoping to the task list closed one route to it and left this one open.The unsafe direction is reachable too.
blocked_decisionpromotes when every parsed ref is closed. A body readingBlocked by rig#9parses to local#9, which is closed here — so the sweep flips a genuinely blocked issue toreadywhilerig#9is still open, and a builder picks work that cannot be done. Nothing on the board is in that state today; the two openblockedissues (#14, #15) both name local#13. The epic instance is live; this one is one plausible body away.Spec
Decisions, all settled here:
#Nis a local reference unless it is qualified by a repository:repo#Nandowner/repo#Nare cross-repo and are dropped before number extraction, in whatever markdown wrapper they appear (bare, in a link label, in a parenthetical). Punctuation adjacency stays local —(#13),,#14, and#14/#15all yield local references, because the house prose uses all three. A URL naming an issue (https://github.com/heavy-duty/rig/issues/112) carries no#Nand needs no rule; the doctrine's declaration form is#N, and it stays that way.Blocked bydeclaration names any cross-repo reference, the sweep never flips toready, even if every local reference in it is closed. New decisionFLAG_CROSS_REPO→ one idempotent comment (<!-- issueflow:blocked-cross-repo -->) naming the unresolvable references and saying triage flips this one by hand. It is notFLAG_UNPARSEABLE: the declaration parsed fine, and shipping the wrong diagnosis is what put four false comments on #13–#16.epic_references; they are prose about a child, not a child. If dropping them leaves no references at all, the existing empty-refs behavior (KEEP, no nudge) is correct and unchanged.Tasks
blocked_referencesandepic_referencesthrough it.FLAG_CROSS_REPOtoblocked_decisionand its comment at the API edge, with the marker above.Acceptance criteria
epic_referenceson the real #1 body yields its local children only —#112is absent, and every locally-referenced child still present. Pinned by a case carrying the realPR [rig#112](…)row verbatim.rig#112andheavy-duty/box#9drop;(#13),#14/#15, and a bare#11, #12survive.Blocked bydeclaration naming only cross-repo references decidesFLAG_CROSS_REPO, neverREADYand neverFLAG_UNPARSEABLE.FLAG_CROSS_REPO— the false-promotion case, pinned explicitly.blocked-cross-repocomment is idempotent across two sweeps of the same body, like every other marker.Test plan
Pure-function cases in
test/issueflow-reconcile.test.sh, no network: the real #1 task-list body as a here-doc fixture (the corpus rule — a fixture shaped like the parser proves nothing), the five reference shapes, and the threeblocked_decisioncases including the all-local-closed-plus-cross-repo one that must fail before the fix. Dogfood is a re-run of the live sweep, not new fixture issues: the epic instance is already on the board, so the evidence is #1 parsing clean.Dependencies
Blocked bynothing. #52 isreadyand edits the same file; no ordering between them — whoever lands second rebases.Changelog
CHANGELOG.mdexists on main as of #11. This carries an entry.Claiming this as builder codex-bot-andresmgsl. I am starting implementation now and will open a draft PR from build/61-cross-repo-reference-guards after the first commit.