--- name: issue-triage description: > Shallow, text-only triage of a GitHub issue on pytorch or torch-xpu-ops. Classifies the issue and returns a report (markdown table + JSON) for the caller to act on. Read-only; the skill itself does not comment on or label the issue. --- # Issue Triage — Shallow Classification & Handling Decision Text-only triage. Reads the issue title, body, and labels. Does NOT read source code, does NOT run tests, does NOT open PRs, does NOT modify the issue in any way (no comments, no labels, no body edits). Produces a single **report** returned to the caller, containing: 1. A markdown table with the classification fields. 2. A JSON summary with the same fields as structured data. The caller (a bot job, an orchestrator skill, or a human) decides what to do with the report: post it as a comment, apply labels, feed it into a larger pipeline, or just read it. `Handling` (agent-fixable vs needs-human) is derived from the other signals — see "Step 5" below. Deep root-cause analysis and any override of this decision happens later in a downstream skill (out of scope for this skill). ## Inputs - A GitHub issue: URL, number, or raw title+body+labels. If given a number or URL, fetch it: ```bash gh issue view "$N" --repo "$OWNER/$REPO" --json title,body,labels ``` - Read-only. This skill never writes to the repository — no comments, no labels, no file edits. The only side effects are the `gh issue view` read above and printing the report to stdout. ## Shell helpers Recipes below assume one helper is in scope: ```bash abort() { echo "ABORT: $*" >&2; exit 1; } ``` ## Preflight `gh` must be authenticated with read access to the target repo: ```bash gh auth status 2>&1 | grep -q "Logged in to github.com" \ || abort "gh not authenticated; run: gh auth login" ``` No write scope is required — this skill only reads. ## Step 1: Classify issue_type - **single-bug** — a single failure: test failures, runtime errors, assertion errors, incorrect output, crashes. Indicators: error tracebacks, failing test names, `RuntimeError`, `AssertionError`, "fails with", `### 🐛 Describe the bug`, test logs. - **batch-bug** — a parent issue tracking *multiple* child failures rather than describing one. Two `batch_kind`s: - `skip-list` — a "Bug Skip" tracking issue asking whether a list of already-skipped tests should still be skipped. Indicators: `Bug Skip` in the title/template, `agent_test: skip-list` label, body is a checklist of test node ids (often with `~~strike-through~~` for entries already resolved), no fresh traceback. Homogeneous — every entry is the same kind of skipped test. - `heterogeneous` — a parent/umbrella issue whose body lists *distinct* sub-bugs, each with its own reproducer, test node id, or linked child issue reference (`owner/repo#N`). Indicators: `[Umbrella]` / `[Tracking]` in the title, a checklist where each item names a *different* test/error, a "Tasks" / "Sub-issues" section of `#N` references. - **nonbug** — feature requests, tasks, performance issues, questions, discussions, enhancement proposals, feature gaps. Indicators: "Enable", "[Task]", "Consider", "Align", "feature gap", "clarification", `enhancement` label, `performance` label, no failing tests. A checklist of *work items* (things to build) is `nonbug`; a checklist of *failing tests / sub-bugs* is `batch-bug`. **Labels are authoritative** — if labels say `agent_test: skip-list`, `issue_type = batch-bug` with `batch_kind = skip-list` regardless of body content. ## Step 2: Detect `reproduction_missing` Report `yes` when the issue lacks all of: - A reproducer command (pytest node id, `python -c ...`, shell command). - A test node id reference (e.g. `test_foo.py::TestBar::test_baz`). - A minimal code snippet that triggers the failure. Report `no` when at least one of the above is present. Batch-bug issues list child test node ids / sub-bug references in their body, so they satisfy the second bullet and report `no`. ## Step 3: Estimate `scope` Based on issue text alone (no source reading): - **`pytorch`** — issue explicitly points at pytorch code (`torch/`, `aten/`, `torch/_inductor/`, `torch/_dynamo/`), a pytorch PR, or a framework-level regression. - **`torch-xpu-ops`** — issue explicitly points at torch-xpu-ops code (`src/ATen/native/xpu/`, XPU kernels, SYCL implementations), or a ported CUDA test failing on XPU due to a kernel gap. - **`both`** — issue text names changes needed in BOTH repos (e.g. pytorch API addition + XPU implementation of that API). - **`unclear`** — issue text does not specify. This is the common case for most bug reports; a downstream deep-triage skill will decide after reading source. ## Step 4: Detect `runtime_dependencies` Scan the issue body, error log, environment section, and labels for explicit mentions of external runtime dependencies. Closed set: | Value | What it means | |---|---| | `triton` | Inductor / torch.compile GPU codegen backend. | | `onednn` | Intel oneDNN library (matmul, conv, etc.). | | `onemkl` | Intel oneMKL library (BLAS, LAPACK, sparse). | | `driver` | GPU driver, level-zero, compute-runtime, `libze_intel_gpu.so`. | | `sycl` | SYCL runtime / DPC++ compiler. | | `xccl` | XCCL communication library. | Only report dependencies **explicitly named** in the issue. Do NOT infer from a stack-trace path alone (e.g. a traceback through `torch._inductor` does not by itself imply `triton` — the issue must say so or show a triton-side error). Empty array `[]` when none are named. ## Step 5: Derive `Handling` Evaluate in order; first match wins: 1. `issue_type` is `nonbug` → **needs-human** (reason: `"not a bug / task issue"`). `batch-bug` does NOT match this rule — a batch of sub-bugs is handled by the orchestrator's fan-out, per-sub-item; do not force it to needs-human here. 2. `reproduction_missing == yes` → **needs-human** (reason: `"no reproducer or test-name reference"`). 3. `runtime_dependencies` is non-empty → **needs-human** (reason: `"runtime dependency requires human triage: "`). 4. Issue explicitly requires hardware or a non-public model/dataset the agent cannot access → **needs-human** (reason: names the missing resource). 5. Otherwise → **agent-fixable**. `scope=both` and `scope=unclear` do NOT force needs-human — a downstream deep-triage skill decides the final target repo. ## Step 6: Return the report Emit both a markdown block and a JSON block to stdout, in that order, separated by a blank line. The caller reads one, both, or neither. ### 6a. Markdown block Assemble this exact structure (values from Steps 1–5). This is what a caller would paste as a comment: ```markdown ## Issue Triage | Field | Value | |-------|-------| | Issue type | single-bug / batch-bug (skip-list) / batch-bug (heterogeneous) / non-bug | | Reproduction missing | yes / no | | Scope | pytorch / torch-xpu-ops / both / unclear | | Dependencies | comma-separated list, or (none) | | Handling | agent-fixable / needs-human | **Reason:** *Automated by issue-triage.* ``` Each `Value` cell above lists the allowed choices; emit exactly one of them. Never leave a literal `|` inside a cell — it splits the cell and breaks the rendered table. Include the `` marker on the first line so a downstream caller can locate its own previous comment (if any) and update it in place. The marker is part of the report; the skill does not consume it. Omit the `**Reason:**` line entirely when `handling == agent-fixable`. For a batch issue, list the sub-items this run handles under the table, one numbered line each, numbered as in the issue body — and say in one sentence how they group (which sub-item takes the fix, which are re-checked against it): ```markdown 4. `test_foo_xpu_float8_e4m3fn` (`TestBarXPU`) -- `pytorch/pytorch#197334` 5. `test_foo_xpu_float8_e5m2` -- `pytorch/pytorch#197336` ``` ### 6b. JSON block Immediately after the markdown block (with one blank line between), emit: ```json { "issue_type": "single-bug | batch-bug | nonbug", "batch_kind": null, "reproduction_missing": true | false, "scope": "pytorch | torch-xpu-ops | both | unclear", "runtime_dependencies": [], "handling": "agent-fixable | needs-human", "reason": "", "suggested_labels": [] } ``` Field notes: - `batch_kind` is `"skip-list"` or `"heterogeneous"` when `issue_type == "batch-bug"`, and `null` otherwise. The orchestrator routes batch fan-out on it (no re-derivation needed downstream). - `reproduction_missing` is a JSON boolean: `true` for the `yes` shown in the table, `false` for `no`. - `runtime_dependencies` is an array from the closed set in Step 4; empty `[]` when none named. - `reason` is required non-empty when `handling == needs-human`, empty string when `handling == agent-fixable`. - `suggested_labels` lists the labels a caller might apply to the issue. Advisory only — the skill does not apply them. Populate per the rules below. - Do NOT invent values not derived from the issue text. ### 6c. Suggested labels `suggested_labels` is populated as follows: - If `handling == "needs-human"` → include `agent:needs-human`. - Empty array otherwise. A missing reproducer needs no label of its own: the orchestrator reports it as `SKIPPED(reproduction_missing)` and applies `agent:skipped`. Scope and dependency values live in the JSON structure, not as labels. ## HARD RULES - **Never modify the issue.** No comments, no labels, no body edits. The caller applies changes based on the report. - **Never read source or run tests.** This skill's contract is text-only shallow triage. Deep source-reading analysis belongs to a separate downstream skill. - **Emit exactly one markdown block and one JSON block to stdout,** in that order. Nothing else. No prose intro, no closing summary. The caller parses stdout; extra text corrupts the parse.