Label an issue that already has an open PR, reconciled by forge-groom #60

Open
opened 2026-09-21 16:47:35 +01:00 by allod-agent · 0 comments
Member

Mark an issue that already has an open pull request, so a tracker reader — human or agent — can tell an unstarted issue from an implemented one awaiting review. An issue stays open until its PR merges, so neither forge issue list nor the Forgejo web UI can currently distinguish the two, and the cost is re-implementing work that is already sitting in a branch.

Primary goals:

  • A label, not a second source of truth — the mark is a cache of a fact the forge already holds in PR bodies, recomputed from scratch on every run, never merged into.
  • Exactly one writer — forge-groom, which already walks every open issue and PR weekly and already holds label-write authority. Nothing else sets or clears it, and no human maintains it by hand.
  • Visible where the tracker is read — a label shows in the web UI and in forge issue list, and is filterable; a computed column would exist only inside this CLI.
  • Cadence matched to the failure — weekly reconciliation is useless for an issue filed and implemented the same afternoon, and entirely sufficient for one rediscovered months later, which is the only case that has cost anything.

Current state and specifics

cmd/forge/issue.go:98-104 builds each listing row from number, title, author, labels and milestone; :155-165 prints the same fields in issue view. Forgejo's issue objects carry no linked-PR field — pull_request is populated only when the issue is a PR — so the link exists nowhere but in the PR bodies.

Measured cost of not having it: a session read forge issue list, saw allod/archetypes#21 open, implemented it end to end, and found at push time that allod/archetypes#24 had implemented the same issue seven weeks earlier and was still open. The issue list was correct and useless.

The link is recoverable without new state. Every implementation PR links its issue by convention (memory.md, PR Workflow: Closes owner/repo#N, or Refs owner/repo#N on the earlier PRs of a chain), so scanning open PR bodies for references recovers it exactly.

Why a groom label rather than a computed column

A field rots when more than one thing writes it, or when nothing recomputes it. Both are avoidable here, because the reconciler already exists.

forge-groom (allod/memory skills/forge-groom/SKILL.md) already walks every open issue and PR in every public repo weekly, already recomputes each answer from what is true on master rather than merging into prior state, and already has label-write authority bounded to a fixed set — landed?, ready-to-merge, blocked, stale, decision. Its table's own rule is the property that matters: "Remove a groom label the run no longer supports." A label added to that set inherits single-writer reconciliation by construction, including removal when a PR closes unmerged — the exact drift a hand-maintained label would suffer.

The alternative considered and rejected: deriving the link on every issue list from one extra fetch of open PRs. It costs no stored state and is never stale, but it exists only inside this CLI, so the web UI — where a human actually browses — still shows nothing. Keep it in reserve if a week of staleness proves too slow in practice.

Suggested default

  • Add one label to the groom set, has-pr or similar, set on an open issue when an open PR's title or body references it, and removed when no open PR does. Accept the bare #N and the repo-qualified owner/repo#N forms, ignoring a qualified reference naming a different repository. A casual mention is a tolerable false positive — the label only says "go read that PR", which is the right action either way — so prefer matching loosely; a missed link is the expensive direction.
  • Name the PR in the groom's report so the label is never the only place the fact appears.
  • The label must exist in a repo before it can be applied; the groom's existing rule covers this — report the missing label rather than creating it, and a human creates it once.

Scope

In scope: the groom's action table and report in allod/memory skills/forge-groom/SKILL.md, and whatever forge capability the scan needs beyond forge pr list as it stands.

Out of scope: closed PRs, which would make every long-lived issue noisy; any hand-maintained field; blocking or reordering behaviour of any kind; and the derived listing column, kept in reserve as above.

Part of allod/strategy#48. Supersedes the derive-on-read design first proposed as allod/tools#220; the owner's reasoning is on allod/memory#59.

Mark an issue that already has an open pull request, so a tracker reader — human or agent — can tell an unstarted issue from an implemented one awaiting review. An issue stays open until its PR merges, so neither `forge issue list` nor the Forgejo web UI can currently distinguish the two, and the cost is re-implementing work that is already sitting in a branch. Primary goals: - **A label, not a second source of truth** — the mark is a cache of a fact the forge already holds in PR bodies, recomputed from scratch on every run, never merged into. - **Exactly one writer** — `forge-groom`, which already walks every open issue and PR weekly and already holds label-write authority. Nothing else sets or clears it, and no human maintains it by hand. - **Visible where the tracker is read** — a label shows in the web UI and in `forge issue list`, and is filterable; a computed column would exist only inside this CLI. - **Cadence matched to the failure** — weekly reconciliation is useless for an issue filed and implemented the same afternoon, and entirely sufficient for one rediscovered months later, which is the only case that has cost anything. ### Current state and specifics `cmd/forge/issue.go:98-104` builds each listing row from number, title, author, labels and milestone; `:155-165` prints the same fields in `issue view`. Forgejo's issue objects carry no linked-PR field — `pull_request` is populated only when the issue *is* a PR — so the link exists nowhere but in the PR bodies. Measured cost of not having it: a session read `forge issue list`, saw `allod/archetypes#21` open, implemented it end to end, and found at push time that `allod/archetypes#24` had implemented the same issue seven weeks earlier and was still open. The issue list was correct and useless. The link is recoverable without new state. Every implementation PR links its issue by convention (`memory.md`, PR Workflow: `Closes owner/repo#N`, or `Refs owner/repo#N` on the earlier PRs of a chain), so scanning open PR bodies for references recovers it exactly. ### Why a groom label rather than a computed column A field rots when more than one thing writes it, or when nothing recomputes it. Both are avoidable here, because the reconciler already exists. `forge-groom` (`allod/memory` `skills/forge-groom/SKILL.md`) already walks every open issue and PR in every public repo weekly, already recomputes each answer from what is true on master rather than merging into prior state, and already has label-write authority bounded to a fixed set — `landed?`, `ready-to-merge`, `blocked`, `stale`, `decision`. Its table's own rule is the property that matters: *"Remove a groom label the run no longer supports."* A label added to that set inherits single-writer reconciliation by construction, including removal when a PR closes unmerged — the exact drift a hand-maintained label would suffer. The alternative considered and rejected: deriving the link on every `issue list` from one extra fetch of open PRs. It costs no stored state and is never stale, but it exists only inside this CLI, so the web UI — where a human actually browses — still shows nothing. Keep it in reserve if a week of staleness proves too slow in practice. ### Suggested default - Add one label to the groom set, `has-pr` or similar, set on an open issue when an open PR's title or body references it, and removed when no open PR does. Accept the bare `#N` and the repo-qualified `owner/repo#N` forms, ignoring a qualified reference naming a different repository. A casual mention is a tolerable false positive — the label only says "go read that PR", which is the right action either way — so prefer matching loosely; a missed link is the expensive direction. - Name the PR in the groom's report so the label is never the only place the fact appears. - The label must exist in a repo before it can be applied; the groom's existing rule covers this — report the missing label rather than creating it, and a human creates it once. ### Scope In scope: the groom's action table and report in `allod/memory` `skills/forge-groom/SKILL.md`, and whatever `forge` capability the scan needs beyond `forge pr list` as it stands. Out of scope: closed PRs, which would make every long-lived issue noisy; any hand-maintained field; blocking or reordering behaviour of any kind; and the derived listing column, kept in reserve as above. Part of allod/strategy#48. Supersedes the derive-on-read design first proposed as allod/tools#220; the owner's reasoning is on allod/memory#59.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
allod/memory#60
No description provided.