diff --git a/.claude/commands/article-audit.md b/.claude/commands/article-audit.md index 6fc07485..d46e3507 100644 --- a/.claude/commands/article-audit.md +++ b/.claude/commands/article-audit.md @@ -198,9 +198,12 @@ One of: - **Open an issue for a genuine gap** — same shape, but the work is larger. Flag if it's an epic. -If the answer is "open an issue," **ask the user before running -`gh issue create`.** They might want to tweak wording, add labels, or defer. -Don't just create issues on their behalf. +If the answer is "open an issue," **first search for an existing one** — +`gh issue list --state open --search ""` — and if a live issue +already covers the topic, extend/comment on it instead of opening a +near-duplicate (see CLAUDE.md "Search before you open an issue"). Then **ask +the user before running `gh issue create`.** They might want to tweak wording, +add labels, or defer. Don't just create issues on their behalf. ## Style notes diff --git a/.claude/commands/feature-spec.md b/.claude/commands/feature-spec.md index 737ab451..2793cb5e 100644 --- a/.claude/commands/feature-spec.md +++ b/.claude/commands/feature-spec.md @@ -188,6 +188,10 @@ Produce: Use the project's [work-item Issue Form fields](../../.github/ISSUE_TEMPLATE/work-item.yml) if possible (What / Why / Acceptance / Notes). Suggest labels: `type/feature`, the relevant `area/*`, `priority/*` if known. + **Before creating: search for an existing issue** — + `gh issue list --state open --search ""` — and extend a live one + rather than opening a near-duplicate, especially for epics (see CLAUDE.md + "Search before you open an issue"). 2. **Optional ADR draft** — if the significance check returned yes. diff --git a/CLAUDE.md b/CLAUDE.md index 1b3ebb83..8461780f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -218,6 +218,8 @@ When you find an antipattern, rule, or specification worth encoding, write to th **Deferral surface (NOT part of the encoding loop).** GitHub Issues (`rule-encoding-deferred` label) tracks findings where code shipped but the encoding hasn't yet. **The issue is a placeholder — a TODO that ensures the encoding eventually happens.** The issue itself is NOT the encoding; the PR that adds the rule to one of the five surfaces above is. Closed issues are not read again in future sessions; the rules live in the surfaces, not in the issue tracker. +**Search before you open an issue (especially epics).** Before `gh issue create`, run `gh issue list --state open --search ""` (and grep titles for the topic) — if an open issue already covers it, comment on or extend that one instead of opening a near-duplicate. Duplicate epics are the costly case: two "frontend" epics fragment progress tracking and the close-as-we-go discipline silently breaks. If a genuine overlap is found after the fact, consolidate to ONE canonical issue (fold the better framing in, close the rest as `duplicate` with a pointer) rather than leaving parallel trackers. Precedent: #129/#130/#102 frontend-epic consolidation, 2026-06-12. + The threshold for encoding is the same as the Debugging Discipline rule: **if the next person could repeat the mistake (or re-derive the rule from first principles), the rule belongs in writing.** Don't encode trivial style nits or one-off mistakes; do encode security patterns, performance traps, concurrency hazards, distributed-systems gotchas, anti-IDOR patterns, anti-IDOR-test patterns, outbox traps, anything cross-cutting. When you push a fix PR for a real finding, the *fix itself* lives in the PR but the *rule* lives in `.claude/`. The two should land together when feasible (single PR with both), or as paired PRs when separation is cleaner. **A merged fix PR without the corresponding rule is a half-finished job** — the next instance of the same antipattern will slip through.