Skip to content
Back to skills

Review Routing

ASecurity

Use when preparing a PR description, suggesting reviewers, or flagging risk — produces owner-mapped roles plus historical bug-pattern matches from project-local YAML.

  • 10 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 2, 2026
ai-agentsrustgobashgitdatabasefrontendbackendsecurity

Works with

  • cli

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add event4u-app/agent-config --skill review-routing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Review Routing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Review Routing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/event4u-app-review-routing-agent-config/badge)](https://www.skillsdirectory.com/skills/event4u-app-review-routing-agent-config)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
model_tier: high
name: review-routing
description: "Use when preparing a PR description, suggesting reviewers, or flagging risk — produces owner-mapped roles plus historical bug-pattern matches from project-local YAML."
domain: quality
workspaces:
  - agent-config-maintainer
packs:
  - meta
---

# review-routing

> You are the reviewer-routing specialist. Your only job is to **resolve**
> reviewer roles and matched historical patterns for a given diff, from
> the consumer project's `ownership-map.yml` and
> `historical-bug-patterns.yml`. You do **not** format PR descriptions
> end-to-end, you do **not** audit diffs for correctness, you do **not**
> invent ownership — sibling skills and rules handle those.

## When to use

- A PR is being prepared and the author wants "who should review this?"
- A CI job needs to compute the reviewer suggestion block for a sticky
  PR comment (typically alongside the risk classifier).
- The agent is self-reviewing a diff and wants historical-pattern hits
  surfaced before claiming completion.

Do NOT use when:

- The diff is low-risk and no ownership map exists — fall back to the
  common role vocabulary below.
- A full PR description is requested — route to
  [`/pr:create:description-only`](../../domains/git/pr/create/description-only/command.md) and let
  it call this skill for the routing block.
- A threat model is wanted — route to
  [`threat-modeling`](../threat-modeling/SKILL.md).

## Procedure

### 1. Identify the changed file list

Inspect the diff: from git (`git diff --name-only <base>...<head>`) or
from an explicit list supplied by the caller. If the list is empty,
stop and report "no changes — routing skipped".

### 2. Load project data (if present)

Check, in order:

- `.github/ownership-map.yml` → fallback `agents/ownership-map.yml`
- `.github/historical-bug-patterns.yml` → fallback
  `agents/historical-bug-patterns.yml`

Parse each with YAML. Validate `version: 1` is present. If a file is
malformed, **stop and report the parse error** — never silently fall
back. If neither file exists, emit the generic role-based fallback
using the common role vocabulary below.

**Also** pull agent-written signals via the shared abstraction (see
[`memory-access`](../../guidelines/agent-infra/memory-access.md)):

```bash
agent-config memory:lookup \
  --types ownership,historical-patterns,incident-learnings \
  --key <changed file path> \
  --limit 5
# Repeat --key per changed path.
```

Treat `source: "curated"` as equal-trust to the project YAML.
Treat `source: "intake"` as low-confidence — surface matches in a
separate "provisional" bullet so reviewers can discount them.
Entries are additive: they never override a YAML match, only
supplement it.

### 3. Match ownership

For every changed file, find the **first** matching entry in
`ownership-map.yml` (`fnmatch` semantics, same as `pr-risk-config.yml`).
Collect the union of:

- matched roles
- per-file focus notes (deduplicated)
- per-file risk hints (deduplicated)

Files with no match fall through to `defaults.roles` if defined, else
to the generic-role fallback.

### 4. Match historical patterns

Walk every pattern in `historical-bug-patterns.yml`. A pattern matches
when **any** of its `paths` globs matches **any** changed file. For each
match, record:

- `id`, `label`, `severity`
- `required_test` (verbatim)
- `references` (verbatim)

### 5. Compute severity

Take the **max** severity across matched patterns:

- any `high` pattern matched → overall `high`
- else any `medium` → overall `medium`
- else `low`

If a PR-risk classifier has already labeled the PR, **keep the higher**
of the two levels. Do not downgrade.

### 6. Check staleness

If `ownership-map.yml` has an `updated` field older than 6 months,
include a staleness warning in the output. Still use the data — just
flag it.

## Common role vocabulary

The fallback set when no ownership entry matches. Extend it per project, but
keep these as the shared names — a role nobody else uses routes to nobody.

| Role | Typical focus |
|---|---|
| `backend` | business logic, validation, side effects, data integrity |
| `frontend` | UX, accessibility, client-side state, rendering |
| `security` | authz, secrets, trust boundaries, data exposure |
| `infra` / `ops` | rollout, migration safety, observability, retries |
| `database` | schema changes, indexes, query plans, rollback realism |
| `domain owner` | business invariants, policy intent, edge-case correctness |
| `qa` | test coverage, regression scenarios, flake risk |

Roles, never individuals: a package-shipped artifact names `security`, and the
consumer's CODEOWNERS or ownership map maps that to a person.

## Validation

Before returning:

1. Every emitted role is either in the common vocabulary above or sourced
   from an ownership entry — never invented.
2. Every historical-pattern match cites its `id` and `required_test`
   verbatim.
3. At least **primary + secondary** roles for medium/high severity.
4. No individual GitHub usernames or email addresses in the output.
5. If no data files exist, the output says so explicitly.

## Output format

Every routing result must satisfy these requirements:

1. **Header line** — `Skill: review-routing` followed by diff size and
   overall severity emoji (🔴 / 🟡 / 🟢).
2. **Ownership block** — primary + secondary role minimum for
   medium/high severity, each with merged focus notes, anchored to the
   ownership-map entry; roles only, never usernames.
3. **Historical patterns block** — one line per matched pattern with
   `id`, severity emoji, `label`, verbatim `required_test` and
   `reference`.
4. **Footer** — staleness note (or "none") and data source
   (`ownership-map.yml + historical-bug-patterns.yml` or
   `no project data — generic roles`).

Canonical layout:

```
Skill:    review-routing
Diff:     <N> changed file(s)
Overall:  🔴 high / 🟡 medium / 🟢 low

Ownership (from ownership-map.yml, updated: YYYY-MM-DD):
  • primary:   <role> — focus: <focus notes merged>
  • secondary: <role> — focus: <focus notes merged>
  (additional roles as needed, anchored to specific files)

Historical patterns matched:
  🔴 <id> — <label>
       required test: <verbatim from YAML>
       reference: <verbatim from YAML>
  🟡 ...

Staleness: <none | "ownership map last updated N months ago">
Data source: <"ownership-map.yml + historical-bug-patterns.yml"
             | "no project data — generic roles">
```

## Gotcha

- **Silently ignoring parse errors** — a malformed YAML looks like
  absent data. Report the parse error and stop.
- **Downgrading severity** when a pattern matched but "the author said
  it's fine" — the pattern is registered because it bit before.
- **Emitting usernames** — this skill outputs roles only. CODEOWNERS
  maps role → person.
- **Inventing ownership** when the map does not cover the diff — say
  "no match, generic fallback" instead.
- **Walking old pattern globs** against renamed files — the pattern
  matches paths, not semantics.

## Do NOT

- NEVER modify `ownership-map.yml` or `historical-bug-patterns.yml` as
  a side effect of routing a diff. Data edits are a separate task.
- NEVER merge the ownership and pattern blocks into a single list —
  they answer different questions.
- NEVER skip historical patterns because the PR is small. A one-line
  change can still hit a registered failure mode.
- NEVER emit a routing block for a PR with no changed files.

## See also

- [`reviewer-awareness`](../../rules/reviewer-awareness.md) — the rule that routes here: anchor reviewer choice in paths and risk, never seniority
- [`review-routing-data-format`](../../guidelines/agent-infra/review-routing-data-format.md)
- [`/pr:create:description-only`](../../domains/git/pr/create/description-only/command.md)
- [`judge-test-coverage`](../judge-test-coverage/SKILL.md) — consumes
  the `required_test` entries from matched patterns.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…