# Issue tracker: GitHub

Issues and specs for SnagBadger live at https://github.com/CosticaPuntaru/SnagBadger/issues. Use the `gh` CLI for all operations.

## Conventions

- **Create an issue**: `gh issue create --title "..." --body "..."`. For multi-line bodies, write the exact text to a temporary UTF-8 file and pass --body-file <path>. Use this for issue and PR bodies and comments.
- **Read an issue**: `gh issue view <number> --json number,title,body,labels,comments`.
- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
- **Make an issue a sub-issue of a parent**: `gh issue create --parent <parent> ...`, or `gh issue edit <parent> --add-sub-issue <child>` afterwards (`gh` 2.94+). Older `gh`: `gh api --method POST repos/<owner>/<repo>/issues/<parent>/sub_issues -F sub_issue_id=<child-db-id>` (database id, as in **Blocking** below). Without sub-issues, put `Part of #<parent>` at the top of the child body.
- **Comment on an issue**: `gh issue comment <number> --body "..."`
- **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
- **Close**: `gh issue close <number> --comment "..."`

Infer the repo from `git remote -v`; `gh` does this automatically when run inside a clone.

## Pull requests as a triage surface

**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_

When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents:

- **Read a PR**: `gh pr view <number> --comments` and `gh pr diff <number>` for the diff.
- **List external PRs for triage**: `gh api --paginate 'repos/{owner}/{repo}/pulls?state=open' --jq '.[] | select(.author_association | IN("OWNER","MEMBER","COLLABORATOR") | not) | {number, title, author: .user.login, author_association, labels: [.labels[].name]}'`.
- **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`.

GitHub shares one number space across issues and PRs, so a bare `#42` may be either: resolve with `gh pr view 42` and fall back to `gh issue view 42`.

## When a skill says "publish to the issue tracker"

Create a GitHub issue.

## When a skill says "fetch the relevant ticket"

Read it as in **Read an issue** above.

## Wayfinding operations

Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.

- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`.
- **Child ticket**: an issue linked to the map as a GitHub sub-issue (see **Make an issue a sub-issue of a parent**). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #<map>` at the top of the child body. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
- **Blocking**: GitHub's **native issue dependencies**, the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only, the live gate). Where dependencies aren't available, fall back to a `Blocked by: #<n>, #<n>` line at the top of the child body. A ticket is unblocked when every blocker is closed.
- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins.
- **Claim**: `gh issue edit <n> --add-assignee @me`, the session's first write.
- **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer (gist + link) to the map's Decisions-so-far.

## Roadmap maintenance and closure on merge

Standing user preference: every wayfinder session adds newly identified work to its affected roadmaps, ticks completed work off, and closes completed tickets when their implementation PR merges. This is ongoing authorization for evidence-backed tracker reconciliation, not authorization to merge PRs or supply human decisions.

Each map has a `### Progress` checklist under Notes. Add `- [ ] [Ticket title](issue URL)` when creating or linking in-scope work; change it to `- [x]` when that ticket is completed. Keep partial, blocked, and pending-merge items unchecked. Include decision children and linked implementation backlogs/tasks that deliver the map's scope. This user-requested checklist overrides wayfinder's default of finding open tickets only by query; native children and dependencies still determine the frontier. Detailed answers remain in tickets, with resolution gists in Decisions so far. Leave cancelled/out-of-scope tickets out of completed progress and link their disposition in Out of scope.

1. At session start, read the relevant map and live child/dependency states. Check linked PR states for claimed tickets and recorded handoffs; reconcile completed merged work before selecting the next frontier ticket. A status audit may reconcile several previously completed tickets without resolving new decisions.
2. Before PR handoff, map each ticket's full acceptance criteria to the final change and exact-commit verification. Put `Closes #<number>` in the PR body for each fully delivered implementation ticket. Use `Refs #<number>` for partial work, parent maps/backlogs, and unresolved decisions. GitHub automatically closes linked issues when the PR merges into the default branch; a merge into a stacking branch does not complete that step.
3. A decision/prototype ticket qualifies for closure only when its human acceptance is already recorded and its question is resolved. Post a resolution comment with that evidence and remaining scope. If accepted code still awaits merge, link the resolution from the map's Notes and use a closing keyword in its PR; after merge, move the pointer to Decisions so far. Decisions without a code delivery can close on recorded resolution as usual. A code merge alone never supplies human acceptance.
4. After merge, verify linked tickets actually closed. For completed tickets missed by closing keywords, post a completion comment linking the merged PR and acceptance/verification evidence, then close as completed. Keep incomplete or acceptance-blocked tickets open with the specific remaining criteria recorded.
5. Re-read each affected map immediately before editing to preserve concurrent updates. Add newly identified in-scope work to Progress, creating a ticket when its question or acceptance criteria can be stated precisely; leave less-defined work in Not yet specified. Tick completed tickets off and add or refresh one title-linked resolution pointer per closed decision in Decisions so far; keep detailed answers in the ticket. Keep implementation completion distinct from product decisions. Remove graduated fog, retain remaining scope with its existing owner or create a precise follow-up, and check native blockers/frontier status. Close a map/backlog only when its destination/completion criteria are met.
6. Before finishing, read back ticket states and changed map sections. Report completed closures and any tracker update failures. If a session ends before merge, the PR closing links and current roadmap Notes must leave the pending state explicit.

Roadmap updates are performed through `gh` by the session doing the work or the next wayfinder reconciliation. GitHub closing keywords automate ticket closure; they do not edit map prose. Repository-wide scheduled or Actions-based map editing is not configured by this policy.
