040-discovery · git:20260822.79aa398 · 2026-08-22 · sha256 70eca8fa890380f8

040-discovery git:20260822.79aa398A

Immutable. This exact content is served forever at /api/v1/blob/70eca8fa890380f8.

---
description: "When the user types /discovery or requests quality analysis, code audit, or issue detection"
globs: ""
alwaysApply: false
---

# Discovery — Quality Analysis & Issue Detection

Systematic quality discovery that runs modular probes adapted to the project's tech stack, presents findings interactively, and creates VCS issues for confirmed problems.

## Invocation

- **Standalone** (`/discovery [scope]`): Full flow with interactive triage (Phases 0-5 + Phase 6 stats)
- **Embedded** (from session-end when `discovery-on-close: true`): Phases 0-3 only, returns structured JSON to caller

Scope accepts: `all` (default), `code`, `infra`, `ui`, `arch`, `session`, `audit`, `vault`, `feature`, or comma-separated like `code,session`.

## Phase 0: Read Session Config

Read Session Config from CLAUDE.md. Parse discovery-specific fields:
- `discovery-probes`, `discovery-exclude-paths`, `discovery-severity-threshold`, `discovery-confidence-threshold`, `discovery-on-close`

## Phase 1: Stack Detection

Detect the project's tech stack via marker file checks (Glob):

| Marker File(s) | Activates |
|----------------|-----------|
| `package.json` | JS/TS probes |
| `tsconfig.json` | TypeScript probes |
| `requirements.txt` / `pyproject.toml` | Python probes |
| `Dockerfile` / `docker-compose.yml` | Container probes |
| `.github/workflows/` | GitHub CI probes |
| `.gitlab-ci.yml` | GitLab CI probes |
| `next.config.*` / `nuxt.config.*` | SSR probes |
| `tailwind.config.*` | Tailwind probes |
| `.orchestrator/` exists | Session probes |

Build activation set: start with marker-matched probes → intersect `discovery-probes` config (if set) → restrict to scope argument (if passed).

Default exclude paths (always apply): `node_modules/`, `.git/`, `dist/`, `build/`, `.next/`, `.nuxt/`, `coverage/`. Add paths from `discovery-exclude-paths`.

Report: "Discovery: [N] probes active across [categories]. Stack: [detected]. Threshold: [severity]."

## Phase 2: Probe Execution

Run probes **sequentially** — Cursor has no parallel agents. One category at a time. Complete each category's analysis before moving to the next.

### 6 Probe Categories

**Code probes** (any project with source files):
- `hardcoded-values`, `orphaned-annotations`, `dead-code`, `ai-slop`, `type-safety-gaps`, `test-coverage-gaps`, `test-anti-patterns`, `security-basics`

**Infra probes** (when CI/Docker markers found):
- CI configuration issues, Dockerfile anti-patterns

**UI probes** (when frontend frameworks detected):
- Accessibility gaps, component anti-patterns

**Arch probes** (any project):
- Circular dependencies, complexity hotspots, deep nesting

**Session probes** (when `.orchestrator/` exists):
- Session metric anomalies, recurring failures, stale learnings

For each probe match, record a finding in this exact format:
```
FINDING:
  probe: <probe_name>
  category: <category>
  severity: <critical|high|medium|low>
  file_path: <absolute path>
  line_number: <number>
  matched_text: <exact text from tool output>
  title: <short title>
  description: <1-2 sentence description>
  recommended_fix: <concrete fix suggestion>
```

If a probe's activation condition is not met, skip with note. If a probe command fails, skip gracefully and continue.

**CRITICAL**: Do NOT fabricate findings. Only report what tool output confirms.

### Key Detection Patterns

| Probe | Severity | Pattern |
|-------|----------|---------|
| Hardcoded secrets | Critical | `(password\|api_key\|secret\|token)\s*[:=]\s*["'][^"']+["']` (exclude test/env/fixtures) |
| eval usage | High | `eval\s*\(` |
| XSS (React) | High | `dangerouslySetInnerHTML` |
| SQL injection | High | `` `[^`]*SELECT[^`]*\$\{`` |
| any type | Medium | `:\s*any\b` or `as\s+any\b` |
| TS suppression | Medium | `@ts-ignore` |
| AI filler | Medium | `(as you can see\|it's worth noting\|needless to say)` |

## Phase 3: Verification & Scoring

### 3.1 Verify Each Finding

For EACH finding: read the file at `file_path:line_number`. Confirm `matched_text` appears at or near that line (+/-3 lines tolerance). If NOT confirmed, discard as false positive.

Report: "Verification: N confirmed, M discarded as false positives"

### 3.2 Confidence Scoring

Start at 40 baseline, add factor scores, clamp to 0-100. Critical severity findings always get minimum 70.

| Factor | Low (+0) | Medium (+10) | High (+20) |
|--------|----------|-------------|------------|
| Pattern specificity | Generic (URL, TODO) | Moderate (orphaned annotation) | Specific (API key regex, eval()) |
| File context | Test/example/docs | Utility/config/scripts | Production source/API handler |
| Historical signal | Previously dismissed | No prior data | Recurring issue |

Read `discovery-confidence-threshold` from config (default: 60).

### 3.3 Deduplication

Same `file_path` + overlapping line range (+/-5 lines) + different probes = duplicate. Keep higher severity finding.

### 3.4 Apply Thresholds

Remove findings below `discovery-severity-threshold` and below `discovery-confidence-threshold`. Log auto-dismissed count.

### 3.5 Embedded Mode Exit

If in embedded mode (called from session-end): STOP HERE. Return this JSON schema:

```json
{
  "findings": [
    {"probe": "string", "category": "string", "severity": "critical|high|medium|low",
     "confidence": 0, "file": "string", "line": 0, "description": "string", "recommendation": "string"}
  ],
  "stats": {
    "probes_run": 0, "findings_raw": 0, "verified": 0,
    "false_positives": 0, "by_category": {"<category>": {"findings": 0}}
  }
}
```

## Phase 4: Interactive Triage (Standalone Only)

Use **numbered Markdown lists** for all choices — Cursor does not have AskUserQuestion.

### Step 1: Summary Table

```
## Discovery Results

Probes run: [N] | Findings verified: [N] | False positives discarded: [N]

| Category | Critical | High | Medium | Low | Total |
|----------|----------|------|--------|-----|-------|
| Code     | ...      | ...  | ...    | ... | ...   |
| Infra    | ...      | ...  | ...    | ... | ...   |
| UI       | ...      | ...  | ...    | ... | ...   |
| Arch     | ...      | ...  | ...    | ... | ...   |
| Session  | ...      | ...  | ...    | ... | ...   |
| Audit    | ...      | ...  | ...    | ... | ...   |
| Vault    | ...      | ...  | ...    | ... | ...   |
| Feature  | ...      | ...  | ...    | ... | ...   |
```

### Step 2: Critical + High Findings — Review Individually

For each Critical or High finding, present with file context (+/-3 lines):

```
[CRITICAL] (confidence: 85) hardcoded-values: API key found in src/config.ts:42

<file context>

Recommended fix: <suggestion>

Options:
1. Create issue (critical)
2. Adjust priority
3. Dismiss — intentional
4. Dismiss — false positive
```

### Step 3: Medium + Low Findings — Review Batched

```
[N] medium/low findings in [category]:
1. [title] — [file_path]:[line] ([severity])

Options:
1. Accept all (Recommended) — one issue per finding. Fastest, and you can still close any of them later.
2. Review individually — decide finding by finding. Costs about a minute per item.
3. Dismiss all — no issues created, and the findings are gone when this session ends.
```

### Step 4: Batch Confirmation

```
Ready to create [N] issues? ([X] critical, [Y] high, [Z] medium, [W] low)

1. Create all [N] issues (Recommended) — the list is already filtered, so nothing here is noise. You can close any of them later.
2. Review list first — read the titles before anything is written. Costs one extra step.
3. Cancel — nothing is written, and this run's findings are not kept.
```

## Phase 5: Issue Creation

For each approved finding:
1. Format using gitlab-ops discovery issue template
2. Labels: `type:discovery` + `priority:<level>` + `area:<inferred>` + `status:ready`
3. **GitLab**: `glab issue create --title "[Discovery] <title>" --label "type:discovery,priority:<level>,area:<area>,status:ready" --description "<body>"`
4. **GitHub**: `gh issue create --title "[Discovery] <title>" --label "..." --body "<body>"`
5. Brief pause (1s) between creations

### Final Report

```
## Discovery Report
- Probes run: [N] across [categories]
- Verified: [N] (false positives: [M])
- User approved: [N]
- Issues created: [N]

| # | Title | Priority | Area | Probe |
|---|-------|----------|------|-------|
```

## Phase 6: Capture Stats (Standalone Only)

After Phase 5, prepare stats for session metrics (do NOT write to `sessions.jsonl` directly — session-end handles that):

- `probes_run`, `findings_raw`, `findings_verified`, `false_positives`, `user_dismissed`, `issues_created`, `by_category`

Report: "Discovery stats: [probes_run] probes, [findings_raw] raw → [findings_verified] verified ([false_positives] false positives). Created [issues_created] issues."

## Critical Rules

- **NEVER** fabricate findings — every finding must come from tool output with verifiable evidence
- **NEVER** create issues without user approval (standalone mode)
- **ALWAYS** verify findings by re-reading the file at the reported line (Phase 3)
- **ALWAYS** use numbered Markdown lists for choices — Cursor has no AskUserQuestion
- If a probe command fails, skip gracefully, continue with others
- If in embedded mode, stop after Phase 3, return findings as structured JSON
- Default exclude paths always apply