---
name: code-review
description: >
  Review code changes for bugs, security, performance, and quality.
  Dual-mode: interactive (local) or headless (CI).
  The review MUST be posted as a comment on the GitLab MR — the skill is NOT complete until the comment is posted (unless --local flag is set).
  Use when the user says /code-review, /review, 'review my code', 'check my changes',
  'review before push', or wants a pre-push code review.
argument-hint: "[optional: MR !IID or URL, issue #IID or URL, or specific files/focus area] [--local to skip GitLab posting]"
allowed-tools:
  - Read
  - Glob
  - Grep
  - Bash
  - Skill
hooks:
  - type: PreToolUse
    matcher: Edit
    hook: |
      echo "BLOCKED: code-review is read-only. Use /code-review-fix to apply fixes."
      exit 2
  - type: PreToolUse
    matcher: Write
    hook: |
      echo "BLOCKED: code-review is read-only. Use /code-review-fix to apply fixes."
      exit 2
---

Review the code changes on the current branch compared to the target branch.

## Required tools

- `glab`

Run `pysae-ai-tools tools require <tools>` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Step 1 : Resolve context

If `$ARGUMENTS` contains `--local`, set `LOCAL_ONLY=true` and strip it before further parsing. Local-only mode skips all GitLab interactions (no MR note, no reviewer, no approval, no label update).

1. **Run detect_context** with any refs from `$ARGUMENTS` (handles `!IID`, `#IID`, URLs automatically):
   ```bash
   CTX=$(pysae-ai-tools internal detect-context $ARGUMENTS_REFS)
   ```
   Extract: `IS_CI`, `MR_IID`, `PROJECT_ID`, `PROJECT_URL`, `MR_TARGET_BRANCH`, `MR_SOURCE_BRANCH`, `ISSUE_IID`.

2. **Checkout source branch** if an explicit MR/issue was provided and we're not already on it.

## Step 2 : Analyze the diff

1. **Set workflow label** — unless `LOCAL_ONLY`, if `ISSUE_IID` is set:
   ```bash
   pysae-ai-tools glab workflow-transition ${ISSUE_IID} "workflow::Under review"
   ```
   Skip silently if it fails. Do NOT change the label again after the review.

2. **Sync branch** — `git pull --ff-only` (skip if explicit MR/issue was provided).

3. **Get the diff** — `git diff origin/${MR_TARGET_BRANCH}...HEAD` — use the target branch from `detect_context`, never guess.

4. **Read modified files** for full context (imports, types, surrounding logic). Stay scoped to diff lines only.

5. **Diff convention**: lines with `-` prefix are **already deleted** — never suggest fixing them (only flag if deletion causes a regression). Lines with `+` are new code to review.

6. **Large diffs** (>500 lines): split the review by file to avoid quality degradation.

7. **Apply the review criteria and production impact analysis** below.

If a `CLAUDE.md` file exists at the repo root, apply those conventions too.

## Review criteria

### Critical (must fix)
- Security vulnerabilities (injection, XSS, leaked secrets, missing auth/authz)
- Bugs and logic errors
- Breaking changes without migration path
- Missing error handling on critical paths
- Race conditions in concurrent/async code
- Production performance under realistic load: per-request cost × concurrency (1000 WS, 100 req/s), crash-mid-operation consistency, unbounded queues/caches, query scaling with data growth

### Major (should fix)
- Type safety issues (untyped params, `any`, missing null checks)
- Architecture violations (wrong layer, tight coupling, bypassed abstractions)
- Performance regressions (N+1 queries, missing indexes, blocking async)
- Missing tests for new functionality

### Minor (consider fixing)
- Naming that doesn't match intent
- Functions exceeding 30 lines
- Code duplication that should be extracted

## Step 3 : Format and print the review

**Language**: French only with proper accents (é, è, ê, à, ç — including capitals É, À, Ç). Apply [french-writing-rules.md](../references/french-writing-rules.md).

**File links**: GitLab permalinks with `COMMIT_SHA=$(git rev-parse HEAD)`:
`${PROJECT_URL}/-/blob/${COMMIT_SHA}/path/to/file.ext#L<line>`

**Structure** per issue:
```
### \#<N> — <SEVERITY> — <short title>

**Fichier** : [`path/to/file.ext:<line>`](${PROJECT_URL}/-/blob/${COMMIT_SHA}/path/to/file.ext#L<line>)

**Problème** : <what's wrong and why it matters>

**Correctif** :
\`\`\`
<corrected code>
\`\`\`
```

**Numbering**: `<N>` starts at 1 and increments in the **final display order** (after severity sort: Critical > Major > Minor). Escape `#` as `\#` to prevent GitLab auto-linking. The numbering allows `/code-review-fix` to reference specific issues — e.g. `/code-review-fix exclu la #3` skips issue \#3, `/code-review-fix #4 uniquement` only fixes \#4.

**Rules**: issues only (no praise, no recap), no emojis, order by severity (Critical > Major > Minor). If nothing wrong: **"No issues found."** End with verdict: **APPROVED** / **MODIFICATIONS REQUIRED** / **BLOCKED**.

In local mode, offer to explain findings in more detail if the user asks.

## Step 4 : Post the review on the GitLab MR

**Skip entirely if `LOCAL_ONLY=true`.**

1. **Find existing note**: `pysae-ai-tools glab review-note find ${MR_IID}` → JSON or `NONE`
2. **Compose body** — if previous note exists, apply update rules below
3. **Upsert**: `echo "${BODY}" | pysae-ai-tools glab review-note upsert ${MR_IID}`
4. **Add as reviewer** (skip in CI): `pysae-ai-tools glab review-note add-reviewer ${MR_IID}`
5. **Approve if APPROVED** — **local mode only**: delegate to `/glab-mr-approve`. **Never approve in CI.**

### Note update rules

Previous issues must NEVER disappear from the note:
- **Deduplicate**: issue in both old and new → keep only in new
- **Resolved**: issue in old but not in new → move to collapsed `<details>` with fixing commit SHA from `git log`
- **Already-resolved**: carry forward from previous `<details>` as-is
- **Permalinks**: new issues use current SHA, carried-over issues keep their original SHA

```
<new review content>

<details><summary>Anciennes reviews (problèmes corrigés depuis)</summary>

### <ORIGINAL_SEVERITY> — <original title>
**Fichier**: <original text, unchanged>
**Problème**: <original text, unchanged>
**Correctif**: <original text, unchanged>
**Corrigé**: [<short_sha>](${PROJECT_URL}/-/commit/<full_sha>)

</details>

---
- *Review \#<N> — <DD/MM/YYYY HH:MM> — @<AUTHOR>*
- *Review \#<N-1> — <previous datetime> — @<previous author>*
- *...*
<!-- claude-review-meta:pass=<N> -->
```

- `<N>`: pass number (1 for first, increment on update). Extract from `<!-- claude-review-meta:pass=<N> -->`
- `<AUTHOR>`: if `$CI_JOB_URL` is set, display `[CI](${CI_JOB_URL})`; otherwise use the current GitLab username (`glab api user | jq -r '.username'`) prefixed with `@`.
- Escape `#` as `\#` to prevent GitLab auto-linking
- Date in Europe/Paris: `TZ=Europe/Paris date +"%d/%m/%Y %H:%M"`
- **History**: keep all previous `- *Review \#...*` lines from the existing note, most recent first. The new line is prepended above the old ones.
- Omit `<details>` if first review or previous had zero issues

$ARGUMENTS
