GitHub Issues standard
Standard scope
Applies to: All HCS-governed GitHub repos with Issues enabled (app-solution orgs, AzureLocal, thisismydemo, Hybrid Cloud Solutions, etc.) — not TierPoint (GitLab) Domain: github-issues Status: Active
This standard governs how GitHub's native issue taxonomy is used across the estate — issue types, issue fields, and labels — and the one thing we add on top: the roadmap marker. It exists so we don't reinvent what GitHub already ships. See work-item-sync.md for how these connect to ADO, and work-items.md for ADO-side authoring rules.
Two-standard split — read this before triaging or authoring an issue:
- User-submitted issues (anyone files a Bug or Feature-request) — we don't control how they're written. This standard defines only how we triage them: type, priority, effort, labels. Do not reject an issue for poor writing; triage it and, if accepted, let the mirrored ADO item be the well-authored record.
- Items we author and sync (the ADO→GitHub roadmap projection, and any ADO-originated GitHub issue) — these do have an authoring bar: they must follow the ADO User-Story/Feature authoring rules in
work-items.md(title/description/AC), carryado-managed, and be locked.
Issue types — use the GitHub-native defaults
GitHub ships three default org-level issue types. Use them as-is. Do not create custom types.
| Type | Use when |
|---|---|
| Bug | A defect — something is broken. GitHub is master (see work-item-sync.md Flow 1). |
| Feature | A feature request or roadmap candidate. GitHub is master until approved, then ADO becomes master and the approved item projects back down (Flow 2). |
| Task | A chore / work unit. Rare for external-facing repos; mostly internal. |
If an issue type is disabled at the org level, re-enable it — do not work around a disabled type with a label.
Issue fields — use the GitHub-native defaults, not label workarounds
Every org gets four preconfigured, typed fields. Use these instead of priority/* or effort/* labels.
| Field | Type | Maps to ADO | Pinned to |
|---|---|---|---|
| Priority | single-select | Priority 1–4 | Bug, Feature |
| Effort | single-select/number | Story Points / Effort | Bug, Feature |
| Start date | date | schedule alignment | Feature |
| Target date | date | schedule alignment | Feature |
Configure these once per org (Part E1 of the pmo plan); do not redefine them per repo.
The one field we add: Delivery Stage
A custom org-level single-select field, used only on the ADO→GitHub roadmap projection (Flow 2):
Backlog → Approved → Roadmap → In-Progress → ShippedThis is what makes the roadmap queryable/reportable instead of just tag-present/absent. It is set and updated only by the sync bot — never manually.
Labels — minimal, workflow-only
Labels are not used for type or priority anymore (the native type + fields above cover those). The full reserved label set:
| Label | Meaning | Set by |
|---|---|---|
needs-triage | Un-triaged intake — new issue, not yet reviewed | anyone filing |
ado-tracked | Issue has a linked ADO work item (Flow 1) | sync bot |
in-progress | Linked ADO item is actively being worked (Flow 1) | sync bot |
resolved | Linked ADO item resolved, pending close (Flow 1) | sync bot |
wont-fix | Linked ADO item closed as won't-fix (Flow 1) | sync bot |
roadmap | Approved Feature projected from ADO — on the public roadmap (Flow 2) | sync bot |
ado-managed | Lock marker — this issue is a bot-owned ADO projection; do not edit (Flow 2) | sync bot |
cross-repo | Affects multiple repos | anyone |
Do not add new labels for type/priority/effort — use the native fields. If a genuinely new workflow label is needed, add it to this table via a PR first.
Enforcement — "no one can edit that tag"
GitHub has no hard read-only-issue primitive. The accepted pattern, used here:
- The ADO→GitHub projection (Flow 2) is created/updated only by the sync bot identity (a dedicated GitHub App or fine-grained PAT — never a personal token).
- The projected issue is locked (
lock conversation) immediately after creation/update. - A scheduled reconcile job diffs the projection against ADO state; any manual edit, unlock, or label change is reverted and the issue is re-locked.
ado-managedis the human-visible signal — anyone looking at the issue sees it's bot-owned before they try to edit it.
Roadmap surface — GitHub Projects (v2) board
The roadmap lives as an org-level GitHub Projects (v2) board, populated by the Flow 2 sync (projected issues + their Delivery Stage field). No ROADMAP.md file is generated.
Any web page (platform.hybridsolutions.cloud, product sites) reads the live roadmap via the Projects v2 GraphQL API — query the project's items and the Delivery Stage field, fetched at build time or on a schedule, rendered as a normal page. This keeps one source of visual truth (the board) instead of a board plus a separately-synced markdown file.
Issue templates
Repos onboarded with the intake layer get .github/ISSUE_TEMPLATE/{bug,feature,task}.yml, bound to the native types above (templates/.github/ISSUE_TEMPLATE/ in this repo — stamped by the onboarding scaffolder). Do not hand-author bespoke templates per repo; extend the shared templates via a PR to this repo if a field is missing.
Remote agents
Issue intake is designed to be agent-agnostic — either GitHub's native Copilot coding agent or a Claude-Code-via-Action workflow can be assigned to work a labeled issue. No agent is wired in by this standard; that's a separate, later decision. Don't build agent-specific coupling into the templates or labels above.
Reference — ADO ↔ GitHub mapping
| GitHub (native) | ADO |
|---|---|
| Issue type Bug | Bug work item |
| Issue type Feature (user-submitted request) | mirrored up as a Feature candidate; on approval becomes ADO Feature (master) |
| Issue type Task | Task work item |
| Field Priority | Priority 1–4 |
| Field Effort | Story Points / Effort |
Label roadmap + locked | ADO Feature on the roadmap (ADO is master, GitHub is read-only projection) |
Label ado-managed | any ADO-mastered item projected to GitHub |
Field Delivery Stage | Feature's roadmap state (Backlog → Approved → Roadmap → In-Progress → Shipped) |