Skip to content

work-unblock: find why parents with every sub-issue closed stay open #12456

Open

Description

@kyle-sexton

Refs: #12284

Owner: unassigned.

Summary

Post-merge bookkeeping has no working owner for parent issues. On 2026-11-01, 25 of 67 open parent issues had every sub-issue closed (for example #6638, 15 of 15). Closed parents lagged their last child's close by p50 0.8 h and p90 159 h (n 53). Merged -> issue closed is p50 0 h, so ordinary Closes links work; only parent close-out lags. Source: audit comment, gaps-checklist row 1.

work-unblock's parent auto-close is the existing owner (.github/workflows/work-unblock.yml). Which close condition each skipped parent fails is UNVERIFIED.

Done when

  • The parents open today with every sub-issue closed are listed, each with the auto-close condition it fails.
  • Each failing condition is fixed, or it is recorded as the intended reason for a person or lane to close that parent.
  • The parent close lag (last child close -> parent close) is re-measured and posted here.

Activity

  1. github-actions commented on Nov 2, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: scoped
    Basis: automated intake triage; the lanes App applied this class.

    Size: Medium
    Complexity: Medium
    Uncertainty: Knowable
    Flags: none
    Blocked by: none

    Understood: 25 of 67 open parent issues have every sub-issue closed, and work-unblock's parent auto-close is not closing them. The ask is to list those parents, record which close condition each fails, fix each condition or record it as an intended manual close, and re-measure the parent close lag.

    Nothing is missing. The first step is to read the workflow and the parents' state, which will settle which conditions fail. The final re-measure needs time to pass after the fix.

    No likely duplicates among the open issues. #12284 is the parent audit this refs.

    Automated triage, applied by the lanes App.

  2. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.
    on Nov 2, 2026
  3. added
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    and removed
    admission-deferredAdmitted but waiting for WIP room; the hourly work-unblock sweep labels it agent-ready.
    on Nov 2, 2026
  4. github-actions commented on Nov 2, 2026

    @github-actions
    Contributor
    No description provided.
  5. github-actions commented on Nov 2, 2026

    @github-actions
    Contributor
    No description provided.
  6. added
    host-runNeeds an unattended run on a host; the host runner takes it, not a person or the issue lane.
    and removed
    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.
    on Nov 2, 2026
  7. melodic-automation-lanes commented on Nov 2, 2026

    @melodic-automation-lanes
    Contributor

    The work-resolve-issue lane stopped on this issue (host-only): the run reports the work needs a host run the lane cannot make.
    It added host-run and removed agent-ready: an agent run on a host builds it, and it waits on no decision from a person.

    In the run's words:

    host-only: every done-when item needs authenticated reads of live tracker state at a scale this lane cannot make. Item 1 means listing each open parent whose sub-issues are all closed, then reading its comments (split record), sub_issue_added events, body task list and each child's closed_by, state_reason and merge to find which splitLeftOpen condition it fails, or reading the label-unblocked job logs, which print '#N stays open: <reason>' (Actions logs need auth). Item 3 needs the lag measured again after a fix has run. This lane has no gh. Unauthenticated WebFetch of the API gets 60 requests an hour and summarized output, and the open-issues listing alone is about 640K characters a page.

    What the run says it did not do:

    • List of the open parents with every sub-issue closed, and the condition each fails: needs authenticated gh API reads or the label-unblocked job logs
    • Fix or record each failing condition: depends on that list, and condition 1 (non-split parents never auto-close) may need an owner decision
    • Re-measure the parent close lag: needs an authenticated sweep after any fix has run
    • tidy, review, verify and the checks steps: no change was made

    Run: https://github.com/melodic-software/claude-code-plugins/actions/runs/41504545903

    To hand it back to the lane, remove host-run and add agent-ready again.

  8. kyle-sexton commented on Nov 3, 2026

    @kyle-sexton
    MemberAuthor

    Claim. Backlog HITL host-run worker is taking this now.

  9. kyle-sexton commented on Nov 3, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded.
    (agent; not an owner decision)

    For these open parents with every sub-issue closed, work-unblock's refusal to auto-close is the intended close condition (owner Q93; docs/conventions/pr-pipeline/README.md "work-unblock closes a split parent as completed only when every sub-issue closed with state_reason completed..."). A person or the HITL lane closes, re-scopes or re-splits each one:

    Not covered by this record: eight parents whose own task list holds acceptance criteria rather than sub-issue citations (#7589, #7577, #7558, #6924, #6755, #5948, #5946, #11124). Auto-close says "not a split parent", admission refuses them as Size Large (SIZE_SPLIT_DONE) at status: confirmed, the issue lane stops them split-required, and unpark treats only a blocked_by close as news, not the last sub-issue close (.github/scripts/work-unblock/label-unblocked.mjs:723-743). Only a person closes them. Changing that changes what lanes do unattended, so it goes to the owner.

    Basis: the label-unblocked: #N stays open: <reason> lines of the 24 scheduled work-unblock runs from 2026-11-02T03:48Z to 2026-11-03T02:48Z (every one of the 18 parents logged a reason, so the hourly rotation and limits.parent-rescan-per-run are not the cause), and a read of each parent's sub-issues, events and task list on 2026-11-03.

  10. kyle-sexton commented on Nov 3, 2026

    @kyle-sexton
    MemberAuthor

    Host run. Diagnosed why each open parent with every sub-issue closed stays open, from 24 work-unblock sweep logs and the parents' own sub-issues, events, task lists and admission comments.

    What ran (2026-11-03, gh as the owner token through the hub gate; no code change):

    • Listed open issues with sub_issues_summary: 56 open parents, 18 with every sub-issue closed (25 of 67 on 2026-11-01).
    • Read the label-unblocked: #N stays open: <reason> lines of the 24 scheduled work-unblock runs 2026-11-02T03:48Z to 2026-11-03T02:48Z (one run, 41504009868, returned no lines). Every one of the 18 logged a reason, so the hourly rotation and limits.parent-rescan-per-run are not the cause.
    • Read each parent's sub-issues, sub_issue_added events, body task list and newest lanes App comment.

    Done-when 1, each parent and the condition it fails (admit.mjs splitLeftOpen):

    Class Parents Condition Who closes
    A #7589, #7577, #7558, #6924, #6755, #5948, #5946, #11124 "not a split parent": the body's task list is the parent's own acceptance criteria, not sub-issue citations nobody today (see below)
    B #12446 (all 4), #9668, #6228, #6476 (18 of 71), #7573, #7559, #11823 a sub-issue closed not_planned a person or the HITL lane re-scopes or closes (Q93, intended)
    C #9668, #7407 App-closed 2026-10-29, reopened from the kyle-sexton account 2026-10-31 (#7407 now also has no task list) intended: a reopen means work is left
    D #4281 recurring intended
    E #5901 in flight, agent-ready the issue lane

    sub_issues_summary.completed counts not_planned closes, so "every sub-issue closed" overstates what auto-close may take. Classes B to E are recorded as intended in the **Decision recorded.** comment on this issue.

    Class A is a loop with no exit: auto-close refuses it (not a split parent); admission refuses Size Large with SIZE_SPLIT_DONE and parks it at status: confirmed; the issue lane stops it split-required (#6924 at 2026-11-02T21:52Z, #7577 on 2026-11-01); and unpark (.github/scripts/work-unblock/label-unblocked.mjs:723-743) treats only a blocked_by close as news, never the last sub-issue close. Only a person closes these.

    Done-when 2, class A, is open for an owner decision. The recorded decisions do not cover it:

    • Owner Q9, the already-done close, is cited only in code (check-trusted-trigger.mjs:439). Its row is in neither decision record. As built, done-evidence.mjs:26-37 accepts only a cited commit or merged pull request whose message closes this issue itself. The children's pull requests close the children, so a class A parent never passes that check.
    • Q-F (2026-10-30) approved fix(intake-triage): refresh split-wait admission comments and close hand-split parents #11323, "close hand-split parents". What it built closes only parents whose open task items each cite a sub-issue (isSplitParent).
    • No row lets a lane judge that a parent's own criteria are met and close it.

    Options:

    1. (recommended) When a parent's sub-issues are all closed completed, admit it to the issue lane at any Size for one verify-and-close run, with a new evidence rule: each criterion is checked on the default branch, then the parent closes. Basis: the run already closes already-done work (stop-routes.json:37). Automation Lanes offered to build it after fix(pr-pipeline): skip a lane's key leg while its key is out of credit #12617 and feat(pr-pipeline): route issues a lane cannot finish to host-run at admission #12628.
    2. Intake re-judges Size on re-entry once the children are closed, so a small residue runs as an ordinary issue.
    3. Keep the current behaviour (a person closes them) and record it.

    Done-when 3, baseline lag: 55 parents closed since 2026-10-30 with closed children. Last child close to parent close: p50 1.1 h, p90 46.7 h, max 327.6 h. 8 more parents closed before their last child and are left out. The post-fix re-measure is still owed.

    Waste found: my first GraphQL search used $cursor instead of $endCursor, so gh --paginate fetched page 1 over and over for about 3 minutes until I stopped it. That was my own error.

    Do not close #12456: done-when 2 (class A) waits on the owner, and done-when 3 needs a re-measure after the fix.

    Target labels: add none; remove host-run.

  11. kyle-sexton commented on Nov 3, 2026

    @kyle-sexton
    MemberAuthor

    Decision recorded.
    (agent; not an owner decision)

    Class A: a parent whose own task list is its acceptance criteria, and whose sub-issues all closed completed (today: #7589, #7577, #7558, #6924, #6755, #5948, #5946, #11124). Once its last sub-issue closes completed, admit the parent to the issue lane at any Size for one verify-and-close run.

    • The run checks each of the parent's done-when items against the merged work, citing each check.
    • It closes completed only when every item is met, and it never closes to lower the count.
    • When an item is unmet, it posts which one and leaves the parent open with the gap named.

    Classes B to E stay as recorded above. Class B means a sub-issue closed not_planned, which Q93 holds.

    Basis:

    • Owner standing direction: s2 says a stop that is not an intent change, a design-altering finding or HIGH/CRITICAL security or cost "is a defect to fix, not a reason to ask me", and s10 sets maximum throughput to zero open issues.
    • stop-routes.json:37 already gives the issue lane a close route for already-done work, so this adds no new mechanism.
    • Closing on checked criteria follows the owner's rule against closing to cut the count (2026-10-31).

    Build: Automation Lanes, when the hub assigns it. Re-measure parent close lag against this issue's baseline after the fix: p50 1.1 h, p90 46.7 h, over 55 parents since 10-30.

  12. removed
    host-runNeeds an unattended run on a host; the host runner takes it, not a person or the issue lane.
    on Nov 3, 2026
  13. kyle-sexton commented on Nov 3, 2026

    @kyle-sexton
    MemberAuthor

    Correction: the class A record above is withdrawn as an agent decision.

    The comment above (6594518053) recorded the class A verify-and-close as an agent decision under s2. That was wrong.

    • Q9's already-done close needs a merged commit that closes the parent's own number.
    • The proposed rule widens that, so it gives the lanes a new unattended power.
    • AGENTS.md reserves that kind of change for the owner: "Ask first ... when the change alters what agents may do unattended and the owner has not decided that change."

    Status: class A is an open owner question. Automation Lanes owns it. It is building the change behind do-not-merge and will put the question to the owner in its morning report. Classes B to E stay as recorded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: lowNice-to-have, cosmetic, or speculative; opportunistic.status: readyTriaged, unblocked, and fully specified; eligible to pick up.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    Fields

    Work status

    agent-ready

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions