Skip to content

Blockers live in a free-text board field, not GitHub's built-in blocked-by relationship: 73 edges on 29 cards, and the one built-in edge is invisible to /issue-check #1893

Description

@devin-ai-integration

Blockers are recorded in a free-text project field (Blocked by) instead of GitHub's built-in issue relationship ("Blocked by" / "Blocking" on the issue sidebar, REST issues/{n}/dependencies/blocked_by). The owner assumed the built-in one was already in use (2026-10-05). It is not: across all 470 open issues, exactly one built-in edge exists, and the owner added it today.

Measured (2026-10-05, 36efdf54a)

$ gh api --paginate 'repos/jlaustill/c-next/issues?state=open&per_page=100' \
    --jq '.[] | select(.pull_request==null) | select(.issue_dependencies_summary.total_blocked_by > 0) | .number'
1428          # -> #1844, added by the owner 2026-10-05 instead of the text field

The board (642 items, --paginate) has a non-empty Blocked by text field on 29 cards: 8 open and 21 closed. Parsed with BlockedByField.parse, the leading-run rule that order-backlog already uses, they name 73 edges, 28 of them on open cards:

open card status blockers per BlockedByField.parse
#1443 Backlog #1444 #1445 #1446 #1447 #1448 #1449 #1450 #1451 #1452 #1466 #1653 #1825
#1448 WIP #1320 #1322 #1447 #1398 #1430
#1668 Backlog #1688 #1780 #1737
#920 Grooming #917 #918 #919
#1324 Backlog #1313 #1357, plus the text "every open v0.3.1-milestone card"
#1457 Grooming #1456
#1831 Grooming #1745
#1832 Grooming #1745

A bare #\d+ scan of the same text would invent edges, because much of it is commentary that cites issues which are not blockers. BlockedByField.ts's header measured five such edges on 2026-09-12. One card (#1489) has text but parses to no blockers.

Today the text field is the only blocker source for:

  • Skills: .claude/skills/issue-check/SKILL.md (Phase 1d, 19 references) and .claude/skills/start-issue/SKILL.md (Phase 3 reads it, Phase 7c appends to it).
  • Docs: CLAUDE.md § "A Card That Turns Out Blocked Is Paused" and docs/WORKFLOW.md § Blocked by.
  • Backlog ordering: scripts/order-backlog.ts, scripts/backlog/{BlockedByField,BacklogOrder}.ts and scripts/utils/ProjectBoard.ts (BLOCKED_FIELD), run by .github/workflows/backlog-order.yml.
  • Board setup: npm run project:setup, which creates the field.

Because nothing else reads the built-in relationship, the edge the owner added on #1428 is invisible to /issue-check. #1428 would still be recommended as unblocked.

The built-in relationship also bears on two open cards about the text field: #1665 (GitHub caps the field near 1 KB, so a required append eventually cannot be written) and #1419 (records destroyed by overwrites, since the field keeps no history).

Definition of done

Open question for the owner

The current rule says Blocked by is a permanent record that is never cleared and only appended to. Does a built-in edge to a blocker that has closed satisfy that "record" requirement, or does the history also need a comment? This decides box 2.

Written by Devin

Activity

added this to the v0.3.1 milestone on Oct 5, 2026

devin-ai-integration commented on Oct 6, 2026

@devin-ai-integration
ContributorAuthor

Starting work on branch refactor/1893-built-in-blocked-by (board: WIP, read 2026-10-06T11:26:31Z).

Re-measured 2026-10-06 on 919c0d152: 29 cards with a non-empty Blocked by (8 open, 21 closed), 73 edges by BlockedByField.parse, unchanged from the body. Built-in edges, open and closed issues: #1428 ← #1844, plus two the body's open-only scan did not see, on closed #1285 (← #7, ← #1241, both closed).

One edge parse finds that the text says is gone: #1668's field ends with "#1780 no longer gates it". The parse still takes #1780 from the leading run of its own segment, and #1780 is open. A literal box 1 would therefore create #1668 ← #1780 and make #1668 read as blocked. Asking the owner before any edge is written.

Approach, under research, not yet approved:

  1. A migration script (dry run by default) that re-measures, creates each built-in edge, and posts each card's full field text as a comment, so no commentary is lost (box 2).
  2. ProjectBoard/OrderBacklog read blockers from the built-in relationship. /issue-check Phase 1d and UNBLOCKS, and /start-issue Phases 3 and 7c, read and write it. Each reader gets a mutation-checked test (box 3).
  3. CLAUDE.md, docs/WORKFLOW.md and both skills say to record a blocker as a built-in relationship (box 4).
  4. The text field's fate is an owner ruling, recorded here (box 5).

devin-ai-integration commented on Oct 6, 2026

@devin-ai-integration
ContributorAuthor

Owner ruling 1, 2026-10-06. The migration does not create #1668 ← #1780. #1668's field withdraws it ("row H ruled out of this card (R10) — #1780 no longer gates it"), and #1780 is open, so a literal migration would have marked #1668 blocked. Box 1 is reworded to "every edge a Blocked by value still claims". The old wording is quoted under the box. #1668's full field text is still preserved in a comment (box 2).

Written by Devin

devin-ai-integration commented on Oct 6, 2026

@devin-ai-integration
ContributorAuthor

Owner ruling 2, 2026-10-06 (box 5). Once the migration is verified, the board's Blocked by text field is deleted. Each card's text is kept word for word in a comment on that card. The built-in relationship plus that comment are the record. Both keep history, which answers #1419 (records overwritten). With no field, its ~1 KB cap cannot be hit, which answers #1665. npm run project:setup stops creating the field.

This also settles the body's open question (box 2): a built-in edge to a closed blocker stays on the sidebar, so it is the record. The one verbatim comment per card carries the wording, and no other history comment is needed.

Written by Devin

devin-ai-integration commented on Oct 6, 2026

@devin-ai-integration
ContributorAuthor

Migration applied (npx tsx scripts/migrate-blocked-by.ts --apply, 2026-10-06):

#920: claims #917 #918 #919  (exists: #917)
#1298: claims #1357
#1300: claims #1357
#1303: claims #1357
#1318: claims #1285 #1357
#1322: claims #1316 #1321
#1323: claims #1301 #1319
#1324: claims #1313 #1357
#1443: claims #1444 #1445 #1446 #1447 #1448 #1449 #1450 #1451 #1452 #1466 #1653 #1825
#1444: claims #1446 #1447 #1449 #1450 #1452 #1435 #1745 #1672
#1445: claims #1317 #1449 #1450
#1447: claims #1323 #1446 #1472
#1448: claims #1320 #1322 #1447 #1398 #1430
#1449: claims #1323 #1447
#1450: claims #1322 #1449
#1451: claims #1446 #1447 #1449 #1450 #1452
#1452: claims #1447 #1449 #1664 #1671
#1457: claims #1456
#1489: claims -
#1511: claims #1508
#1544: claims #1553
#1664: claims #1667 #1668
#1666: claims #1664 #1668
#1667: claims #1668
#1668: claims #1688 #1737
#1672: claims #1745
#1681: claims #1668
#1831: claims #1745
#1832: claims #1745

29 cards with text; 72 claimed edges (1 withdrawn by ruling); 1 already built-in.
Created 71 edges and 29 comments.
Re-read: every claimed edge exists as a built-in relationship.

The one pre-existing edge (#920 ← #917) was a single hand-made probe of the endpoint just before the run. #1668 ← #1780 skipped per ruling 1. Every card's text is preserved verbatim in a comment marked <!-- blocked-by-migration #1893 -->.

Written by Devin

devin-ai-integration commented on Oct 7, 2026

@devin-ai-integration
ContributorAuthor

Box 6: the board's Blocked by field is deleted (by the owner, 2026-10-06). The project API now lists the fields as Title, Assignees, Status, Labels, Linked pull requests, Milestone, Repository, Reviewers, Parent issue, Sub-issues progress, Created, Updated, Closed.

Written by Devin

added a commit that references this issue on Oct 7, 2026
added a commit that references this issue on Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

tech-debtInternal codebase or process debt, not a C-Next language defect

Projects

  • Status
    Done

Relationships

None yet

Development

No branches or pull requests

Issue actions