A universal investigation framework combining the 5 Ws and 5 Whys.
Applicable to any problem with decomposable causal structure — across disciplines, domains, and scales.
SOMETHING HAPPENED → TO SOMEONE → SOMEWHERE → AT SOME POINT → FOR SOME REASON
📋 Framework · 🧮 The Math · 🔬 Proofs · 📊 Diagrams · ⚙️ Engine
Every problem in every field has the same anatomy.
The vocabulary changes. The structure never does.
The 5 Ws tell you what happened.
The 5 Whys tell you why it happened.
Together they tell you what to do about it.
Establish the full picture before drilling into cause.
| Question | What It Captures |
|---|---|
| Who | The actor, subject, or stakeholder involved |
| What | The event, problem, or incident |
| When | The timeline — before, during, and after |
| Where | The location, system, environment, or context |
| Why | The surface-level, immediately apparent reason |
Start at the surface Why. Ask why again.
Keep going until you hit something you can actually change.
Why (surface)
└─► Why 1
└─► Why 2
└─► Why 3
└─► Why 4
└─► Why 5: ROOT CAUSE
Whys can and should branch. Real problems are rarely single-cause.
Map each root cause to a concrete change. Apply the counterfactual test:
"If this change had existed before the problem occurred,
would the problem still have happened?"
Each root cause is either fixed, mitigated, or accepted.
Confirm the fix worked. Update your priors.
The framework compounds over time — but only if learning is explicit.
| Domain | Who | What | When | Where | Why |
|---|---|---|---|---|---|
| 🏥 Medicine | Patient | Symptom | Onset | Body system | Presenting complaint |
| 🔒 Security | Threat actor | Breach | Attack window | Vulnerability | Attack vector |
| ⚙️ Engineering | System | Failure | Timeline | Component | Error message |
| 📈 Business | Team / Process | Bottleneck | Quarter | Department | Stated reason |
| ⚖️ Legal | Defendant | Act | Date | Jurisdiction | Motive |
| 🧠 Personal | You | Decision | Moment | Context | Emotion |
The framework is an applied graph traversal algorithm for causal inference —
with probability weighting, entropy reduction, and Bayesian evidence updating at every node.
| # | Concept | What It Answers |
|---|---|---|
| 01 | Graph Theory | What is the structure of an investigation? |
| 02 | Exponential Problem Space | Why do investigations feel overwhelming? |
| 03 | Causal Inference | How do you prove something caused something else? |
| 04 | Information Theory | How do you measure investigative progress? |
| 05 | Bayesian Reasoning | How do you weigh competing causes? |
| 06 | Search Algorithms | How do you move through the Why tree? |
| 07 | Cognitive Biases | What corrupts the investigation? |
| 08 | Evidence Evaluation | How do you know which evidence to trust? |
Map before you drill. Complete the 5 Ws before starting the 5 Whys.
Evidence at every node. An assertion without evidence is a guess.
Branch when reality branches. If a Why has multiple answers, follow all of them.
5 is a heuristic, not a rule. Stop when you reach something you can actually change.
The framework is recursive. A root cause can become a new "What." Run it again if needed.
The framework is also available as a Python library with built-in LLM integration.
Works with any provider — OpenAI, Anthropic, Groq, Mistral, Ollama, or any OpenAI-compatible endpoint.
cd engine && pip install -e .Auto-investigate with any LLM — one call, all 4 layers:
from htsa_engine.llm import LLMAdvisor
advisor = LLMAdvisor("https://api.openai.com/v1", api_key="sk-...", model="gpt-4o")
inv = advisor.run("API returning 500 errors since 2:47 AM, EU region only")
print(inv.root_causes)
inv.save("investigation.json")Or drive it manually — full control over every decision:
from htsa_engine import Investigation, Evidence, EvidenceTier, EvidenceDirection
inv = Investigation(title="API 500 errors", pruning_threshold=0.05)
inv.set_situation(who_affected="Users", what="500 errors", when_during="2:47 AM", where="EU-west", why_surface="Load spike")
inv.complete_situation()
origin = inv.start_causal_chain("Server errors under load")
branch = inv.add_hypothesis(origin, "Memory leak", probability=0.6)
# ... add evidence, mark root cause, resolve, verify
inv.save("investigation.json")