# Quirk #77 — Pest --parallel Unique Key Collision Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Document Pest --parallel `ProjectBulkActionsTest::rejects_bulk_when_scope_filter_captures_more_than_500_projects` collision как новый quirk #77 в memory `feedback_environment.md` + extend `pest-parallel-debugger` subagent с 5-th hypothesis.

**Architecture:** 2 deliverables — (a) Memory quirk entry following established pattern (quirks 70-76 structure: symptom / root cause / why / how to apply); (b) Subagent system prompt extension (new hypothesis section + updated diagnostic pipeline + updated output template).

**Tech Stack:** Markdown edits, no code changes. Memory file lives outside repo (`C:/Users/Administrator/.claude/projects/...`). Subagent file in repo at `.claude/agents/pest-parallel-debugger.md`.

**Discovery context:** Task 8 of completion plan ([docs/superpowers/plans/2026-05-13-claude-automation-completion-plan.md](2026-05-13-claude-automation-completion-plan.md) §Task 8) — Pest baseline regression check discovered new flake in `ProjectBulkActionsTest`. Subagent applied `superpowers:systematic-debugging` (3 hypotheses, 2 falsified, 1 confirmed). NOT a regression from feat/claude-automation work (`f454e95` audit-2 commit zero PHP code touched). Pre-existing flake surfaced during baseline run.

**Evidence captured (this session):**

- [`db/schema.sql:836`](../../../db/schema.sql#L836) — `UNIQUE (tenant_id, name)` constraint on `projects` table
- [`app/database/factories/ProjectFactory.php:23`](../../../app/database/factories/ProjectFactory.php#L23) — `'name' => fake()->words(3, true)` (Faker Lorem provider, default English locale ~100 words → ~1M combos)
- [`app/tests/Pest.php:18`](../../../app/tests/Pest.php#L18) — `// ->use(RefreshDatabase::class)` (RefreshDatabase commented; DatabaseTransactions implicit)
- [`app/tests/Feature/Api/ProjectBulkActionsTest.php:194-206`](../../../app/tests/Feature/Api/ProjectBulkActionsTest.php#L194-L206) — test creates 501 projects in single tenant via `Project::factory()->for($tenant)->count(501)->create()`

**Subagent raw output (Task 8) reproducible signature:**

```text
{"tool":"pest","result":"failed","tests":742,"passed":738,"assertions":2240,"duration_ms":~32000,"errors":1,
"error_details":[{
  "test":"P\\Tests\\Feature\\Api\\ProjectBulkActionsTest::__pest_evaluable_it_rejects_bulk_when_scope_filter_captures_more_than_500_projects",
  "file":"\\app\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php",
  "line":426,
  "message":"SQLSTATE[23505]: Unique violation: 7 ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности \"projects_tenant_id_name_key\"\nDETAIL: Ключ \"(tenant_id, name)=(<id>, <faker-name>)=(11795, eius animi qui)\" уже существует."
}],"skipped":3}
```

Tenant_id varied between runs (11795 → 11850, ~50 apart suggesting per-worker auto-increment offset). Sequential isolation: 14/14 ✅.

**Spec/source:** Discovered empirically. No formal spec — quirk documentation is the spec.

---

## File Structure

| Файл | Действие |
|---|---|
| `C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/feedback_environment.md` | Append quirk #77 entry (following existing #70-76 pattern); **NOT in repo, не commit'ить** |
| `C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/MEMORY.md` line 5 (feedback_environment reference) | Bump «76 квирков» → «77 квирков», добавить #77 в summary list |
| `.claude/agents/pest-parallel-debugger.md` (в repo на feat/claude-automation OR в работе после merge на main) | Extend subagent system prompt: +Quirk 77 in known-quirks section, +Hypothesis 5 в diagnostic pipeline, +Hypothesis 5 в output template |

---

## Task 1: Draft quirk #77 entry для memory `feedback_environment.md`

**Files:**

- Modify: `C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/feedback_environment.md` (append before final blank line)

- [ ] **Step 1.1: Find anchor position**

```bash
grep -n "^\*\*76\.\|^\*\*77\.\|^---$" "C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/feedback_environment.md" | tail -5
```

Identify line после last existing quirk #76 (or wherever pattern continues — file may have grown).

- [ ] **Step 1.2: Compose quirk #77 entry**

Follow established pattern (quirks 70-76 structure: bold-numbered title, then date + context, then Why, then How to apply):

```markdown
**77. Pest --parallel deterministic unique-key collision на `projects(tenant_id, name)` (13.05.2026 day +1, Task 8 baseline check finding).** `vendor/bin/pest --parallel --recreate-databases` reproducibly fails 738/742 на `ProjectBulkActionsTest::rejects_bulk_when_scope_filter_captures_more_than_500_projects` (file `app/tests/Feature/Api/ProjectBulkActionsTest.php:194-206`). Signature: `SQLSTATE[23505] projects_tenant_id_name_key — (tenant_id, name)=(<id>, "<faker-name>")`. Tenant_id varies between runs (11795, 11850 — ~50 apart suggesting per-worker auto-increment); name from Faker Lorem provider `fake()->words(3, true)` (~100 default English words → ~1M 3-word combos). Test creates 501 projects in single tenant via `Project::factory()->for($tenant)->count(501)->create()`. Sequential isolation `vendor/bin/pest tests/Feature/Api/ProjectBulkActionsTest.php` passes 14/14. **Deterministic** in --parallel, **passing** sequential.
**Why:** Root cause partial: collision on `(tenant_id, name)` UNIQUE (`db/schema.sql:836`). Birthday paradox math для 501 samples из ~1M combos дает ~12.5% per-test failure probability — НЕ deterministic. Reproducible-in-parallel-but-not-sequential pattern suggests interaction между worker processes (shared Faker seed via PHP global state? shared autoload init? Eloquent factory caching?). Full RCA pending — required deeper investigation beyond 41-second subagent diagnostic run (Task 8). NOT a regression from any specific commit — verified `git show f454e95 --stat` (audit-2 docs commit zero PHP touched), and `ProjectBulkActionsTest.php` last modification was commit `64d8dae` (feat: scope.filter resolver + 500-limit guard) without subsequent code changes triggering the flake.
**How to apply:** (1) Treat as **known parallel-only flake** — sequential `vendor/bin/pest tests/Feature/Api/ProjectBulkActionsTest.php` always 14/14 ✅. (2) При baseline regression check после feature-merge — accept 738/742 как baseline (vs «pure» 742/739/0/3 memory baseline from earlier sessions when flake didn't surface); rerun sequential для isolation confirm. (3) Long-term fix candidates (когда позволяет окружение): seed Faker explicitly с unique-per-test seeds (`fake()->seed($testId)`), OR add `->unique()` to factory name generation (`fake()->unique()->words(3, true)`), OR migrate Pest.php к `RefreshDatabase::class` (currently commented line 18) которое force-recreates DB per-test instead of TX rollback. (4) При появлении similar collision flakes на других `(tenant_id, name)` или похожих UNIQUE constraints — этот же класс quirk, same hypothesis.
```

- [ ] **Step 1.3: Append to memory file**

Use Edit tool с anchor (last existing quirk text), append new entry **before** any trailing whitespace/blank lines.

- [ ] **Step 1.4: Verify (no commit — memory files outside repo)**

```bash
grep -c "^\*\*77\." "C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/feedback_environment.md"
```

Expected: `1`.

---

## Task 2: Update `MEMORY.md` summary line для feedback_environment

**Files:**

- Modify: `C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/MEMORY.md` line 5

- [ ] **Step 2.1: Bump count + add summary**

**OLD line 5:**

```markdown
- [Особенности окружения](feedback_environment.md) — Windows Server 2022 + 76 квирков (последний bump: **13.05.2026 day +1 +квирки 74-76**): #76 docs/superpowers/plans/ relative paths требуют `../../../` для app/ references (lychee strict semantics; CTO-19 fixup `f6e1e64`); #75 Vuetify-internal default mdi-* names НЕ покрыты простым grep user code — нужно прочёсывать `node_modules/vuetify/lib/iconsets/mdi*` тоже (CTO-19 Task 2.b extension +25 entries → 103 total); #74 `npm install` требует `--legacy-peer-deps` из-за Histoire 1.0.0-beta.1 peerDep conflict; #73 Pest --parallel cumulative state расширился на long sessions без `--recreate-databases`. **Полный список 1-76 в файле**
```

**NEW line 5:**

```markdown
- [Особенности окружения](feedback_environment.md) — Windows Server 2022 + 77 квирков (последний bump: **13.05.2026 day +1 +квирк 77**): #77 Pest --parallel deterministic unique-key collision на `projects(tenant_id, name)` в `ProjectBulkActionsTest::rejects_bulk_when_scope_filter_captures_more_than_500_projects` (501-project bulk, Faker Lorem ~1M combos, ~12.5% sporadic→deterministic в parallel; sequential 14/14 ✅; root cause partial — possible worker state sharing); #76 docs/superpowers/plans/ relative paths требуют `../../../` для app/ references; #75 Vuetify-internal default mdi-* names НЕ покрыты простым grep user code; #74 `npm install` требует `--legacy-peer-deps` из-за Histoire 1.0.0-beta.1 peerDep conflict. **Полный список 1-77 в файле**
```

- [ ] **Step 2.2: Verify**

```bash
grep -E "77 квирков|#77 Pest" "C:/Users/Administrator/.claude/projects/c---------------------crm-------------/memory/MEMORY.md"
```

Expected: 2 matches (line 5 mentions).

---

## Task 3: Extend `.claude/agents/pest-parallel-debugger.md` subagent

**Files:**

- Modify: `.claude/agents/pest-parallel-debugger.md` (на feat/claude-automation OR на feat/claude-automation-quirk77-update — new sub-branch off main after PR merge)

**Decision (apply-time):** if Task 9 sync нормативки (completion plan) уже merged → create new sub-branch `feat/quirk-77-update` off main; else commit on `feat/claude-automation` directly (этот PR remains scoped к 8 automations + sync нормативки already drafted; adding quirk #77 в same PR mixes scope).

Recommendation: **separate branch** post Task 9 merge для atomic-commit hygiene.

### Edit 3.1: Add Quirk 77 в known-quirks section (after Quirk 73)

**Anchor:** end of Quirk 73 block, before `**NB:** quirks 70 (axe-core...)` line.

**Insert:**

```markdown
3. **Quirk 77 (memory feedback_environment.md, added 13.05.2026 day +1) — Pest --parallel deterministic unique-key collision на `projects(tenant_id, name)` в bulk-action tests.**
   - Symptom: `vendor/bin/pest --parallel --recreate-databases` reproducibly fails 738/742 на `ProjectBulkActionsTest::rejects_bulk_when_scope_filter_captures_more_than_500_projects`. Signature `SQLSTATE[23505] projects_tenant_id_name_key — (tenant_id, name)=(<id>, "<faker-3words>")`. Tenant_id varies per run (~50 apart — per-worker auto-increment).
   - Test creates 501 projects в single tenant; Faker Lorem provider ~100 default English words → ~1M 3-word combos; birthday paradox ~12.5% per-test → НЕ deterministic baseline. Reproducible-in-parallel-but-not-sequential pattern suggests worker state sharing (shared Faker seed via PHP global state? Eloquent factory caching?). Full RCA pending.
   - Sequential `vendor/bin/pest tests/Feature/Api/ProjectBulkActionsTest.php` passes 14/14 ✅.
   - Mitigation: treat as known parallel-only flake; sequential isolation always passes; baseline regression check on main post-merge — accept 738/742 OR rerun sequential.
```

(Adjust numbering — make this #3 in known-quirks list, push existing «**NB:**» line после.)

### Edit 3.2: Add Hypothesis 4 в diagnostic pipeline (between current H3 «cumulative state» и H4 «other»)

**Current diagnostic pipeline ends with «Hypothesis 4 — other». Insert new H4 (quirk 77) before, renumber «other» to H5.**

**Replace:**

```markdown
4. **Hypothesis 4 — other.** If none of above → escalate с raw output + tested hypotheses + outcome per hypothesis.
```

**With:**

```markdown
4. **Hypothesis 4 — quirk 77 (unique-key collision в bulk-action tests).** Failing test creates ≥500 records of one model в single tenant с Faker-generated unique field? Pattern: `SQLSTATE[23505]` + `_tenant_id_<col>_key` constraint name + Faker-style value в DETAIL. Rerun sequential `./vendor/bin/pest <test-file>` — if passes 14/14 → quirk 77 confirmed; document as known parallel-only flake, не fix без user OK (root cause не fully RCA'd).
5. **Hypothesis 5 — other.** If none of above → escalate с raw output + tested hypotheses + outcome per hypothesis.
```

### Edit 3.3: Update output template — add Hypothesis 4 row

**Replace в Output format block:**

```text
Hypothesis 3 (quirk 73 cumulative state): <falsified|confirmed|untested>
  Evidence: <command + output>

Conclusion: <real fix needed | quirk 72 — known race document | quirk 73 — recreate-databases fixed | other — escalate>
```

**With:**

```text
Hypothesis 3 (quirk 73 cumulative state): <falsified|confirmed|untested>
  Evidence: <command + output>
Hypothesis 4 (quirk 77 unique-key collision): <falsified|confirmed|untested>
  Evidence: <command + output>

Conclusion: <real fix needed | quirk 72 — known race document | quirk 73 — recreate-databases fixed | quirk 77 — known parallel-only flake document | other — escalate>
```

### Edit 3.4: Update agent description (frontmatter)

**OLD description:**

```yaml
description: |
  Diagnose Pest 4 --parallel test failures in the Лидерра CRM project.
  Classifies failures as (a) real failure, (b) quirk 72 (Redis supplier:session
  race в subdir-only), (c) quirk 73 (cumulative state on long sessions),
  or (d) other — escalate. Falsifies hypotheses with actual command runs.
```

**NEW description:**

```yaml
description: |
  Diagnose Pest 4 --parallel test failures in the Лидерра CRM project.
  Classifies failures as (a) real failure, (b) quirk 72 (Redis supplier:session
  race в subdir-only), (c) quirk 73 (cumulative state on long sessions),
  (d) quirk 77 (unique-key collision в bulk-action tests with Faker-generated names),
  or (e) other — escalate. Falsifies hypotheses with actual command runs.
```

### Step 3.5: Verify markdownlint + commit

```bash
npx markdownlint-cli2 ".claude/agents/pest-parallel-debugger.md" 2>&1 | tail -5
```

Expected: 0 errors.

```bash
git add .claude/agents/pest-parallel-debugger.md
"C:/моя/проекты/портал crm/Документация/bin/gitleaks.exe" protect --staged --config "C:/моя/проекты/портал crm/Документация/.gitleaks.toml" --no-banner
git commit -m "$(cat <<'EOF'
feat(agent): extend pest-parallel-debugger с quirk 77 (unique-key collision)

Added Quirk 77 documentation per memory feedback_environment.md addition:
Pest --parallel deterministic unique-key collision на projects(tenant_id, name)
в ProjectBulkActionsTest::rejects_bulk_when_scope_filter_captures_more_than_500_projects.

- New Hypothesis 4 в diagnostic pipeline (between quirk 73 и «other»)
- Updated output template (Hypothesis 4 row + extended Conclusion options)
- Updated description frontmatter (added quirk 77 classification)

Evidence (Task 8 baseline check):
- Reproducible 738/742 в --parallel --recreate-databases
- Sequential isolation 14/14 passes
- Pre-existing flake, NOT regression from any specific commit
- Root cause partial (Faker seed sharing hypothesis); full RCA pending

NB: project-local subagent auto-discovery может требовать session restart.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```

---

## Self-review (after writing plan)

### 1. Spec coverage

- ✅ Memory quirk entry (Task 1) — follows established pattern (numbered, dated, symptom/why/apply).
- ✅ MEMORY.md summary update (Task 2) — bumps count + adds #77 to inline summary.
- ✅ Subagent extension (Task 3) — 4 distinct edits to integrate quirk 77 throughout subagent prompt.

### 2. Placeholder scan

- `<id>`, `<faker-name>`, `<faker-3words>`, `<col>`, `<test-file>` — these are documentation placeholders for varying actual values, not implementation gaps. Acceptable.
- No "TBD" / "implement later" / "fill in details".

### 3. Type consistency

- Quirk number `77` consistent across Task 1 entry, Task 2 summary, Task 3 hypothesis label.
- File paths `app/tests/Feature/Api/ProjectBulkActionsTest.php`, `app/database/factories/ProjectFactory.php`, `db/schema.sql:836` consistent.
- Existing quirk numbers `70-76` referenced consistently with their actual content (verified via Grep this session).

### 4. NB ограничения (явно зафиксированы)

- **Не верифицировал** root cause of «deterministic-in-parallel-but-not-sequential» pattern beyond «possible worker state sharing» hypothesis. Full RCA requires deeper investigation (PHP shared globals via fork, Faker internal state, Pest worker config). Quirk entry honestly documents this как «root cause partial; pending».
- **Не запускал** Pest на feat/claude-automation worktree to re-confirm collision — relied on Task 8 subagent's two consecutive --parallel runs.
- **Не верифицировал** что Faker Lorem default has ~100 words exact count — citation of general Faker docs knowledge, may differ in actual installed Faker version.
- **Не применил** ни одного Edit от Tasks 1-3 — это plan only.

---

## Execution handoff

Plan complete и saved to `docs/superpowers/plans/2026-05-13-quirk-77-pest-parallel-unique-key-collision-plan.md`. Two execution options:

1. **Inline Execution** — execute Tasks 1-3 в new session through `superpowers:executing-plans`. NB: Task 1+2 modify files OUTSIDE repo (memory), no commit needed. Task 3 commits to feat/claude-automation OR new sub-branch.

2. **Plan-only** — saved для будущей реализации; defer until Task 9 sync нормативки (completion plan) merged, then apply quirk 77 update on fresh sub-branch.

**Recommendation:** Plan-only — wait until completion plan Task 9 merged, then apply quirk 77 на separate branch `feat/quirk-77-update` для atomic-commit hygiene.

**Which approach?** (или — plan saved здесь, оставить как future-work item для memory cleanliness)
