process-code-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited process-code-review (Agent Skill) and scored it 91/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Constraint:
CLAUDE.md and the sibling instruction files that section lists after the branch checkout, and review against the rules they carry, not only the packaged ones.@skills/pr-summary/SKILL.md on the linked issue / JIRA ticket follows the language of the source assignment. Never mix languages inside the same comment; never use bilingual Kritické (Critical) style parentheses.@rules/laravel/laravel.mdc, @rules/laravel/architecture.mdc, @rules/laravel/filament.mdc, and @rules/laravel/livewire.mdc@rules/git/general.mdc Pull Policy, in order: resolve the default branch (DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's@^origin/@@')" — never hardcode origin/main), git fetch origin, git pull --rebase to take the PR branch's own remote first, then git rebase "origin/$DEFAULT_BRANCH" to bring the default branch in, resolve any conflicts, and git push --force-with-lease. Do not git pull again after the rebase — it would undo the sync. If the rebase changed composer.lock, run composer install immediately so dependencies match the new lockfile. If the rebase surfaces conflicts that cannot be resolved cleanly, stop and report it (the existing merge-conflict constraint).skills/code-review-github/scripts/load-issue.sh <NUMBER|URL> — the single deterministic entry point. Never call gh issue view, gh pr view, or gh api /repos/.../issues/... directly. Read review comments, files, commits, status checks, and closingIssues off the resulting JSON document. If the script is unavailable (missing tool, exit code 2/3) fall back to the GitHub MCP server, and always prefer the MCP fallback for review-thread / line-anchored comments that the script does not return.load-issue.sh returns general comments[] and reviews[] but never the line-anchored review threads nor their resolved/unresolved state. Fetch them deterministically with the GraphQL reviewThreads connection — this is not one of the forbidden REST endpoints (gh issue view, gh pr view, gh api /repos/.../issues/...): gh api graphql -f query='
query($owner:String!,$repo:String!,$number:Int!,$cursor:String){
repository(owner:$owner,name:$repo){
pullRequest(number:$number){
reviewThreads(first:100, after:$cursor){
pageInfo{ hasNextPage endCursor }
nodes{
id isResolved path line
comments(first:100){ nodes{ author{login} body url createdAt } }
}
}
}
}
}' -F owner=<owner> -F repo=<repo> -F number=<number>Do not accept a truncated list — the "every unresolved thread" guarantee depends on completeness. When reviewThreads.pageInfo.hasNextPage is true, repeat the query with -F cursor=<endCursor> until it is false; when any thread's comments.nodes reaches the page size, page that thread's comments the same way. If gh api graphql is unavailable, fall back to the GitHub MCP server for the same thread list plus its resolved state.
comments[]).reviewThreads query — add every thread where isResolved == false (human reviewer and bot) as a checklist item, and skip every thread where `isResolved == true`. Record each thread's id so it can be marked resolved once its fix lands (see Resolve addressed reviewer threads below).#### Reproducer extraction (per finding)
For every Critical and Moderate finding, extract the reproducer fields published by the CR skills (@skills/code-review/SKILL.md, @skills/code-review-github/SKILL.md, @skills/code-review-jira/SKILL.md, @skills/security-review/SKILL.md):
n/a — <reason> when the Fix narrative is sufficient)Read the reproducer fields off comments[] and body / descriptionText returned by the deterministic loader for the originating tracker instead of re-fetching the issue:
skills/code-review-github/scripts/load-issue.sh <NUMBER|URL>. Never call gh issue view, gh pr view, or gh api /repos/.../issues/... directly.skills/code-review-jira/scripts/load-issue.sh <KEY|URL>. Never call acli directly.Use these to write a failing test before applying the fix:
n/a); rerun the test until it passes.If a CR-skill finding lacks Faulty Example, Expected Behavior, or Test Hint, request a CR rerun rather than guessing. Suggested Fix may legitimately be n/a per the CR rules.
"Awaiting external input" findings are exempt from the reproducer requirement. A finding whose Suggested Fix is the literal request-for-link template from @rules/code-review/general.mdc Third-Party API & Service Documentation Verification (issue #748) step 3 has no Faulty Example / Expected Behavior / Test Hint by nature — there is no code bug to reproduce, only a missing external source. Do not request a CR rerun for it and do not attempt a code fix for it — the only remedy is the author supplying the documentation link. It still counts toward `criticalCount + moderateCount` per that rule's step 6, so it is not simply waved through: it triggers the Review loop's dedicated Awaiting-external-input short-circuit below instead of a normal fix-and-retry iteration. The request is never posted as a separate PR reply — that rule's step 3 publishes the request-for-link Suggested Fix exclusively through the CR skill's ## Findings block, and this exemption creates no second channel for it.
Free-form reviewer threads are exempt from the reproducer requirement. Unresolved threads written by human reviewers will not carry the four structured fields. Do not request a CR rerun for them and do not block. Instead, derive the intent from the comment text, apply the minimal best-effort fix that satisfies it, and add or adjust a test at your discretion (a regression test when the comment describes a behavior bug; none when it is a naming / readability / dead-code remark). Keep the change scoped strictly to what the reviewer asked for. The exemption removes only the mandatory reproducer workflow — a behavior-changing best-effort fix still has to satisfy the diff-scoped coverage gate enforced by the Review loop below (@rules/php/core-standards.mdc Testing).
While reading the affected files in preparation for the CR fixes, you may encounter problems that are unrelated to the reviewer feedback but were already present in those files. The following categories qualify:
@rules/php/core-standards.mdc, @rules/git/general.mdc, @rules/laravel/*, …) or any other rule under .claude/rules/.@rules/security/backend.md, @rules/security/frontend.md, or @rules/security/mobile.md would flag (injection, missing authn/authz, unsafe deserialization, sensitive-data exposure, …).Rules:
@rules/git/general.mdc Git Rules — the finished history must be a logical partition of the change set; when a fix round bundled two findings into one commit or attached a fix to an unrelated commit, reshape the history before pushing rather than describing the drift in the PR):@rules/git/general.mdc: fix(<scope>): pre-existing — <description> for bugs and security, refactor(<scope>): pre-existing — <description> for rule violations without behavior change.pre-existing — prefix is mandatory so reviewers can identify these commits at a glance.fix(<scope>): pre-existing — … (bug, security) — add the regression test in the same commit as the fix; the test must fail before the fix lands and pass after.refactor(<scope>): pre-existing — … (project-rule violation, behavior-preserving) — apply @rules/refactoring/general.mdc Test Coverage Contract: when the target lines are below 100% coverage, author a dedicated test(<scope>): cover <area> before pre-existing refactor commit before the refactor commit, and do not modify pre-existing tests inside the refactor commit (mechanical renames forced by the refactor itself stay exempt and must be flagged in the commit body).cr-status PR comment posted during PR update, list every pre-existing fix under a ## Pre-existing fixes heading with a one-line rationale, so reviewers can review them independently of the CR thread.cr-status comment as a deferred follow-up with the reason — the reviewer can then file a follow-up issue.#### Commit granularity — one CR item = one commit
Every checklist item built during intake — each structured CR finding and each unresolved reviewer thread — is resolved in exactly one commit of its own, and no commit carries two items. This is the CR form of the logical-partition rule in @rules/git/general.mdc Git Rules (its assignment-side counterpart is @skills/resolve-issue/references/commit-planning.md), so a reviewer opening the PR's Commits tab reads the fix history as a one-to-one map of the review points.
@rules/refactoring/general.mdc Test Coverage Contract wins, exactly as in the Pre-fix phase above — the missing coverage lands in a dedicated test(<scope>): cover <area> before refactor commit ordered before the refactor commit, which itself modifies no pre-existing test.@rules/git/general.mdc Commit Messages — fix(<scope>): … for a behavior defect, refactor(<scope>): … for a behavior-preserving cleanup, test(<scope>): … for a coverage-only finding, docs(<scope>): … for a documentation-only one. The subject names the resolved finding, never the review round — fix(auth): reject expired reset tokens, not fix: iteration 2 review fixes. Identify the item in the commit body: the finding title, or the reviewer thread's path:line and author.git commit --fixup=<sha> during the loop, git rebase --autosquash before the push — instead of adding a second commit for the same item. Never squash distinct items together to compensate. Scope — unpushed commits of the current run only. The fold applies to commits this run created and has not pushed yet. When the item's commit was already pushed by an earlier run of this skill, do not rewrite it: reviewer threads are anchored to those commits and rewriting them outdates the review. Land the correction as a new commit for that item instead, naming the item and the commit it corrects in the body. The one-item-one-commit guarantee therefore holds per run — across runs the history carries one commit per item per run, which is the honest record of what each round changed.git log --oneline "origin/$DEFAULT_BRANCH"..HEAD, autosquash the --fixup commits from step 5, and confirm that every checklist item resolved in this run has exactly one commit among the commits this run created, that each of those commits maps to exactly one item (or is a named pre-existing / coverage commit), and that none of them bundles two items. Commits an earlier run left on the branch are outside the walk (step 5 Scope) — they are read for context, never reshaped, so a second commit for an item an earlier run already pushed is the expected record, not drift. Reshape a drifted history before the push — never describe the drift in the cr-status comment instead of fixing it. This skill has two fix-carrying push paths and both are bound by this step: Finalization on a converged loop, and the Review loop's Awaiting-external-input short-circuit, which pushes the fix commits already applied in that run before publishing its own cr-status. The intake git push --force-with-lease that publishes the rebase in Before processing a PR carries no fix commit and is exempt. A branch that reaches the remote still carrying literal fixup! … subjects violates this section and @rules/git/general.mdc Commit Messages.@skills/code-review/SKILL.md). Do not gate on the full-suite coverage percentage during a CR / review loop iteration.php artisan migrateThis is a blocking loop. Do not advance to Finalization, PR update, or Completion until the loop converges. The final report (technical and non-technical) is published only once, after convergence.
iteration = 1 and maxIterations = 3 — three review rounds is the hard cap, not a soft target. A loop that has not converged in three rounds is not converging by iterating: the residual findings need a human decision, and further rounds only re-spend tokens on the same diff. The cap pairs with the late-iteration report scope below — the third and final round reports Critical and Moderate findings only.@skills/code-review-github/SKILL.md@skills/code-review-jira/SKILL.mdThe invocation must include the explicit quiet-mode instruction (see Quiet review runs below) and the current `iteration = <n>` value, so the wrapper can apply the late-iteration report scope (see Late-iteration report scope below). The review run must not publish to the PR or to the issue tracker during loop iterations — capture findings in memory only. Each iteration's CR wrapper runs its Reviewer Comment Fulfillment Gate (canonically defined in @skills/code-review-github/SKILL.md), so the review reloads every reviewer comment / thread and re-verifies that the fixes applied in the previous iteration actually satisfy each reviewer instruction.
criticalCount and moderateCount in the latest review, and read the reviewer comments: M/N fulfilled verdict the wrapper records. Let unfulfilledCount = N − M (the reviewer instructions still not satisfied and not rejected-with-reason). Each not-fulfilled instruction is already raised by the gate as a Critical finding, so it is included in criticalCount — unfulfilledCount is tracked separately only to make the convergence condition and the loop report explicit.criticalCount + moderateCount == 0 and unfulfilledCount == 0 → converged, exit the loop. The run may not converge while any reviewer comment is still not fulfilled (the change does not yet correspond to what the reviewer asked for) — fulfilling every loaded reviewer instruction is a first-class convergence condition alongside the zero-Critical / zero-Moderate gate.@rules/code-review/general.mdc Third-Party API & Service Documentation Verification (issue #748) step 3. When that is the case, the loop has not converged (the finding still counts toward criticalCount + moderateCount per that rule's step 6), but no further iteration can resolve it — resolving it requires a human to supply the documentation link. Do not advance to step 6 and do not run another iteration: stop the loop immediately in a dedicated Blocked: awaiting external input terminal state. Before publishing, commit and push any fix commits already applied earlier in this run — the short-circuit stops before Finalization, so this is the only point in this terminal state where "Commit and push changes" still happens; a cr-status describing a state that never reached the remote is a defect. That push is bound by Commit granularity — one CR item = one commit exactly like Finalization's: run its step 6 reconciliation (autosquash the loop's --fixup commits, one commit per item) before pushing. As the narrow exception to the PR update convergence precondition below, publish a cr-status comment reporting the current (non-zero) criticalCount + moderateCount under a ## Awaiting external input heading naming each request-for-link finding by title and linking to the CR comment that carries it, then stop — do not render the resolved-items report, do not resolve reviewer threads, and do not run Promote the PR out of Draft; the PR stays a Draft and the non-zero count keeps @skills/merge-github-pr/SKILL.md from merging it. Escalate the same request to the user/caller in the completion report. A later run re-enters this loop at iteration 1 once the author has supplied the link, at which point the rule's Gate step re-verifies against the new source.iteration, and go back to step 2.iteration > maxIterations and the loop still has not converged, stop and surface the remaining findings to the user — do not push or publish a partial report. The user must triage the residual findings manually before any final report goes out.#### Quiet review runs (during the loop)
code-review-github and code-review-jira honour the suppression: no PR comment, no JIRA comment, no linked-issue summary is posted while the loop is still iterating.criticalCount + moderateCount == 0) is the only iteration whose output is published — that publication is performed by the PR update + Completion steps below, not by the review skill itself.#### Late-iteration report scope (CR iteration > 2)
iteration value into every CR wrapper invocation (iteration = <n>). From iteration > 2 the wrapper reports Critical and Moderate findings only — Minor findings, the Refactoring (DRY / tech debt) section, and the Refactoring proposals section are dropped from the report, in-memory and published alike. Canonical contract: @rules/code-review/general.mdc Late-Iteration Report Scope — Critical & Moderate Only (CR iteration > 2).criticalCount + moderateCount and unfulfilledCount over exactly the findings that gate convergence, so the convergence condition is unaffected.Report scope: header line and the real, unchanged Counts numbers. Do not re-run the review unfiltered just to restore the dropped sections.build.xml/phing.xml; fall back to Composer scripts in composer.json)Precondition: the Review loop above must have exited with criticalCount + moderateCount == 0. If the loop hit maxIterations without converging, do not proceed — return the remaining findings to the user for manual triage instead.
@skills/test-like-human/SKILL.md. The user-perspective testing skill runs on demand only — leave it for the user to trigger via /test-like-human after the PR is updated.git log --oneline "origin/$DEFAULT_BRANCH"..HEAD) before the push, autosquash any --fixup commits the loop produced, and reshape a drifted history rather than pushing itgh pr create --draft) per Draft pull requests; the Promote the PR out of Draft step below marks it ready once this converged run is published@rules/git/general.mdc)@rules/reports/general.mdc)Precondition: same as Finalization — convergence required. The sole exception is the Awaiting-external-input short-circuit in the Review loop above, which publishes its own narrow cr-status post (non-zero counts, no Draft promotion) and skips every other step in this section — it never treats that publish as satisfying this precondition for the full PR update.
cr-status marker namespace. On GitHub, the marker makes the status comment identifiable as a status post (separate from the cr-comment namespace); on JIRA the helper ignores the marker argument, so cr-status and cr-comment posts are distinguished by content only (resolved-items body vs. ## Pre-existing fixes section vs. CR findings). Concretely:skills/code-review-github/scripts/upsert-comment.sh <PR-NUMBER|URL> - cr-status (body on stdin). The helper appends <!-- cr-status:actor=<gh-login> --> to the body for traceability and POSTs a new comment on every run — it never PATCHes a prior status comment. Action (created) is logged on stderr; include it in the in-conversation completion report.skills/code-review-jira/scripts/upsert-comment.sh <KEY|URL> - cr-status. The helper POSTs a new comment on every run — it never edits a prior status comment in place. Fall back to the JIRA MCP server's addCommentToJiraIssue on exit code 2/3.cr-comment namespace) stays untouched by this skill.## Pre-existing fixes section in the cr-status body listing each commit subject (fix/refactor(<scope>): pre-existing — …) with a one-line rationale derived from the commit body, so reviewers can review the pre-existing fixes independently of the CR thread. Omit the section entirely when no pre-existing fix landed (consistent with the always-omit-empty-section convention).#### Resolve addressed reviewer threads (GitHub)
After the fixes are committed and pushed (Finalization above), mark every reviewer review thread whose finding was actually fixed as resolved, using the thread id captured during intake:
gh api graphql -f query='mutation($threadId:ID!){ resolveReviewThread(input:{threadId:$threadId}){ thread{ isResolved } } }' -F threadId=<thread-id>cr-status report instead of resolving it.gh api graphql is unavailable, fall back to the GitHub MCP server's resolve-review-thread operation.#### Promote the PR out of Draft (GitHub)
Convergence is exactly the moment the PR becomes ready to merge, so this skill owns the Draft → ready transition per @rules/git/general.mdc Draft pull requests:
criticalCount + moderateCount == 0), mark the PR ready for review now: gh pr ready <PR-NUMBER|URL>. This is the same class of GitHub PR state change as resolving a review thread, not a code change.maxIterations without converging, the PR stays a Draft — never promote a PR that still carries Critical / Moderate findings.gh pr ready is idempotent. If gh pr ready is unavailable, fall back to the GitHub MCP server's mark-ready operation.#### Per-item justification (required)
Every resolved review point in the PR comment must include a brief justification using this format:
- [x] {short finding title}
- **Why:** {what was wrong / what the reviewer asked for}
- **Reason:** {root cause or rule that was violated}
- **Solution:** {what was changed and why this is the best fit}
- **Commit:** {short SHA} — {commit subject}Rules:
Precondition: Review loop has converged (criticalCount + moderateCount == 0).
@skills/code-review-github/SKILL.md@skills/code-review-jira/SKILL.md@skills/record-project-memory/SKILL.md with the converged CR context and the PR link. It appends to docs/memory/PROJECT_MEMORY.md only the lessons that clear the promotion bar in @rules/compound-engineering/general.mdc Compound Memory (per project) (a recurring CR finding is the canonical input); a CR that surfaced nothing durable records nothing.M/N fulfilled verdict) — every actionable reviewer instruction satisfied, or rejected/deferred with its recorded reason~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.