You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As maintainers of NWACus/web, we have 83 open issues and no consistent way to tell what state any of them is in. We recently adopted an agent-assisted triage workflow (docs/agents/issue-tracker.md, docs/agents/triage-labels.md) that speaks in terms of five canonical triage states — but four of the five don't exist as labels yet, and the backlog predates the workflow entirely:
35 open issues have no labels at all; only 14 of 83 carry a category (bug/enhancement).
Legacy labels overlap the canonical vocabulary: NEW ≈ needs-triage, needs user feedback ≈ needs-info, needs-investigation ≈ needs-triage, question ≈ needs-info.
Issue templates auto-apply labels that fight the new vocabulary: bug_report.md and blank.md apply NEW; claude-task.md applies claude, a label that does not exist, so GitHub silently drops it and those issues arrive unlabeled.
Several labels answer no question anyone asks: area:* (only 6 of 83 open issues carry one; nobody routes work by area), quick fix, urgent, question (zero open uses each).
The result: nobody — maintainer, teammate, contributor, or agent — can query "what needs my attention," "what's ready to pick up," or "what are we waiting on."
Solution
Adopt a single, minimal label vocabulary where every label answers a real query, migrate the backlog onto it, and wire the issue templates so new issues arrive pre-labeled. Then triage the existing 83 issues in phases so every open issue carries exactly one category (bug/enhancement) and one state (needs-triage/needs-info/ready-for-agent/ready-for-human/wontfix).
tenant:nwac (renamed from NWAC Specific; tenant:dvac etc. created when first needed)
Modifiers (4)
good first issue, tech debt, blocked, payload-workaround
Dependabot / PRs (2)
dependencies, javascript (untouched, not part of issue triage)
User Stories
As a maintainer, I want every open issue to carry exactly one category and one state label, so that I can see the shape of the backlog at a glance.
As a maintainer, I want a needs-triage queue, so that I know exactly which issues are waiting on my evaluation and can process them oldest-first.
As a maintainer, I want a needs-info state with a triage-notes comment on each issue, so that reporters know precisely what to answer and stalled issues don't look like active ones.
As a maintainer, I want exactly one label for each concept (no NEW vs needs-triage, no question vs needs-info), so that queries don't silently miss issues filed under a synonym.
As a maintainer, I want new issues to arrive already stamped needs-triage via the issue templates, so that the untriaged bucket never silently regrows.
As a maintainer, I want stale legacy labels (quick fix, urgent, question, area:*) removed, so that the label picker offers only choices we actually use.
As a maintainer, I want tenant-specific issues labeled tenant:<slug>, so that center-specific work (currently 5 NWAC issues) is queryable per tenant and the scheme extends to DVAC/SAC/SNFAC and future centers without inventing new conventions.
As a teammate reviewing this plan, I want the full label inventory with create/migrate/delete/keep decisions in one document, so that I can object to a specific decision rather than reverse-engineering intent from label churn.
As a teammate, I want ready-for-human distinct from ready-for-agent, so that I can pick up work requiring judgment, design decisions, or external access without wading through agent-suitable tasks.
As an open-source contributor, I want good first issue kept and paired with a written brief on the issue, so that I can start contributing without insider context.
As an AFK agent (Claude via @claude mention or triage sessions), I want ready-for-agent to mean "fully specified, with an agent brief," so that I can implement without guessing requirements.
As an AFK agent, I want the claude-task.md template to apply ready-for-agent instead of the nonexistent claude label, so that maintainer-authored agent tasks enter the state machine correctly instead of arriving unlabeled.
As a bug reporter, I want the bug template to stamp bug + needs-triage, so that my report enters the triage queue without anyone having to notice it manually.
As a reporter whose issue is marked needs-info, I want a comment listing the specific questions blocking triage, so that I can respond once with everything needed.
As a maintainer, I want tech-debt issues to carry enhancement + tech debt (modifier, not a third category), so that the category invariant stays simple while tech debt remains queryable.
As a maintainer, I want blocked kept as an orthogonal modifier, so that an issue can be both ready-for-human and blocked without corrupting the state machine.
As a maintainer, I want payload-workaround kept (template-wired, tracks workarounds to revisit when upstream Payload fixes land), so that dormant-but-purposeful tracking survives the cleanup.
As a maintainer, I want rejected enhancements written to .out-of-scope/ when closed wontfix, so that future duplicate requests can be answered by pointing at the prior decision.
As a future maintainer, I want docs/agents/triage-labels.md updated to match the actual label set, so that agent-assisted triage sessions and reality never diverge.
Implementation Decisions
Label creation. Create four state labels with traffic-light colors so state reads at a glance in the issue list: needs-triage (#D93F0B orange, "Maintainer needs to evaluate this issue"), needs-info (#FBCA04 yellow, "Waiting on reporter for more information"), ready-for-agent (#0E8A16 green, "Fully specified; an AFK agent can pick this up"), ready-for-human (#1D76DB blue, "Needs human implementation"). wontfix already exists and completes the state set.
Migrations (9 open issues), then delete the source labels.
Deletions (no migration needed — zero open uses each):question, quick fix, urgent, area:admin, area:frontend, area:backend, area:infra. Deleting a label strips it from closed issues too (13 / 12 / 9 / ~27 historical uses respectively); we accept the history loss. Area labels are dropped because nothing routes by area — only 6 of 83 open issues carry one, and in the new workflow "where in the codebase" lives in the agent brief with actual file pointers.
Rename:NWAC Specific → tenant:nwac via label edit (rename preserves the 5 existing issue associations). Other tenant:<slug> labels are created on demand when an issue actually needs one, not pre-created.
Issue template updates (three files under the GitHub issue-template directory):
Bug report template: labels: bug, NEW → labels: bug, needs-triage.
Blank issue template: labels: NEW → labels: needs-triage.
Claude task template: labels: claude → labels: ready-for-agent (replacing a label that doesn't exist; a maintainer-authored Claude task is fully specified by construction).
Documentation: Update docs/agents/triage-labels.md — the mapping table is already canonical-to-canonical, but the paragraph claiming only wontfix exists becomes stale once labels are created. Because docs are drift-bound (drift.lock), run the drift check wrapper after edits and update drift links if needed.
Backlog triage, phased:
Phase 1 — fast-pass sweep (one session, all 83 issues): title/body-level pass only; assign a category (bug/enhancement) to every issue and stamp everything untriaged with needs-triage. Apply tenant:nwac where applicable. No codebase exploration in this phase.
Phase 3 — hygiene: templates handle auto-labeling on arrival (done above); periodic triage sessions process the three attention buckets (unlabeled, needs-triage, needs-info with reporter reply).
Conventions: every AI-posted triage comment or issue starts with the disclaimer line > *This was generated by AI during triage.* Every triaged issue carries exactly one category and one state; conflicting states get flagged to the maintainer rather than silently resolved.
Testing Decisions
This is a process/configuration change — nothing under the application source tree changes, so no Jest tests. Verification is against observable issue-tracker state via gh queries, which are the natural seams:
Label inventory seam: the repo label list matches the 14-label table exactly — no more, no fewer.
Migration seam: searching open issues for each legacy label (NEW, needs user feedback, needs-investigation, question, quick fix, urgent, area:*, NWAC Specific) returns zero results; the 9 migrated issues carry their target labels; the 5 former NWAC Specific issues carry tenant:nwac.
Template seam: creating a test issue from each of the three templates yields the intended labels (bug + needs-triage / needs-triage / ready-for-agent); the test issues are then closed.
Phase 1 exit criterion: a query for open issues lacking a category label returns zero, and a query for open issues lacking a state label returns zero.
Docs seam: the drift check wrapper (pnpm drift:check) passes after documentation and template edits.
Prior art: none needed — these are the same gh issue list/gh label list queries the triage workflow itself uses day-to-day.
Out of Scope
A priority:* label scheme (the ready-for-* queues plus oldest-first ordering cover current needs; revisit only if a real prioritization query emerges).
Pre-creating tenant:dvac / tenant:sac / tenant:snfac before an issue needs them.
Retroactively relabeling closed issues.
GitHub Actions automation to enforce label invariants (templates + periodic triage sessions are enough for now).
Project boards or milestone restructuring.
The individual triage outcomes of Phase 2 — each themed batch is its own working session with its own maintainer decisions; this PRD only establishes the vocabulary, the wiring, and the plan.
Renaming good first issue or changing how contributors are directed to it.
Further Notes
Label deletion is irreversible for closed-issue history; the deletions above were checked for open-issue usage (all zero) before being proposed.
Bulk label edits should be batched gently — the GitHub search API rate-limited during the investigation for this PRD, so the sweep should prefer gh issue list pagination over per-issue search queries.
.out-of-scope/ does not exist yet; it is created the first time an enhancement is closed wontfix.
Current backlog snapshot for reviewers: 83 open issues; 35 unlabeled; 14 with a category; 12 good first issue; 11 tech debt; 5 NEW; 5 NWAC Specific; 3 needs user feedback; oldest open issue dates to March 2025.
Problem Statement
As maintainers of NWACus/web, we have 83 open issues and no consistent way to tell what state any of them is in. We recently adopted an agent-assisted triage workflow (
docs/agents/issue-tracker.md,docs/agents/triage-labels.md) that speaks in terms of five canonical triage states — but four of the five don't exist as labels yet, and the backlog predates the workflow entirely:bug/enhancement).NEW≈needs-triage,needs user feedback≈needs-info,needs-investigation≈needs-triage,question≈needs-info.needs user feedback(Include events from another AC #673, A3 courses can display alongside avalanche center events #808, Change Forecast Navigation? #919) have no comment telling the reporter what feedback is needed — the label is a dead end.bug_report.mdandblank.mdapplyNEW;claude-task.mdappliesclaude, a label that does not exist, so GitHub silently drops it and those issues arrive unlabeled.area:*(only 6 of 83 open issues carry one; nobody routes work by area),quick fix,urgent,question(zero open uses each).The result: nobody — maintainer, teammate, contributor, or agent — can query "what needs my attention," "what's ready to pick up," or "what are we waiting on."
Solution
Adopt a single, minimal label vocabulary where every label answers a real query, migrate the backlog onto it, and wire the issue templates so new issues arrive pre-labeled. Then triage the existing 83 issues in phases so every open issue carries exactly one category (
bug/enhancement) and one state (needs-triage/needs-info/ready-for-agent/ready-for-human/wontfix).Final vocabulary — 14 labels:
needs-triage,needs-info,ready-for-agent,ready-for-human,wontfixbug,enhancementtenant:nwac(renamed fromNWAC Specific;tenant:dvacetc. created when first needed)good first issue,tech debt,blocked,payload-workarounddependencies,javascript(untouched, not part of issue triage)User Stories
needs-triagequeue, so that I know exactly which issues are waiting on my evaluation and can process them oldest-first.needs-infostate with a triage-notes comment on each issue, so that reporters know precisely what to answer and stalled issues don't look like active ones.NEWvsneeds-triage, noquestionvsneeds-info), so that queries don't silently miss issues filed under a synonym.needs-triagevia the issue templates, so that the untriaged bucket never silently regrows.quick fix,urgent,question,area:*) removed, so that the label picker offers only choices we actually use.tenant:<slug>, so that center-specific work (currently 5 NWAC issues) is queryable per tenant and the scheme extends to DVAC/SAC/SNFAC and future centers without inventing new conventions.ready-for-humandistinct fromready-for-agent, so that I can pick up work requiring judgment, design decisions, or external access without wading through agent-suitable tasks.good first issuekept and paired with a written brief on the issue, so that I can start contributing without insider context.@claudemention or triage sessions), I wantready-for-agentto mean "fully specified, with an agent brief," so that I can implement without guessing requirements.claude-task.mdtemplate to applyready-for-agentinstead of the nonexistentclaudelabel, so that maintainer-authored agent tasks enter the state machine correctly instead of arriving unlabeled.bug+needs-triage, so that my report enters the triage queue without anyone having to notice it manually.needs-info, I want a comment listing the specific questions blocking triage, so that I can respond once with everything needed.enhancement+tech debt(modifier, not a third category), so that the category invariant stays simple while tech debt remains queryable.blockedkept as an orthogonal modifier, so that an issue can be bothready-for-humanandblockedwithout corrupting the state machine.payload-workaroundkept (template-wired, tracks workarounds to revisit when upstream Payload fixes land), so that dormant-but-purposeful tracking survives the cleanup..out-of-scope/when closedwontfix, so that future duplicate requests can be answered by pointing at the prior decision.docs/agents/triage-labels.mdupdated to match the actual label set, so that agent-assisted triage sessions and reality never diverge.Implementation Decisions
Label creation. Create four state labels with traffic-light colors so state reads at a glance in the issue list:
needs-triage(#D93F0B orange, "Maintainer needs to evaluate this issue"),needs-info(#FBCA04 yellow, "Waiting on reporter for more information"),ready-for-agent(#0E8A16 green, "Fully specified; an AFK agent can pick this up"),ready-for-human(#1D76DB blue, "Needs human implementation").wontfixalready exists and completes the state set.Migrations (9 open issues), then delete the source labels.
NEW→needs-triage(5 issues).needs user feedback→needs-info(3 issues: Include events from another AC #673, A3 courses can display alongside avalanche center events #808, Change Forecast Navigation? #919). Because none has triage notes, each migration must be accompanied by a triage-notes comment listing the specific outstanding questions — or, if the original ask can't be reconstructed, demote toneeds-triageinstead.needs-investigation→needs-triage(1 issue: Shared Content (Pages, Media, etc.) #564). Investigation is part of triage evaluation, not a separate state.Deletions (no migration needed — zero open uses each):
question,quick fix,urgent,area:admin,area:frontend,area:backend,area:infra. Deleting a label strips it from closed issues too (13 / 12 / 9 / ~27 historical uses respectively); we accept the history loss. Area labels are dropped because nothing routes by area — only 6 of 83 open issues carry one, and in the new workflow "where in the codebase" lives in the agent brief with actual file pointers.Rename:
NWAC Specific→tenant:nwacvia label edit (rename preserves the 5 existing issue associations). Othertenant:<slug>labels are created on demand when an issue actually needs one, not pre-created.Issue template updates (three files under the GitHub issue-template directory):
labels: bug, NEW→labels: bug, needs-triage.labels: NEW→labels: needs-triage.labels: claude→labels: ready-for-agent(replacing a label that doesn't exist; a maintainer-authored Claude task is fully specified by construction).Documentation: Update
docs/agents/triage-labels.md— the mapping table is already canonical-to-canonical, but the paragraph claiming onlywontfixexists becomes stale once labels are created. Because docs are drift-bound (drift.lock), run the drift check wrapper after edits and update drift links if needed.Backlog triage, phased:
bug/enhancement) to every issue and stamp everything untriaged withneeds-triage. Applytenant:nwacwhere applicable. No codebase exploration in this phase.wontfixmaintainer call; rejected enhancements seed.out-of-scope/; (b) well-specified bugs → repro + agent brief →ready-for-agent(e.g. Scheduled publishing breaks on-demand revalidation: future-dated documents 404 until ISR fallback #1125, Checkbox not respecting click on links #1094, Improve UX or exclude draft pages from navigation #1084, Potential Appearance Issue on Admin Landing Page with Center Icons #598); (c)needs-inforepair — proper triage-notes comments on Include events from another AC #673, A3 courses can display alongside avalanche center events #808, Change Forecast Navigation? #919; (d)good first issue/tech debtpool — likely rich inready-for-agentoutcomes; (e) thetenant:nwaccluster (Rebuild NWAC Django Forecast Tool #134, NWAC Data Portal #1106, NWAC Wx Station Graphs #1107, NWAC Data Accumulation table #1108, NWAC Weather Forecast Archives #1131) triaged as a group — probably ends in a PRD rather than five separate briefs; (f) remainder, oldest-first.needs-triage,needs-infowith reporter reply).Conventions: every AI-posted triage comment or issue starts with the disclaimer line
> *This was generated by AI during triage.*Every triaged issue carries exactly one category and one state; conflicting states get flagged to the maintainer rather than silently resolved.Testing Decisions
This is a process/configuration change — nothing under the application source tree changes, so no Jest tests. Verification is against observable issue-tracker state via
ghqueries, which are the natural seams:NEW,needs user feedback,needs-investigation,question,quick fix,urgent,area:*,NWAC Specific) returns zero results; the 9 migrated issues carry their target labels; the 5 formerNWAC Specificissues carrytenant:nwac.bug+needs-triage/needs-triage/ready-for-agent); the test issues are then closed.pnpm drift:check) passes after documentation and template edits.Prior art: none needed — these are the same
gh issue list/gh label listqueries the triage workflow itself uses day-to-day.Out of Scope
priority:*label scheme (theready-for-*queues plus oldest-first ordering cover current needs; revisit only if a real prioritization query emerges).tenant:dvac/tenant:sac/tenant:snfacbefore an issue needs them.good first issueor changing how contributors are directed to it.Further Notes
gh issue listpagination over per-issue search queries..out-of-scope/does not exist yet; it is created the first time an enhancement is closedwontfix.good first issue; 11tech debt; 5NEW; 5NWAC Specific; 3needs user feedback; oldest open issue dates to March 2025.