Skip to content

GitHub Code Review - System automatycznego review

Przegląd

System działa w dwóch trybach dla procesu code review na GitHub:

MODE A: REVIEW (system recenzuje czyjś kod)
┌─────────────────────────────────────────────┐
│ n8n wykrywa: User przypisany jako reviewer │
│               na PR                         │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Ustawia start_commands: github-review       │
│ mode=review                                 │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ System:                                     │
│ 1. Pobiera PR (branch, diff, files)        │
│ 2. Pobiera kontekst (issue, comments)      │
│ 3. Analizuje kod (quality, logic, tests)   │
│ 4. Generuje review comments (konstruktywne)│
│ 5. Publikuje w GitHub                      │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Author odpowiada na komentarze              │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ n8n wykrywa odpowiedź → trigger iteracji    │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ System:                                     │
│ 1. Czyta odpowiedzi authora                │
│ 2. Weryfikuje zmiany w kodzie              │
│ 3. DECYZJA:                                │
│    • Akceptuje → Approve PR                │
│    • Kontynuuje dyskusję → Reply           │
│    • Request changes → Kolejne uwagi       │
└─────────────────────────────────────────────┘


MODE B: RESPOND (system odpowiada na review swojego kodu)
┌─────────────────────────────────────────────┐
│ n8n wykrywa: Nowy review comment            │
│              na PR systemu                  │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Ustawia start_commands: github-review       │
│ mode=respond                                │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ System:                                     │
│ 1. Pobiera review comments                 │
│ 2. Analizuje każdą uwagę                   │
│ 3. DECYZJA dla każdej uwagi:               │
│    • Zasadna → Wprowadź zmiany w kodzie    │
│    • Dyskusyjna → Wyjaśnij reasoning       │
│    • Niejasna → Poproś o wyjaśnienie       │
│ 4. Commit zmian (jeśli konieczne)          │
│ 5. Reply na wszystkie komentarze           │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Reviewer weryfikuje odpowiedzi/zmiany      │
└─────────────────────────────────────────────┘

┌─────────────────────────────────────────────┐
│ Proces powtarza się do:                    │
│ • PR Approved                              │
│ • Changes requested (max iteracji)         │
└─────────────────────────────────────────────┘

Workflow n8n

Trigger 1: User przypisany jako reviewer (MODE A: REVIEW)

Gdy: GitHub webhook: pull_request.review_requested gdzie assignee to system bot

Warunek:

  • Reviewer to bot user (np. code-gen-bot)
  • PR nie jest draft
  • PR jest do review

Akcje n8n:

  1. Utwórz task w systemie (jeśli nie istnieje)

    json
    {
      "task_id": "REVIEW-{PR_NUMBER}",
      "title": "Code Review: {PR_TITLE}",
      "issue": {
        "id": "PR-{REPO}-{NUMBER}",
        "url": "{PR_URL}",
        "author_id": "{PR_AUTHOR}",
        "assignee_id": "code-gen-bot"
      },
      "repositories": [{
        "folder": "{REPO_NAME}",
        "git_url": "{REPO_GIT_URL}",
        "target_branch": "{BASE_BRANCH}",
        "working_branch": "{HEAD_BRANCH}",
        "merge_request_id": "{PR_NUMBER}",
        "merge_request_url": "{PR_URL}"
      }]
    }
  2. Ustaw start_commands dla MODE A: REVIEW

    json
    {
      "ai": {
        "start_commands": [
          {
            "id": "init_workspace",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/init_workspace.sh",
            "dependencies": []
          },
          {
            "id": "github_pr_fetch",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/github_pr_fetch.sh \"{PR_URL}\" \"/task/.spec/github\"",
            "dependencies": ["init_workspace"]
          },
          {
            "id": "github_review_perform",
            "catalog": "START",
            "executor": "claude",
            "command": "/plugin-codegen:github-review /task --mode=review --iteration=1",
            "dependencies": ["github_pr_fetch"]
          }
        ]
      },
      "github_review": {
        "mode": "review",
        "iteration": 1,
        "pr_number": 123,
        "pr_url": "...",
        "status": "in_progress",
        "last_review_id": null
      }
    }
  3. Przenieś task do TODO (system go podejmie)

  4. Powiadomienie Mattermost:

    📝 Code Review: PR #{NUMBER} - {TITLE}
    Reviewer: @code-gen-bot
    Author: @{AUTHOR}
    Branch: {HEAD} → {BASE}

Trigger 2: Author odpowiedział na review (MODE A: ITERACJA)

Gdy: GitHub webhook: pull_request_review_comment where:

  • Comment jest odpowiedzią na review comment systemu
  • PR w którym system jest reviewerem

Akcje n8n:

  1. Odczytaj task.json

  2. Sprawdź status review

    javascript
    if (task_json.github_review.mode === "review" &&
        task_json.github_review.status === "awaiting_author") {
      // Przejdź do kolejnej iteracji
    }
  3. Zwiększ iteration counter

    json
    {
      "github_review": {
        "mode": "review",
        "iteration": 2,
        "status": "review_iteration",
        "last_review_id": "...",
        "last_comment_id": "..."
      }
    }
  4. Zmień start_commands na iterację

    json
    {
      "ai": {
        "start_commands": [
          {
            "id": "init_workspace",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/init_workspace.sh",
            "dependencies": []
          },
          {
            "id": "github_pr_refresh",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/github_pr_fetch.sh \"{PR_URL}\" \"/task/.spec/github\" --refresh",
            "dependencies": ["init_workspace"]
          },
          {
            "id": "github_review_iterate",
            "catalog": "START",
            "executor": "claude",
            "command": "/plugin-codegen:github-review /task --mode=review --iteration=2",
            "dependencies": ["github_pr_refresh"]
          }
        ]
      }
    }
  5. Przenieś task do TODO (wznów review)

  6. Powiadomienie:

    💬 Code Review PR #{NUMBER} - Author odpowiedział
    Wznowienie review (iteracja 2)

Trigger 3: Nowy review comment na PR systemu (MODE B: RESPOND)

Gdy: GitHub webhook: pull_request_review lub pull_request_review_comment where:

  • PR stworzony przez system (branch: claude/{TASK_ID})
  • Review od innego usera (nie bota)

Akcje n8n:

  1. Znajdź task dla tego PR (przez merge_request_url w task.json)

  2. Ustaw start_commands dla MODE B: RESPOND

    json
    {
      "ai": {
        "start_commands": [
          {
            "id": "init_workspace",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/init_workspace.sh",
            "dependencies": []
          },
          {
            "id": "github_pr_fetch_own",
            "catalog": "START",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/github_pr_fetch.sh \"{PR_URL}\" \"/task/.spec/github\" --own",
            "dependencies": ["init_workspace"]
          },
          {
            "id": "github_review_respond",
            "catalog": "START",
            "executor": "claude",
            "command": "/plugin-codegen:github-review /task --mode=respond --iteration=1",
            "dependencies": ["github_pr_fetch_own"]
          },
          {
            "id": "github_push_changes",
            "catalog": "END",
            "executor": "bash",
            "command": "bash /workspace/files/helpers/github_push_changes.sh",
            "dependencies": ["github_review_respond"]
          }
        ]
      },
      "github_review": {
        "mode": "respond",
        "iteration": 1,
        "pr_number": 456,
        "pr_url": "...",
        "status": "responding",
        "reviewer_id": "{REVIEWER}",
        "last_review_id": "..."
      }
    }
  3. Przenieś task do TODO (jeśli był done - reactive)

  4. Powiadomienie:

    📬 Review otrzymany na PR #{NUMBER}
    Reviewer: @{REVIEWER}
    Comments: {COUNT}
    System przygotowuje odpowiedź...

Trigger 4: PR zaakceptowany (COMPLETION)

Gdy: GitHub webhook: pull_request_review where:

  • Review state: approved
  • PR systemu lub PR gdzie system jest reviewerem

Akcje n8n:

  1. Update task.json

    json
    {
      "github_review": {
        "status": "approved",
        "approved_at": "2026-01-06T10:00:00Z",
        "approved_by": "{APPROVER}"
      }
    }
  2. Powiadomienie:

    ✅ PR #{NUMBER} zaakceptowany!
    Approver: @{APPROVER}
  3. Jeśli MODE A (system recenzował):

    • Zamknij task → done
  4. Jeśli MODE B (system odpowiadał):

    • Merge PR (jeśli auto-merge enabled)
    • Zamknij task → done

Komenda Claude: /github-review

Parametry

/plugin-codegen:github-review <task_path> --mode=review|respond --iteration=N

Mode: review (system recenzuje)

Przepływ:

markdown
1. READ GitHub PR context:
   - /task/.spec/github/PR_CONTEXT.md (opis PR, linked issues)
   - /task/.spec/github/pr_diff.patch (pełny diff)
   - /task/.spec/github/files_changed.json (lista zmienionych plików)
   - /task/.spec/github/review_comments.json (istniejące komentarze)

2. CHECKOUT branch:
   - git fetch origin {head_branch}
   - git checkout {head_branch}

3. ANALIZA KODU (per file):
   For each file in files_changed:
     a) READ file content (current state)
     b) READ diff for this file
     c) ANALYZE:
        - Code quality (naming, structure, complexity)
        - Logic correctness (bugs, edge cases)
        - Best practices (patterns, anti-patterns)
        - Tests coverage (czy są testy dla zmian)
        - Security (SQL injection, XSS, etc.)
        - Performance (N+1, memory leaks, etc.)
     d) GENERATE review comments (inline + general)

4. FILTRUJ komentarze:
   - Tylko konstruktywne uwagi
   - Konkretne sugestie (nie ogólniki)
   - Przykłady kodu (jeśli możliwe)
   - Priorytet: 🔴 Critical | 🟡 Important | 🟢 Nice-to-have

5. ZAPISZ review:
   - /task/.spec/github/REVIEW_iteration_{N}.md
   - Format: GitHub review markdown

6. PUBLIKUJ review (przez webhook):
   - Event: `github_review_generated`
   - Payload: review comments + decision

7. DECYZJA:
   - Jeśli CRITICAL issues → REQUEST_CHANGES
   - Jeśli tylko IMPORTANT → COMMENT (nie blokuj)
   - Jeśli tylko NICE-TO-HAVE lub brak → APPROVE

Struktura REVIEW_{iteration}.md:

markdown
# Code Review - Iteration {N}

## 📊 Summary

- **Files reviewed:** 5
- **Lines changed:** +234 / -156
- **Comments:** 12 (🔴 2 critical, 🟡 5 important, 🟢 5 nice-to-have)
- **Decision:** REQUEST_CHANGES / COMMENT / APPROVE

## 🔴 Critical Issues (must fix)

### src/app/services/user.service.ts:45
**Issue:** SQL Injection vulnerability
```typescript
// Current (VULNERABLE)
const query = `SELECT * FROM users WHERE id = ${userId}`;

// Suggested fix
const query = `SELECT * FROM users WHERE id = ?`;
db.query(query, [userId]);

Reasoning: Direct string interpolation allows SQL injection. Use parameterized queries.

src/app/components/login/login.component.ts:120

Issue: Password stored in plain text

typescript
// Current (INSECURE)
localStorage.setItem('password', password);

// Suggested fix
// Don't store passwords client-side at all
// Use token-based authentication

Reasoning: Security best practice - never store passwords on client.

🟡 Important Issues (should fix)

src/app/services/api.service.ts:78

Issue: Missing error handling

typescript
// Current
async getData() {
  const response = await fetch(url);
  return response.json();
}

// Suggested
async getData() {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return response.json();
  } catch (error) {
    console.error('API error:', error);
    throw error;
  }
}

Reasoning: Unhandled network errors will crash the app.

🟢 Nice-to-have (optional improvements)

src/app/components/navbar/navbar.component.ts:23

Suggestion: Extract magic number to constant

typescript
// Current
if (items.length > 10) { ... }

// Suggested
private readonly MAX_ITEMS = 10;
if (items.length > this.MAX_ITEMS) { ... }

Reasoning: Improves maintainability and readability.

✅ Positive Observations

  • Good test coverage for user service (85%)
  • Clean component structure
  • Proper use of TypeScript types
  • Consistent code style

📝 General Comments

  1. Tests missing: No tests for login component - please add
  2. Documentation: Consider adding JSDoc for public methods
  3. Performance: Consider lazy loading for heavy modules

🎯 Next Steps

  1. Fix critical issues (SQL injection, password storage)
  2. Address important issues (error handling)
  3. Add tests for login component
  4. (Optional) Apply nice-to-have suggestions

Review by: @code-gen-bot Date: 2026-01-06 10:00:00 Iteration: 1


**Webhook payload:**

```json
{
  "event": "github_review_generated",
  "mode": "review",
  "iteration": 1,
  "pr": {
    "number": 123,
    "url": "...",
    "author": "developer123",
    "branch": "feature/user-login"
  },
  "review": {
    "decision": "REQUEST_CHANGES",
    "files_reviewed": 5,
    "lines_changed": {
      "additions": 234,
      "deletions": 156
    },
    "comments": {
      "total": 12,
      "critical": 2,
      "important": 5,
      "nice_to_have": 5
    },
    "critical_issues": [
      {
        "file": "src/app/services/user.service.ts",
        "line": 45,
        "issue": "SQL Injection vulnerability",
        "severity": "critical"
      },
      {
        "file": "src/app/components/login/login.component.ts",
        "line": 120,
        "issue": "Password stored in plain text",
        "severity": "critical"
      }
    ]
  },
  "actions_requested": {
    "github": {
      "create_review": true,
      "review_state": "REQUEST_CHANGES",
      "review_body": "...",
      "inline_comments": [
        {
          "path": "src/app/services/user.service.ts",
          "line": 45,
          "body": "🔴 **SQL Injection vulnerability**\n\n..."
        }
      ]
    },
    "mattermost": {
      "send_notification": true,
      "message": "📝 Review completed for PR #123\n🔴 2 critical issues found\n🟡 5 important issues\nDecision: REQUEST_CHANGES"
    }
  }
}

Mode: respond (system odpowiada na review)

Przepływ:

markdown
1. READ review comments:
   - /task/.spec/github/review_comments.json (wszystkie comments)
   - /task/.spec/github/last_review_id.txt (ostatni przetworzony review)

2. FILTER nowe comments:
   - Gdzie comment_id > last_review_id
   - Group by file + line

3. For each comment:

   a) READ kontekst:
      - Plik którego dotyczy
      - Linia kodu
      - Thread (jeśli jest odpowiedź)

   b) ANALIZA uwagi:
      - Czy zasadna? (logic check)
      - Czy dotyczy security/performance/correctness?
      - Czy to preferencja stylowa?

   c) DECYZJA:

      IF zasadna (bug/security/logic issue):
        → FIX code
        → Git commit
        → Reply: "✅ Fixed. {explanation}"

      ELSE IF warto rozważyć (performance/best practice):
        → EVALUATE: czy improvement znaczący?
        → IF tak:
          → FIX code
          → Reply: "✅ Good point, applied. {explanation}"
        → ELSE:
          → Reply: "🤔 {reasoning why not applied}"

      ELSE IF preferencja stylowa (minor):
        → IF easy to apply:
          → FIX code
          → Reply: "✅ Updated"
        → ELSE:
          → Reply: "📝 {explanation of current approach}"

      ELSE IF niejasna:
        → Reply: "❓ Could you clarify? {specific question}"

4. COMMIT changes (jeśli były):
   - Group related fixes
   - Descriptive commit message
   - Reference review comments

5. PUSH changes:
   - git push origin {head_branch}

6. PUBLIKUJ replies (przez webhook):
   - Event: `github_review_responded`
   - Payload: replies + commits

7. UPDATE status:
   - Mark all comments as addressed

Przykład odpowiedzi:

markdown
### Response to @reviewer on user.service.ts:45

**Fixed - SQL Injection vulnerability**

You're absolutely right, this was a critical security issue. Changed to parameterized query:

\`\`\`typescript
const query = `SELECT * FROM users WHERE id = ?`;
const result = await db.query(query, [userId]);
\`\`\`

Commit: `abc123f`

---

### Response to @reviewer on api.service.ts:78

**Good point - Added error handling**

Added try-catch with proper error logging and re-throw:

\`\`\`typescript
async getData() {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    return response.json();
  } catch (error) {
    this.logger.error('API error:', error);
    throw error;
  }
}
\`\`\`

Also added unit tests for error scenarios.

Commit: `def456a`

---

### Response to @reviewer on navbar.component.ts:23

🤔 **Regarding magic number extraction**

While I agree constants are generally better, in this specific case the value `10` is:
1. Used only once in the codebase
2. Directly related to UI constraint (visible items)
3. Likely to change based on design (not business logic)

Current approach keeps it co-located with the UI logic. If we need to reuse this value elsewhere, I'll extract it then. What do you think?

---

### Response to @reviewer on login.component.ts (tests)

**Added tests for login component**

Added comprehensive test suite:
- ✅ Successful login flow
- ✅ Failed login (wrong credentials)
- ✅ Network error handling
- ✅ Form validation

Coverage: 92%

Commit: `ghi789b`

Webhook payload:

json
{
  "event": "github_review_responded",
  "mode": "respond",
  "iteration": 1,
  "pr": {
    "number": 456,
    "url": "...",
    "reviewer": "tech-lead"
  },
  "response": {
    "comments_addressed": 8,
    "commits_made": 3,
    "fixes_applied": 5,
    "discussions_opened": 1
  },
  "commits": [
    {
      "sha": "abc123f",
      "message": "fix: Use parameterized queries to prevent SQL injection",
      "files_changed": ["src/app/services/user.service.ts"]
    },
    {
      "sha": "def456a",
      "message": "feat: Add comprehensive error handling to API service",
      "files_changed": ["src/app/services/api.service.ts"]
    },
    {
      "sha": "ghi789b",
      "message": "test: Add test suite for login component (92% coverage)",
      "files_changed": [
        "src/app/components/login/login.component.spec.ts"
      ]
    }
  ],
  "actions_requested": {
    "github": {
      "reply_to_comments": true,
      "replies": [
        {
          "comment_id": "12345",
          "body": "✅ **Fixed - SQL Injection vulnerability**\n\n..."
        }
      ]
    },
    "mattermost": {
      "send_notification": true,
      "message": "📬 Responded to review on PR #456\n✅ 5 fixes applied\n💬 1 discussion opened\n📝 3 commits pushed"
    }
  }
}

Skrypty Bash

1. github_pr_fetch.sh

Lokalizacja: docker/{worker}/files/helpers/github_pr_fetch.sh

Użycie:

bash
bash github_pr_fetch.sh <PR_URL> <OUTPUT_DIR> [--refresh|--own]

Co robi:

bash
#!/bin/bash
# github_pr_fetch.sh - Pobiera pełny kontekst PR z GitHub

set -e

PR_URL="$1"
OUTPUT_DIR="$2"
MODE="${3:-}"  # --refresh, --own, lub empty

# Parse PR URL
# https://github.com/owner/repo/pull/123
REPO_OWNER=$(echo "$PR_URL" | cut -d'/' -f4)
REPO_NAME=$(echo "$PR_URL" | cut -d'/' -f5)
PR_NUMBER=$(echo "$PR_URL" | cut -d'/' -f7)

echo "📥 Fetching PR #$PR_NUMBER from $REPO_OWNER/$REPO_NAME"

mkdir -p "$OUTPUT_DIR"

# 1. Get PR metadata (gh CLI)
gh pr view "$PR_NUMBER" \
  --repo "$REPO_OWNER/$REPO_NAME" \
  --json number,title,body,state,author,headRefName,baseRefName,commits,files,reviews,comments \
  > "$OUTPUT_DIR/pr_metadata.json"

# 2. Get PR diff
gh pr diff "$PR_NUMBER" \
  --repo "$REPO_OWNER/$REPO_NAME" \
  > "$OUTPUT_DIR/pr_diff.patch"

# 3. Get files changed
gh pr view "$PR_NUMBER" \
  --repo "$REPO_OWNER/$REPO_NAME" \
  --json files \
  | jq '.files' > "$OUTPUT_DIR/files_changed.json"

# 4. Get review comments
gh api "/repos/$REPO_OWNER/$REPO_NAME/pulls/$PR_NUMBER/comments" \
  > "$OUTPUT_DIR/review_comments.json"

# 5. Get reviews
gh api "/repos/$REPO_OWNER/$REPO_NAME/pulls/$PR_NUMBER/reviews" \
  > "$OUTPUT_DIR/reviews.json"

# 6. Generate PR_CONTEXT.md (markdown summary)
cat > "$OUTPUT_DIR/PR_CONTEXT.md" <<EOF
# Pull Request Context

## PR Information

- **Number:** #$PR_NUMBER
- **Title:** $(jq -r '.title' "$OUTPUT_DIR/pr_metadata.json")
- **Author:** $(jq -r '.author.login' "$OUTPUT_DIR/pr_metadata.json")
- **State:** $(jq -r '.state' "$OUTPUT_DIR/pr_metadata.json")
- **Branch:** $(jq -r '.headRefName' "$OUTPUT_DIR/pr_metadata.json") → $(jq -r '.baseRefName' "$OUTPUT_DIR/pr_metadata.json")
- **URL:** $PR_URL

## Description

$(jq -r '.body' "$OUTPUT_DIR/pr_metadata.json")

## Changes Summary

- **Commits:** $(jq '.commits | length' "$OUTPUT_DIR/pr_metadata.json")
- **Files Changed:** $(jq '.files | length' "$OUTPUT_DIR/pr_metadata.json")

## Files Changed

$(jq -r '.files[] | "- \(.path) (+\(.additions) / -\(.deletions))"' "$OUTPUT_DIR/pr_metadata.json")

## Existing Reviews

$(jq -r '.[] | "- @\(.user.login): \(.state) (\(.submitted_at))"' "$OUTPUT_DIR/reviews.json")

## Review Comments

$(jq -r '.[] | "- @\(.user.login) on \(.path):\(.line): \(.body | split("\n") | join(" "))"' "$OUTPUT_DIR/review_comments.json")

EOF

echo "✅ PR context saved to $OUTPUT_DIR"

2. send_review_webhook.sh

Lokalizacja: docker/{worker}/files/helpers/send_review_webhook.sh

Użycie:

bash
bash send_review_webhook.sh <EVENT_TYPE> <PAYLOAD_FILE>

Event types:

  • github_review_generated - System wygenerował review
  • github_review_responded - System odpowiedział na review

Logika decyzyjna Claude

Review Mode - Kiedy APPROVE vs REQUEST_CHANGES?

python
def decide_review_action(review_comments):
    """
    Decyduje czy zaakceptować PR czy prosić o zmiany
    """

    critical_count = count_by_severity(review_comments, 'critical')
    important_count = count_by_severity(review_comments, 'important')

    # Critical issues = zawsze REQUEST_CHANGES
    if critical_count > 0:
        return "REQUEST_CHANGES", f"{critical_count} critical issues must be fixed"

    # Dużo important issues = REQUEST_CHANGES
    if important_count >= 5:
        return "REQUEST_CHANGES", f"{important_count} important issues should be addressed"

    # Kilka important = COMMENT (nie blokuj ale zaznacz)
    if important_count > 0:
        return "COMMENT", f"{important_count} suggestions for improvement"

    # Tylko nice-to-have lub brak issues = APPROVE
    return "APPROVE", "Code looks good!"


def classify_issue_severity(issue_type, impact):
    """
    Klasyfikuje severity uwagi
    """

    CRITICAL = [
        'security_vulnerability',
        'data_loss_risk',
        'crash_inducing_bug',
        'breaking_change_unintentional'
    ]

    IMPORTANT = [
        'logic_error',
        'missing_error_handling',
        'performance_issue',
        'missing_tests_for_critical_path',
        'race_condition',
        'memory_leak'
    ]

    NICE_TO_HAVE = [
        'code_style',
        'naming_convention',
        'missing_comments',
        'code_duplication_minor',
        'performance_micro_optimization'
    ]

    if issue_type in CRITICAL:
        return 'critical'
    elif issue_type in IMPORTANT:
        return 'important'
    else:
        return 'nice_to_have'

Respond Mode - Kiedy FIX vs DISCUSS?

python
def decide_response_action(review_comment, code_context):
    """
    Decyduje jak odpowiedzieć na review comment
    """

    issue_type = classify_comment_type(review_comment)

    # Security/Correctness = zawsze fix
    if issue_type in ['security', 'correctness', 'bug']:
        return "FIX", "Critical issue, fixing immediately"

    # Performance = evaluate impact
    if issue_type == 'performance':
        impact = estimate_performance_impact(review_comment, code_context)
        if impact > 10:  # > 10% improvement
            return "FIX", f"Significant improvement ({impact}%), applying"
        else:
            return "DISCUSS", f"Minor impact ({impact}%), current approach is acceptable"

    # Best practice = evaluate effort vs benefit
    if issue_type == 'best_practice':
        effort = estimate_implementation_effort(review_comment)
        benefit = estimate_benefit(review_comment)

        if benefit / effort > 2:  # ROI > 2
            return "FIX", "Good suggestion, low effort high benefit"
        else:
            return "DISCUSS", "Trade-off explanation"

    # Style preference = evaluate consistency
    if issue_type == 'style':
        is_project_standard = check_project_coding_standards(review_comment)
        if is_project_standard:
            return "FIX", "Aligning with project standards"
        else:
            return "DISCUSS", "Current style is intentional"

    # Unclear comment = ask for clarification
    if is_unclear(review_comment):
        return "ASK", "Could you provide more context?"

    return "ACKNOWLEDGE", "Noted for future reference"

Format komentarzy review

Zasady konstruktywnego review:

  1. Konkretne, nie ogólnikowe ❌ "This code is bad" ✅ "This function has O(n²) complexity. Consider using a Map for O(1) lookups"

  2. Z przykładem rozwiązania ❌ "Fix the error handling" ✅ "Add try-catch:\ntypescript\ntry { ... } catch (e) { ... }\n"

  3. Z wyjaśnieniem "dlaczego" ❌ "Use const instead of let" ✅ "Use const to prevent accidental reassignment and signal immutability"

  4. Priorytet jasno oznaczony 🔴 Critical (must fix) 🟡 Important (should fix) 🟢 Nice-to-have (optional)

  5. Pozytywne feedback też

    • ✅ "Good test coverage"
    • ✅ "Clean separation of concerns"
    • ✅ "Excellent error messages"

Przykład: Pełny proces review

Scenariusz: System recenzuje PR (MODE A)

1. Developer tworzy PR #123

Title: Add user authentication
Branch: feature/user-auth → main
Files: 8 changed (+450 / -120)

2. Developer przypisuje @code-gen-bot jako reviewer

3. n8n wykrywa → tworzy task + ustawia start_commands (mode=review)

4. System wykonuje review:

bash
init_workspace

github_pr_fetch (pobiera PR context, diff, files)

github-review --mode=review --iteration=1
  ├─ Checkout branch feature/user-auth
  ├─ Analiza każdego pliku:
  ├─ user.service.ts SQL injection (🔴)
  ├─ login.component.ts Password storage (🔴)
  ├─ api.service.ts Missing error handling (🟡)
  ├─ auth.guard.ts Missing tests (🟡)
  └─ navbar.component.ts Magic number (🟢)
  ├─ Generuje REVIEW_1.md
  └─ Wysyła webhook

5. n8n publikuje review w GitHub:

Decision: REQUEST_CHANGES
🔴 2 critical issues
🟡 3 important issues
🟢 2 nice-to-have

6. Developer poprawia critical issues i odpowiada:

@code-gen-bot Fixed SQL injection and password storage.
Also added error handling. Tests will be in separate PR.

7. n8n wykrywa odpowiedź → trigger iteracji 2

8. System wykonuje review iteration 2:

bash
github_pr_refresh (pobiera nowe zmiany + komentarze)

github-review --mode=review --iteration=2
  ├─ Czyta poprzedni REVIEW_1.md
  ├─ Czyta nowe commits
  ├─ Weryfikuje fixes:
  ├─ SQL injection Fixed (parameterized query)
  ├─ Password storage Fixed (removed)
  └─ Error handling Fixed (try-catch added)
  ├─ Sprawdza tests ⚠️ Still missing
  ├─ DECYZJA:
  - Critical: 0
  - Important: 1 (missing tests)
  - Decision: COMMENT (nie blokuj)
  └─ Wysyła webhook

9. n8n publikuje review iteration 2:

Decision: COMMENT
✅ Critical issues fixed - great job!
🟡 Tests still missing but not blocking
Suggested: Add tests before merge

10. Developer:

@code-gen-bot Agreed, will add tests. Can you approve so we can merge after tests?

11. System wykonuje iteration 3:

bash
DECYZJA:
- Critical: 0
- Important: 0 (tests będą dodane)
- Decision: APPROVE

12. n8n publikuje approval:

✅ APPROVED
All issues addressed. PR ready to merge after tests are added.

Scenariusz: Developer recenzuje kod systemu (MODE B)

1. System tworzy PR #456 (po zakończeniu implementacji taska)

Title: feat(admin): Change admin bar color to dark blue
Branch: claude/DEV-1_10 → master
Files: 3 changed (+25 / -8)

2. Tech lead robi review:

markdown
Comment 1 on container.component.scss:12:
🔴 Don't hardcode colors. Use design tokens from _colors.scss

Comment 2 on container.component.ts:45:
🟡 Consider adding a service for admin bar configuration

Comment 3 on container.component.spec.ts:
🔴 Missing tests for super admin role verification

3. n8n wykrywa review → ustawia start_commands (mode=respond)

4. System odpowiada na review:

bash
github_pr_fetch_own (pobiera review comments)

github-review --mode=respond --iteration=1
  ├─ Czyta review_comments.json
  ├─ Dla każdego comment:

  Comment 1 (hardcoded colors):
  ├─ ANALIZA: Security? No. Correctness? No. Best practice? YES
  ├─ DECYZJA: FIX (design tokens = standard)
  ├─ ZMIANA: Dodaj $admin-bar-color do _colors.scss
  ├─ ZMIANA: Użyj tokena w component.scss
  └─ COMMIT: "refactor: Use design token for admin bar color"

  Comment 2 (service):
  ├─ ANALIZA: Over-engineering? Probably (single use case)
  ├─ DECYZJA: DISCUSS
  └─ REPLY: "Current approach is simpler. Service would add
  │               unnecessary abstraction for single config value.
  │               Happy to refactor if we add more admin bar features."

  Comment 3 (missing tests):
  ├─ ANALIZA: Critical? YES (security verification)
  ├─ DECYZJA: FIX
  ├─ ZMIANA: Dodaj testy dla isSuperAdmin flow
  └─ COMMIT: "test: Add tests for super admin role verification"

  └─ Wysyła webhook

github_push_changes (push commits)

5. n8n publikuje replies + commits:

markdown
✅ Fixed - Using design token
Commit: abc123f

🤔 Regarding service extraction
[reasoning...]

✅ Added tests for super admin role
Commit: def456a
Coverage: 92%

6. Tech lead weryfikuje:

@code-gen-bot Good reasoning on the service. Approved! ✅

7. System merge PR (auto-merge if enabled)

Zasady konstruktywnej dyskusji

Dla systemu recenzującego (MODE A):

  1. Nie lej wody: ❌ "This is interesting approach but I think maybe we could consider..." ✅ "Use Map instead of nested loops (O(n²) → O(n))"

  2. Konkretne przykłady: ❌ "Refactor this" ✅ "Extract to helper:\ntypescript\nfunction validateEmail(email) { ... }\n"

  3. Priorytet zawsze:

    • 🔴 Must fix (security, bugs, data loss)
    • 🟡 Should fix (performance, maintainability)
    • 🟢 Nice-to-have (style, naming)
  4. Doceniaj dobre rzeczy:

    • Zawsze znajdź min. 1 pozytywny feedback
    • ✅ "Excellent test coverage"
    • ✅ "Clean separation of concerns"

Dla systemu odpowiadającego (MODE B):

  1. Szybko przyznaj rację gdy zasadne: ✅ "You're absolutely right. Fixed in commit abc123"

  2. Wyjaśniaj reasoning gdy nie zgadzasz się: ✅ "Current approach is simpler because [konkretny powód]"

  3. Nie dyskutuj o preferencjach: ❌ "I prefer this style" ✅ "Aligned with project coding standards (see CONTRIBUTING.md)"

  4. Poproś o wyjaśnienie gdy niejasne: ✅ "Could you clarify what you mean by 'better structure'?"

Max iteracji:

  • Review mode: 3 iteracje

    • Po 3: Automatyczny APPROVE z note: "Remaining items are minor"
  • Respond mode: 2 iteracje

    • Po 2: Final response: "Addressed all major concerns. Open to further discussion in next PR if needed."

FAQ

Q: Co jeśli system i human reviewer się nie zgadzają? A: System zawsze ustępuje human reviewer po 2 iteracjach dyskusji.

Q: Jak system radzi sobie z subiektywnym feedback (np. "to brzydko wygląda")? A: Prosi o konkretny, obiektywny feedback: "Could you specify what makes it unclear? Happy to improve readability."

Q: Co jeśli review dotyczy designu a nie kodu? A: System odpowiada: "Design decisions should be discussed in the issue. This PR implements the agreed spec."

Q: Czy system może merge'ować bez human approval? A: Tylko jeśli PR ma label auto-merge-allowed. Domyślnie wymaga human approval.

Q: Co jeśli system zrobi błąd w review? A: Human może override review. System uczy się z feedback (future: ML feedback loop).