ci: add PR triage tier bot#285
Conversation
Adds a PR Triage workflow that classifies each PR into a risk tier (1-4) based on files touched, diff size, and author/branch, then labels the PR and posts an explanatory comment. Tier classification is adapted to this monorepo's package layout: core SDK packages (node-opentelemetry, browser, otel-web, session-recorder) and the release workflow are critical (Tier 4); repo config, smoke-tests, and non-release workflows are trivial (Tier 1). Classification logic is pure and unit-tested (node --test) and runs as a gating job before the classify step.
|
Greptile SummaryThis PR adds automated risk-tier classification for pull requests. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "ci: harden triage dep-bump detection and..." | Re-trigger Greptile |
🟢 Tier 1 — TrivialDocs, images, lock files, or a low-risk dependency bump (patch-level, or a minor bump of a non-OpenTelemetry dependency). No functional code changes detected. Why this tier:
Review process: Auto-merge once CI passes. No human review required. Stats
|
- pr-triage.js: collect per-PR failures and throw after the loop so a gating workflow can detect incomplete triage (bulk mode still continues past individual failures) - pr-triage.yml: use inputs.pr_number || 'bulk' as the concurrency group fallback instead of github.run_id, so concurrent bulk dispatches serialize
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || | ||
| inputs.pr_number || 'bulk' }} |
There was a problem hiding this comment.
A bulk dispatch uses the PR Triage-bulk group, while a pull-request event or targeted dispatch for PR #42 uses PR Triage-42. These runs can overlap even though both update PR #42. If a push starts the per-PR run while a bulk run is processing that PR, the bulk run can write its earlier classification last, leaving the tier label and sticky comment stale. Bulk processing and per-PR processing need coordination at the PR level.
Context Used: AGENTS.md (source)
| 1: { | ||
| emoji: '🟢', | ||
| headline: 'Tier 1 — Trivial', | ||
| detail: 'Docs, images, lock files, or a dependency bump. No functional code changes detected.', | ||
| process: 'Auto-merge once CI passes. No human review required.', | ||
| sla: 'Resolves automatically.', | ||
| }, |
There was a problem hiding this comment.
I think we need to be a bit more cautious with dependency version bumps. The OpenTelemetry SDK, for example, could potentially introduce breaking changes. If possible, I'd suggest treating any OpenTelemetry SDK version bump (major or minor) as T2. For non-OpenTelemetry dependencies, only major version bumps should be treated as T2.
Address PR #285 review feedback: - parseSemver now parses abbreviated ranges (^1, 1.x, bare major) and is anchored so non-semver targets (git URLs, npm: aliases) return null - Dependency-bump detection scopes out package metadata keys (version, name, ...), accumulates all version pairs per name so a duplicate name across blocks can't mask a risky bump, and fails closed for unparseable @opentelemetry/* bumps - Label writes are now add-then-remove with 404-tolerant removal so concurrent runs never leave a PR unlabeled or fail on an already-removed label - Corrected the staleness-guard comment to reflect that it narrows, not closes, the bulk-vs-per-PR race Adds 12 regression tests (112 total, all passing).
Adds a PR Triage workflow that auto-classifies each PR into a risk tier (1–4), labels it, and posts an explanatory comment.
Opened as a draft to test the workflow behavior before enabling it broadly.
What it does
pull_requesttomain(opened / synchronize / reopened / ready_for_review); skips drafts for the classify step.testjob runs the pure classification logic vianode --testbefore anything is labeled.classifyjob applies areview/tier-Nlabel and posts a sticky comment explaining why.Risk tiers
Every PR lands in exactly one tier. Classification is checked top-down: Tier 4 wins first, then Tier 1, then Tier 2, otherwise Tier 3. Line counts exclude test files and trivial files (docs, lock files, config).
.changeset// repo config /smoke-tests// non-release workflows /.github/scripts/).< 200prod lines and single-package and no corepackage.jsonedit and (for agent branches)< 50prod lines across≤ 3files.≥ 200prod lines, cross-package, a corepackage.jsonedit, or an agent branch that exceeds the Tier 2 size limits.node-opentelemetry,browser,otel-web,session-recorder) orrelease.yaml, or a very large diff (> 1000prod lines human /> 400agent).Agent-branch guardrail
Branches prefixed
claude/,agent/, orai/have a tighter Tier 2 ceiling (< 50lines,≤ 3files) and a lower Tier 4 escalation threshold (> 400lines vs.> 1000for humans), so machine-generated diffs always get at least one mandatory human review.Repo-specific adaptation
This feature is mainly based off HyperDX OSS , however, classification is tuned to this monorepo's layout:
node-opentelemetry,browser,otel-web,session-recorder— andrelease.yaml.smoke-tests/, and non-release workflows.package.jsonedits block Tier 2.Overriding a classification
Remove the bot-applied
review/tier-*label and apply a different one by hand. Manual overrides are detected (via the label event actor) and preserved on subsequent pushes — the bot won't re-classify a PR a human has re-tiered.Notes
GITHUB_TOKEN).pull_requestworkflow, it may not run on this PR itself — it takes effect for PRs opened after merge tomain. Use theworkflow_dispatchtrigger (with apr_number) to test against an existing PR.