blob: 3946dc05b5004fbfccbc0c778edfad3888d24c06 [file] [view]
# Issue and PR labels
The Label workflow classifies the issue or PR that triggered it using Cloudflare
Workers AI (`@cf/qwen/qwen3-30b-a3b-fp8`). It runs when an issue or PR is opened,
edited or reopened, and when a PR receives new commits. It processes open items
only. There is no scheduled scan or historical backfill.
## Assignment policy
| Labels | Issues | PRs | Assignment |
| --- | --- | --- | --- |
| `bug`, `enhancement`, `documentation`, `research`, `release` | Yes | No | AI chooses one type; it may abstain when none applies. |
| `releases-note/feat`, `releases-note/fix`, `releases-note/refactor`, `releases-note/docs`, `releases-note/ci`, `releases-note/build`, `releases-note/chore` | No | Yes | AI chooses one release-note category. |
| `core`, `website`, `services/*`, `bindings/*`, `integrations/*` | Yes | Yes | AI selects directly affected components from the repository catalog. |
| `breaking-changes` | No | Yes | AI may add it for an explicit incompatible API or behavior change. |
| `size:*` | No | Yes | The script calculates changed lines. |
The category follows the substantive purpose. For example, a docstring-only
fix belongs to `releases-note/docs`, a routine dependency upgrade to
`releases-note/build`, and a package compilation regression to
`releases-note/fix`. The title prefix is evidence rather than an override.
Performance optimizations without new public functionality belong to
`releases-note/refactor`.
`research` covers technical investigations and unresolved design questions.
`release` covers release tracking issues. A usage question that does not fit a
type can receive component labels without a type.
Existing type/category labels are preserved, including maintainer corrections.
Component labels and `breaking-changes` are additive; the workflow does not
remove them when subsequent edits change the scope. Maintainers can correct
these labels. Size labels are recalculated on PR events and replace prior size
labels.
Maintainers control `lgtm`, `run-with-secrets`, `release-blocker`,
`good first issue`, `good first vibe`, and `help wanted`. The model cannot select
them. Language labels, `dependencies`, and `github_actions` remain under the
existing Dependabot/manual workflow and are preserved.
## Component catalog
`scripts/label.py` derives services from the generated service inventory in
`website/data/services.json`, and bindings/integrations from their repository
directories. Layers and HTTP transports use `core`.
Existing naming conventions are retained: service names use underscores in
labels, and the `hf` service uses `services/huggingface`. New component labels
are created when catalog inputs change on `main`. Synchronization only creates
missing labels; it does not rename, delete or overwrite existing labels.
The classifier never creates labels from model-generated names.
## Size labels
The size is additions plus deletions from GitHub's PR file list:
| Label | Changed lines |
| --- | --- |
| `size:XS` | 0–9 |
| `size:S` | 10–29 |
| `size:M` | 30–99 |
| `size:L` | 100–499 |
| `size:XL` | 500–999 |
| `size:XXL` | 1,000 or more |
The calculation excludes `*.lock`, `pnpm-lock.yaml`, `package-lock.json`,
`DEPENDENCIES.*`, `services.json`, and `generated.js`. Other generated files
still count; binary changes have the line counts reported by GitHub.
## Setup and operation
Configure these repository Actions settings before enabling classification:
- Variable `CLOUDFLARE_ACCOUNT_ID`: the account that provides Workers AI.
- Secret `CLOUDFLARE_API_TOKEN`: a token scoped to that account with Workers AI
inference permission. Follow the Cloudflare
[REST API setup](https://developers.cloudflare.com/workers-ai/get-started/rest-api/).
GitHub's workflow token receives `issues: write` and `pull-requests: write` for
label assignment, and `contents: read` for the trusted checkout. Fork PRs use
`pull_request_target`; the workflow always checks out the default branch and
never executes the PR's code. Titles, bodies and diff excerpts are sent to the
model as data. Model output is validated locally against separate issue/PR
categories and the component catalog before any label write.
The request contains at most 10,000 body characters and 6,000 characters of diff
excerpts, plus the file list. Classification is approximate; large diffs are not
fully analyzed. The workflow checks the current title, body and PR head again
before applying its result and skips a result if the item changed during
inference. These reads are not an atomic lock against concurrent edits.
Requests retry HTTP 429 and transient server errors up to three attempts.
Missing credentials, quota exhaustion, truncated output and invalid labels
fail the job without applying a classification. After fixing the cause, rerun
the failed job. Logs contain proposed label changes and model token/Neuron
usage. They do not publish model-generated explanations as comments.
Run local contract tests with:
```shell
python3 -m unittest discover -s scripts -p test_label.py
```
With `GH_TOKEN` and `GITHUB_REPOSITORY` configured, synchronize definitions with
`python3 scripts/label.py sync`. To inspect one saved Actions event, also set
`GITHUB_EVENT_PATH` and the Cloudflare credentials, then run
`python3 scripts/label.py event`. This defaults to a dry run; `--apply` writes
the selected labels. Neither command enumerates historical issues or PRs.