--- name: pr-quality-all version: 1.0.0 description: Run all six PR quality axes (security, QA, analyst, architect, DevOps, roadmap) against your working changes and merge their verdicts into one. Use when you say `run all the quality gates`, `pr-quality all`, or `full pre-push review`. Do NOT use to run one axis on its own (use pr-quality-security or its sibling for that axis), and do NOT use as the pre-merge gate (use review). license: MIT allowed-tools: Bash(git:*), Skill argument-hint: base-branch user-invocable: true metadata: routing: role: conditional-adjunct invoker: pr-comment-responder trigger: pr-comment-responder redirects local quality gates before a push here user-facing: true --- # PR Quality Gate: All Axes Run all six quality axes against your working changes, then merge their verdicts into one answer about whether this branch is safe to push. Migrated from the pr-quality/all command under ADR-064, which makes skills the single user-invocable surface and renames the namespaced sub-command pr-quality/all to pr-quality-all. The command file is gone, so its path is named here in plain text rather than as a citation to something a reader could open. ## Triggers `run all the quality gates`, `pr-quality all`, `full pre-push review`, `run every review axis` ## Arguments Base branch: $ARGUMENTS If `$ARGUMENTS` names a branch, forward it to every axis. Otherwise default to `main`. The base is forwarded verbatim so all six judge the same diff. ## Process 1. Run `git branch --show-current` to name the current branch. 2. Resolve the base branch from `$ARGUMENTS`, defaulting to `main`. Reject an empty value or one starting with `-` (Git parses a leading dash as an option, not a ref), then resolve it to a commit with `BASE_SHA=$(git rev-parse --verify --quiet "^{commit}")`. An unresolved or rejected ref is a hard stop: report it and do not fall back to an empty diff. Use `$BASE_SHA` for every base-dependent command below and when forwarding to the axes: the branch can move between this step and the last axis call, and the SHA cannot. 3. Count changed files: tracked (`git diff "$BASE_SHA" --name-only`) plus untracked (`git ls-files --others --exclude-standard`). If the combined count is zero, emit PASS and stop; there is nothing for any axis to read. A tracked-only count misses a change set that is entirely new files. 4. Invoke each axis through the `Skill` tool, forwarding `$BASE_SHA` in place of the original branch-name argument: `pr-quality-security`, `pr-quality-qa`, `pr-quality-analyst`, `pr-quality-architect`, `pr-quality-devops`, `pr-quality-roadmap`. Each axis re-resolves what it is given with its own `git rev-parse --verify --quiet`; forwarding the SHA makes that a no-op instead of a second, later resolution of a name that may have moved. 5. Parse each axis's `VERDICT: TOKEN` line. An axis that crashed or returned no parseable verdict is UNKNOWN, never PASS. 6. Merge the six tokens with the table below, then emit the summary. ## Verdict Aggregation Canonical: `.claude/lib/ai_review_common/verdict.py:merge_verdicts`. - ANY `CRITICAL_FAIL`, `REJECTED`, `FAIL`, `NEEDS_REVIEW`, or `NON_COMPLIANT` -> Final: **CRITICAL_FAIL** - ANY `WARN` or `PARTIAL` (no critical failures) -> Final: **WARN** - ANY `UNKNOWN` (no critical, no warn) -> Final: **UNKNOWN** - ALL `PASS` or `COMPLIANT` -> Final: **PASS** - Empty input -> Final: **UNKNOWN** UNKNOWN downgrades a would-be PASS so a missing or crashed axis cannot silently produce a green verdict. Real WARN and CRITICAL_FAIL findings override UNKNOWN. ## Output Summary Generate the consolidated report in EXACTLY this format. Do not add preambles or explanations before the table: | Agent | Verdict | Status | Key Findings | |-------|---------|--------|--------------| | Security | [verdict] | [emoji] | [summary] | | QA | [verdict] | [emoji] | [summary] | | Analyst | [verdict] | [emoji] | [summary] | | Architect | [verdict] | [emoji] | [summary] | | DevOps | [verdict] | [emoji] | [summary] | | Roadmap | [verdict] | [emoji] | [summary] | **FINAL VERDICT**: [PASS|WARN|UNKNOWN|CRITICAL_FAIL] Emoji mapping, canonical at `.claude/lib/ai_review_common/issue_triage.py:get_verdict_emoji`: PASS and COMPLIANT are a check mark, WARN and PARTIAL a warning sign, CRITICAL_FAIL / REJECTED / FAIL / NEEDS_REVIEW / NON_COMPLIANT a cross mark, and UNKNOWN a question mark. **Next Steps**: - **PASS**: Safe to commit and push - **WARN**: Review findings, address if time permits, safe to push - **UNKNOWN**: At least one axis failed to evaluate (skill crashed, no parseable verdict). Investigate which axis and re-run; do NOT treat as PASS. - **CRITICAL_FAIL**: Fix blocking issues before pushing ## Verification - [ ] All six axes ran, or each absent one is reported UNKNOWN by name - [ ] Every axis received the same resolved base commit (`$BASE_SHA`), not the branch name - [ ] The base ref was rejected if empty or leading-dash, and resolved to `$BASE_SHA` before any `git diff` - [ ] The empty-change check counted untracked files, not only the tracked diff - [ ] The final verdict follows the merge table, not a judgement call - [ ] No axis returning UNKNOWN was rolled up into PASS - [ ] The table is the first thing emitted, with no preamble - [ ] Each row's findings cite a file, or say the axis found nothing ## Anti-Patterns | Avoid | Why | Instead | |-------|-----|---------| | Stopping after the first CRITICAL_FAIL axis | The author gets one finding per round instead of the whole list, which is the iteration paradox this gate exists to avoid | Run all six, then merge | | Rolling UNKNOWN up into PASS | A crashed axis then reads as a clean one, so the gate is green exactly when it measured least | Let UNKNOWN downgrade, and name the axis that failed | | Re-deriving the merge rules here | Two copies of a table drift, and the copy in a prompt drifts first | Follow the canonical merge function; this page quotes it | | Running the axes on different bases | Six verdicts about six diffs do not merge into one answer | Resolve the base to a commit once and forward that SHA, not the branch name | | Treating this as the pre-merge gate | It reads working changes, not the PR; `review` is the gate `ship` checks | Run this before pushing, and `review` before shipping | ## Standing Decision The seven `pr-quality-*` skills (this one and the six axis skills) are kept as a standalone surface. Issue #5067 asked whether to delete them, merge them into `/review`, or keep them. The decision is keep, recorded 2026-09-29. Rationale: - The repository owner's KEEP rule for skills and agents (epic #5456, comment of 2026-09-11) holds while a skill exists. Removing a command family breaks muscle memory and external docs that name it, and the owner reverted an earlier full removal for that reason (issue #5067, comment of 2026-09-04). - The cost the issue targeted is gone. No workflow runs the review axes against a diff: PR #5132 deleted `ai-pr-quality-gate.yml`. Keeping the seven skills adds no CI compute. - `pr-comment-responder` routes to this skill (see `metadata.routing`), and it is the one-verdict, pre-push view. `/review` stays the pre-merge gate and writes the marker that `/ship` validates. Revisit only if the owner rescinds the KEEP rule for these skills. The per-check audit of `pre_pr_sequence.py` against `pr-validation.yml` lives in `docs/WORKFLOW-VALIDATION.md`. ## Extension Points - **A seventh axis.** Add its `pr-quality-` skill, then add one row here and one line to step 4. The merge table is unchanged: it is token-based, not axis-count-based. - **Different merge policy.** The rules live in `verdict.py`. Change them there and every consumer moves together. - **Machine consumption.** Each axis emits schema-bound JSON alongside its verdict, so a downstream reader parses those rather than this table.