Hard Rules
- Future fragility, not current bugs. Pre-mortem analyzes code that WORKS NOW but will plausibly break from a reasonable future edit. If something is already broken, stop and run a systematic diagnosis (debug-session) instead.
- Every finding needs a complete causal chain. "This could be a problem" is not a finding. Write the full incident in past tense with cause → effect → detection, or don't report it.
- Hard cap of 7 incidents per analysis. Pick the most plausible and highest-severity. Over-reporting buries the signal.
- Coverage downgrades severity. If a fragility is already protected by tests, it is not a P0. Lower its severity accordingly.
Pre-Mortem Analysis
Write incident reports for bugs that haven't happened yet. Read working code and identify where future edits will plausibly introduce failures.
Philosophy
This is NOT a linter. NOT a code review. This is a predictive failure analysis — imagining realistic future scenarios where reasonable edits break working code. The output is written in past tense ("What happened", "Why it broke") to force complete causal chains instead of vague warnings.
Step 1: Scope Selection
Ask: "Which area should I pre-mortem?" or infer from context.
Scope options:
- File: Single file deep-dive (best for complex modules)
- Feature: Cross-file analysis of a feature path (best for integration risks)
- System: Broad scan for top fragility hotspots (broadest; parallelize across modules if the host supports it)
Read the target code. Max 5 files for File/Feature scope. For System scope, work module by module.
Step 2: Fragility Pattern Scan
For each code area, check these 12 fragility patterns:
| Pattern |
What to Look For |
| Implicit ordering |
Code that works only because steps happen in a specific order, with no enforcement |
| Shared mutable state |
Globals, module-level dicts, class variables mutated by multiple callers |
| Stringly-typed contracts |
String comparisons for control flow (if status == "active") |
| Baked-in data assumptions |
Hardcoded column names, assumed data shapes, magic indices |
| Coincidental correctness |
Code that produces right answers for current data but wrong for edge cases |
| Non-atomic operations |
Multi-step mutations that can leave state inconsistent if interrupted |
| Invisible invariants |
Rules that must hold but aren't enforced (e.g., "X must be called before Y") |
| Load-bearing defaults |
Default values that silently mask failures instead of surfacing them |
| Implicit resource lifecycles |
Files, connections, locks that depend on call order for cleanup |
| Version-coupled assumptions |
Code that breaks when a dependency updates (API version, schema change) |
| Silent None propagation |
Functions that return None on failure where callers expect values |
| Train/inference skew |
ML paths where training and prediction use different preprocessing |
Step 3: Write Incident Reports
For each fragility found (max 7 per analysis), write a realistic incident report:
### Incident: [Short title]
**Severity:** P0 / P1 / P2 / P3
**Fragility Pattern:** [from table above]
**File(s):** [paths]
**What happened:** [Past tense — describe the plausible future scenario]
A developer added multi-field validation to the form processor. Each invalid field
now generates a separate error record. The success_rate metric divided total_records
by error_count, assuming one error per row. With multiple errors per row, the
denominator inflated, dropping the reported success rate from 94% to 61%.
**Why it broke:** [Root cause chain]
The success_rate calculation in metrics.py:47 assumed a 1:1 relationship between
rows and errors. This assumption was never documented or enforced. The validation
change was reasonable and passed all existing tests.
**How it was caught:** [Realistic detection path]
An A/B test showed a 30% drop in the success metric. The on-call engineer traced it
to the validation change merged 3 days prior.
**Hardening suggestion:** [Specific, minimal fix]
Add assertion: `assert error_count <= total_records` in metrics calculation.
Or: normalize by unique row IDs, not raw error count.
Step 4: Output PRE-MORTEM.md
Write all incidents to PRE-MORTEM.md (or .planning/PRE-MORTEM.md if that directory exists) with:
- Header: date, scope, files analyzed
- Incidents ranked by severity (P0 first)
- Summary: total fragilities found, top 3 actionable items
Step 5: Route to Action
| Finding |
Route To |
| P0 fragility in production code |
Flag to the user immediately — potential current risk |
| P1-P2 fragilities |
Add to a tracked "hardening backlog" (e.g., a TODO/backlog doc) |
| Pattern appears across 3+ files |
Capture it as a systemic insight in your durable notes — it's bigger than one file |
| ML train/inference skew detected |
Pair with a domain expert review before deploying the model path |
Trigger Conditions
- Reviewing code for fragility before a deployment or release
- Just completed a feature and want to know where it will bite later
- The user says "what could break", "find fragile code", "pre-mortem", "what will go wrong", or "future bugs"
- A working module is about to take on new callers or new edits
Out of Scope
- Current bugs or test failures → run a systematic diagnosis (debug-session)
- Code style or naming → refactor-session
- Security vulnerabilities → security-audit
- Performance bottlenecks → performance-tuning
- Quality review of code as written (not future fragility) → code-review-session
Common Traps
- Finding current bugs, not future fragilities — pre-mortem is about code that WORKS NOW but will break from reasonable future edits. If it's already broken, use debug-session.
- Vague warnings without causal chains — "This could be a problem" is useless. Write the full incident with past-tense causality.
- Over-reporting — Max 7 incidents. Pick the most plausible and highest-severity. Don't report style issues.
- Ignoring test coverage — If a fragility is already covered by tests, it's not a P0. Downgrade severity.
1---2name: pre-mortem3description: Use when reviewing code for fragility before deployment, after completing a feature, before a release, or when the user says "what could break", "find fragile code", "pre-mortem", "what will go wrong", "future bugs". NOT for current bugs (use debug-session) or code style (use refactor-session).4license: MIT5---67## Hard Rules89- **Future fragility, not current bugs.** Pre-mortem analyzes code that WORKS NOW but will plausibly break from a reasonable future edit. If something is already broken, stop and run a systematic diagnosis (debug-session) instead.10- **Every finding needs a complete causal chain.** "This could be a problem" is not a finding. Write the full incident in past tense with cause → effect → detection, or don't report it.11- **Hard cap of 7 incidents per analysis.** Pick the most plausible and highest-severity. Over-reporting buries the signal.12- **Coverage downgrades severity.** If a fragility is already protected by tests, it is not a P0. Lower its severity accordingly.1314# Pre-Mortem Analysis1516Write incident reports for bugs that **haven't happened yet**. Read working code and identify where future edits will plausibly introduce failures.1718## Philosophy1920This is NOT a linter. NOT a code review. This is a **predictive failure analysis** — imagining realistic future scenarios where reasonable edits break working code. The output is written in past tense ("What happened", "Why it broke") to force complete causal chains instead of vague warnings.2122## Step 1: Scope Selection2324Ask: "Which area should I pre-mortem?" or infer from context.2526Scope options:27- **File**: Single file deep-dive (best for complex modules)28- **Feature**: Cross-file analysis of a feature path (best for integration risks)29- **System**: Broad scan for top fragility hotspots (broadest; parallelize across modules if the host supports it)3031Read the target code. Max 5 files for File/Feature scope. For System scope, work module by module.3233## Step 2: Fragility Pattern Scan3435For each code area, check these 12 fragility patterns:3637| Pattern | What to Look For |38|---------|-----------------|39| **Implicit ordering** | Code that works only because steps happen in a specific order, with no enforcement |40| **Shared mutable state** | Globals, module-level dicts, class variables mutated by multiple callers |41| **Stringly-typed contracts** | String comparisons for control flow (`if status == "active"`) |42| **Baked-in data assumptions** | Hardcoded column names, assumed data shapes, magic indices |43| **Coincidental correctness** | Code that produces right answers for current data but wrong for edge cases |44| **Non-atomic operations** | Multi-step mutations that can leave state inconsistent if interrupted |45| **Invisible invariants** | Rules that must hold but aren't enforced (e.g., "X must be called before Y") |46| **Load-bearing defaults** | Default values that silently mask failures instead of surfacing them |47| **Implicit resource lifecycles** | Files, connections, locks that depend on call order for cleanup |48| **Version-coupled assumptions** | Code that breaks when a dependency updates (API version, schema change) |49| **Silent None propagation** | Functions that return None on failure where callers expect values |50| **Train/inference skew** | ML paths where training and prediction use different preprocessing |5152## Step 3: Write Incident Reports5354For each fragility found (max 7 per analysis), write a realistic incident report:5556```markdown57### Incident: [Short title]5859**Severity:** P0 / P1 / P2 / P360**Fragility Pattern:** [from table above]61**File(s):** [paths]6263**What happened:** [Past tense — describe the plausible future scenario]64A developer added multi-field validation to the form processor. Each invalid field65now generates a separate error record. The success_rate metric divided total_records66by error_count, assuming one error per row. With multiple errors per row, the67denominator inflated, dropping the reported success rate from 94% to 61%.6869**Why it broke:** [Root cause chain]70The success_rate calculation in metrics.py:47 assumed a 1:1 relationship between71rows and errors. This assumption was never documented or enforced. The validation72change was reasonable and passed all existing tests.7374**How it was caught:** [Realistic detection path]75An A/B test showed a 30% drop in the success metric. The on-call engineer traced it76to the validation change merged 3 days prior.7778**Hardening suggestion:** [Specific, minimal fix]79Add assertion: `assert error_count <= total_records` in metrics calculation.80Or: normalize by unique row IDs, not raw error count.81```8283## Step 4: Output PRE-MORTEM.md8485Write all incidents to `PRE-MORTEM.md` (or `.planning/PRE-MORTEM.md` if that directory exists) with:86- Header: date, scope, files analyzed87- Incidents ranked by severity (P0 first)88- Summary: total fragilities found, top 3 actionable items8990## Step 5: Route to Action9192| Finding | Route To |93|---------|---------|94| P0 fragility in production code | Flag to the user immediately — potential current risk |95| P1-P2 fragilities | Add to a tracked "hardening backlog" (e.g., a TODO/backlog doc) |96| Pattern appears across 3+ files | Capture it as a systemic insight in your durable notes — it's bigger than one file |97| ML train/inference skew detected | Pair with a domain expert review before deploying the model path |9899## Trigger Conditions100101- Reviewing code for fragility before a deployment or release102- Just completed a feature and want to know where it will bite later103- The user says "what could break", "find fragile code", "pre-mortem", "what will go wrong", or "future bugs"104- A working module is about to take on new callers or new edits105106## Out of Scope107108- Current bugs or test failures → run a systematic diagnosis (debug-session)109- Code style or naming → refactor-session110- Security vulnerabilities → security-audit111- Performance bottlenecks → performance-tuning112- Quality review of code as written (not future fragility) → code-review-session113114## Common Traps115116- **Finding current bugs, not future fragilities** — pre-mortem is about code that WORKS NOW but will break from reasonable future edits. If it's already broken, use debug-session.117- **Vague warnings without causal chains** — "This could be a problem" is useless. Write the full incident with past-tense causality.118- **Over-reporting** — Max 7 incidents. Pick the most plausible and highest-severity. Don't report style issues.119- **Ignoring test coverage** — If a fragility is already covered by tests, it's not a P0. Downgrade severity.