This repository is used to validate the Watchflow /risk and /reviewers slash commands against the configured rules.
| # | Rule | Severity |
|---|---|---|
| 1 | PRs must reference a linked issue (e.g. Fixes #123) |
🟠 High |
| 2 | When a PR modifies CODEOWNERS paths, those owners must be added as reviewers | 🟠 High |
| 3 | All review comment threads must be resolved before merge | 🟠 High |
| 4 | PR total lines changed must not exceed 500 lines | 🟡 Medium |
| 5 | PR titles must follow a pattern (feat:, fix:, docs:, etc.) and description must be ≥ 50 chars |
🟡 Medium |
| 6 | Source code changes must include a CHANGELOG or .changeset update |
🟡 Medium |
| 7 | PR description must accurately reflect the actual code changes in the diff | 🟡 Medium |
All 7 rules are behavioural (no file-path patterns). Risk scoring for
/riskuses PR size and contributor signals (see table below).
| Signal | Points | Trigger condition |
|---|---|---|
| Watchflow rule match | severity pts (capped at 10) | Rules with file-path patterns match changed files |
| Large changeset | +3 | > 50 files changed |
| Moderate changeset | +1 | 21–50 files changed |
| Many lines changed | +2 | > 2 000 lines added/removed |
| Significant lines changed | +1 | 501–2 000 lines added/removed |
| No test coverage | +2 | Source files (.py, .js, .ts, .go, etc.) changed without any test file |
| First-time contributor | +2 | PR author association is NONE, FIRST_TIME_CONTRIBUTOR, or FIRST_TIMER |
| Revert PR | +2 | PR title starts with Revert |
Risk thresholds: 🟢 Low ≤ 3 | 🟡 Medium 4–6 | 🟠 High 7–10 | 🔴 Critical > 10
- Install Watchflow GitHub App on this repo.
- Set CODEOWNERS: open
.github/CODEOWNERSand replace placeholder usernames with your actual GitHub accounts. Add a second collaborator for load-balancing tests. - Watchflow must be running (or deployed) and connected to this repo via webhook.
- All slash commands (
/risk,/reviewers) are posted as PR comments.
Goal: Verify /risk reports Low (score ≤ 3).
PR to create:
- Branch from
main, edit onlyREADME.md(1–5 lines) - Title:
docs: update README - Description (≥ 50 chars +
Fixes #1):Update README to add setup instructions. Fixes #1 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Risk: Low (score 0)
- No rule signals (no path-based rules in this repo)
- No size signals (tiny PR, 2 files)
- Label
watchflow:risk-lowapplied
Goal: Verify /risk reports Medium (score 4–6) from size signals.
PR to create:
- Branch from
main, create 21–50 new JS files undersrc/utils/(e.g.util_01.js…util_30.js, each ~25 lines = ~750 LOC total) - Title:
feat: add utility modules - Description (≥ 50 chars +
Fixes #2):Adds a set of utility modules used across the application. Fixes #2 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Risk: Medium (score 4 = +1 moderate changeset + +1 significant LOC + +2 no test coverage)
- Signals:
Moderate changeset(+1),Significant lines changed(+1),No test coverage(+2) - Label
watchflow:risk-mediumapplied
Goal: Verify /risk reports High (score 7–10) from extreme size signals.
PR to create:
- Branch from
main, create 51+ new JS files undersrc/generated/(e.g.gen_01.js…gen_55.js, each ~45 lines = ~2 475 LOC total) - Do NOT add any test file
- Title:
feat: add generated modules - Description (≥ 50 chars +
Fixes #3):Adds generated modules for the application layer. Fixes #3 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Risk: High (score 7 = +3 large changeset + +2 many lines + +2 no test coverage)
- Signals:
Large changeset(+3),Many lines changed(+2),No test coverage(+2) - Label
watchflow:risk-highapplied
Goal: Verify No test coverage (+2 pts) fires when source code is added without test files.
PR to create:
- Branch from
main, addsrc/payments/refund.js(new JS file, any content) - Do NOT add any file matching
testorspecpattern - Title:
feat: add refund module - Description (≥ 50 chars +
Fixes #4):Adds refund functionality to the payments module. Fixes #4 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Signal:
No test coverage(+2 pts) - Overall risk depends on PR size (likely Low to Medium)
Goal: Verify Large changeset (+3 pts) fires when > 50 files are changed.
PR to create:
- Branch from
main, create 51+ tiny files (e.g.src/stubs/stub_01.js…stub_51.js, each 1 line) - Title:
chore: add stubs - Description (≥ 50 chars +
Fixes #5):Adds stub files for upcoming module development. Fixes #5 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Signal:
Large changeset(+3 pts, "N files changed") - Risk at least Medium
Goal: Verify Many lines changed (+2 pts) fires when > 2 000 lines are added/removed.
PR to create:
- Branch from
main, add a single large file (e.g.src/data/large_dataset.json) with 2 001+ lines - Title:
feat: add data file - Description (≥ 50 chars +
Fixes #6):Adds a large static data file used by the analytics module. Fixes #6 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Signal:
Many lines changed(+2 pts)
Goal: Verify First-time contributor (+2 pts) fires when the PR author is new to the repo.
Setup: Use a brand-new GitHub account that has never contributed to this repo.
PR: Any small change (e.g. edit README.md), conventional title, proper description with issue link, include CHANGELOG.md.
Comment on PR:
/risk
Expected response:
- Signal:
First-time contributor(+2 pts, "@username is a new contributor")
Goal: Verify Revert PR (+2 pts) fires when the PR title starts with Revert.
PR to create:
- Branch from
main, revert any recent commit - Title: must start with
Revert(e.g.Revert: feat: add utility modules) - Description (≥ 50 chars + issue link):
Reverts the utility modules added in the previous PR. Fixes #8 - Include
CHANGELOG.mdupdate
Comment on PR:
/risk
Expected response:
- Signal:
Revert PR(+2 pts, "This PR reverts previous changes")
Goal: Verify CODEOWNERS owners are recommended first.
Setup: Ensure .github/CODEOWNERS has at least one path mapped to a real GitHub user.
PR to create: Change a file covered by CODEOWNERS. Proper title + description + issue link + CHANGELOG.
Comment on PR:
/reviewers
Expected response:
- CODEOWNERS owner appears as recommended reviewer
- Reason mentions: CODEOWNERS or code ownership
- Label
watchflow:reviewer-recommendationapplied - Reviewer actually assigned to the PR
Goal: Verify commit history is used when no CODEOWNERS exists.
Setup: Temporarily remove or empty .github/CODEOWNERS. Ensure the repo has prior commits by different contributors.
PR to create: Edit any source file (e.g. src/index.js).
Comment on PR:
/reviewers
Expected response:
- Reviewer recommended based on commit history
- Reason mentions recent commits to the changed file
- Top committer for that file is recommended
Cleanup: Restore CODEOWNERS.
Goal: Verify the PR author never appears in the recommended reviewer list.
Setup: The PR author must have prior commits in the changed files (would normally score as a candidate).
PR to create: Any PR where the author has commit history on changed files.
Comment on PR:
/reviewers
Expected response:
- PR author login does NOT appear in the recommended or assigned list
Goal: Verify that a low-risk PR gets exactly 1 reviewer.
PR to create: Same setup as TC-01 (tiny README change, correct title, issue link, CHANGELOG updated).
Comment on PR:
/reviewers
Expected response:
- Risk: Low
- Exactly 1 reviewer assigned
- Response shows 1 ranked entry
Goal: Verify that a high-risk PR gets 2–3 reviewers.
Setup: Ensure CODEOWNERS has at least 2 individual users mapped to paths being changed.
PR to create: Same setup as TC-03 (51+ files, 2 000+ LOC, no tests).
Comment on PR:
/reviewers
Expected response:
- Risk: High
- 2–3 reviewers assigned
Goal: Verify a reviewer with many recent reviews is ranked lower.
Setup:
- Have contributor A review 5+ recent PRs in this repo
- Have contributor B with fewer reviews
- Both are CODEOWNERS or top committers for the changed files
PR to create: Edit any file both contributors own.
Comment on PR:
/reviewers
Expected response:
- Overloaded reviewer's reason includes:
Load penalty: N recent reviews (heavy queue) - Lower-loaded reviewer ranked higher
Goal: Verify a reviewer with ≥ 80% approval rate gets +2 pts boost.
Setup:
- Contributor A approves several PRs (builds high approval rate)
- Contributor B leaves mostly "Request changes" reviews
PR to create: Any file both contributors are candidates for.
Comment on PR:
/reviewers
Expected response:
- Contributor A's reason includes:
High review acceptance rate (N%)
Goal: Verify the second /reviewers within 30 seconds is silently ignored.
Steps:
- Comment
/reviewerson any open PR → wait for Watchflow response - Immediately comment
/reviewersagain (within 30 seconds)
Expected:
- First command: full response posted
- Second command: no response (silently ignored)
Goal: Verify /reviewers --force re-runs even within the 30-second window.
Steps:
- Comment
/reviewers→ wait for response - Immediately comment
/reviewers --force
Expected:
- First command: full response
- Second command with
--force: another full response posted
Goal: Verify /risk has a separate 30-second cooldown.
Steps:
- Comment
/risk→ wait for response - Immediately comment
/riskagain
Expected:
- First
/risk: response posted - Second
/risk(within 30 s): silently ignored
Goal: Verify the correct risk label is applied based on score.
Steps: Run /risk on PRs of different sizes (TC-01, TC-02, TC-03).
Expected labels:
- Low risk →
watchflow:risk-low - Medium risk →
watchflow:risk-medium - High risk →
watchflow:risk-high
Goal: Verify watchflow:reviewer-recommendation label is applied.
Steps: Run /reviewers on any open PR.
Expected: PR has both watchflow:risk-{level} AND watchflow:reviewer-recommendation labels.
Goal: Verify recommended reviewers are actually assigned to the PR.
Steps: Run /reviewers on a PR where the reviewer is not yet assigned.
Expected:
- PR's Reviewers sidebar shows the recommended user(s)
- Reviewer receives a GitHub notification
Goal: Verify .watchflow/expertise.json is committed to the repo after a /reviewers run.
Steps:
- Delete
.watchflow/expertise.jsonif it exists - Run
/reviewerson any PR
Expected:
- A new commit appears on the base branch adding
.watchflow/expertise.json - File contains
contributorsmap with file paths and commit counts
Goal: Verify /reviewers uses historical expertise from expertise.json on subsequent runs.
Steps:
- Run
/reviewerson a PR (createsexpertise.json) - Open a new PR touching the same files
- Run
/reviewerson the new PR
Expected:
- Reviewer reason includes:
Historical expertise in N changed file(s)
Run /risk on any PR and verify the comment contains:
- Heading:
🛡️ Watchflow: Risk Assessment - Risk level emoji (🟢 Low / 🟡 Medium / 🟠 High / 🔴 Critical) + score number
- List of risk signals with label, description, and points
Run /reviewers on any PR and verify the comment contains:
👥 Watchflow: Reviewer Recommendation
**Risk:** <emoji> <Level> (<N> files changed)
**Recommended:**
1. @username — one-sentence reason
**Summary:** one-line LLM-generated summary
<details>
<summary>Risk signals considered</summary>
- **Signal label**: description
</details>
| Test Case | What to change | Expected risk |
|---|---|---|
| TC-01, TC-12 | README.md + CHANGELOG.md only | 🟢 Low |
| TC-02 | 21–50 JS files, ~750 LOC, no tests | 🟡 Medium |
| TC-03, TC-13 | 51+ files, 2 000+ LOC, no tests | 🟠 High |
| TC-04 | 1 source file, no test file | Low+ (no test signal) |
| TC-05 | 51+ tiny files | Medium+ (file count signal) |
| TC-06 | 1 file, 2 001+ lines | Medium+ (LOC signal) |
| TC-07 | Any (brand-new account) | Low+ (contributor signal) |
| TC-08 | Any, title starts Revert |
Low+ (revert signal) |
| TC-09 | File covered by CODEOWNERS | Any |
| TC-14, TC-15 | Any (load/acceptance setup required) | Any |