typescript-systematic-debugging
Systematic root-cause investigation for TypeScript backends. Use whenever the task is to debug an incident, regression, flaky behavior, timeout, unexpected 4xx/5xx, stuck stream, worker failure, Redis
SKILL.md.claude/skills/typescript-systematic-debugging/SKILL.md
GitHubTypeScript Systematic Debugging
Purpose
Apply a disciplined debugging method across the runtime, data, integration, streaming, reliability, performance, and observability surfaces used in this repository.
This skill is a narrow workflow-meta specialist. It does not own broad
architecture, review, or implementation work. Its job is to turn symptoms
into:
- a named failure surface
- a small set of competing mechanisms
- the best next diagnostic step
- an explicit bar for when "root cause" is justified
When used from a project agent, let the agent own scope, handoffs, and final decisions. This skill owns the debugging method only.
Expert Standard
Do not spend time restating common debugging advice.
Strong models will already know the generic moves:
- reproduce the issue
- inspect logs
- check recent changes
- form hypotheses
That is not the value of this skill.
The value of this skill is narrower and deeper reasoning:
- identify the first plausible bad boundary instead of narrating the whole stack
- separate neighboring failure classes that are easy to conflate
- choose the one next diagnostic step with the highest discriminating power
- keep the failure surface shrinking after each observation
- withhold fix direction until the mechanism has defeated the strongest nearby explanation
- keep the answer compact, operational, and hard to fool
If the answer could be rewritten as a generic debugging checklist with only small wording changes, it is still too shallow for this skill.
Read These References When You Need Them
references/investigation-checklist.mdUse when the symptom is still vague, the codebase is unfamiliar, or the prompt starts with only a failure report instead of a localized seam.references/confusion-pairs.mdUse when the first explanation sounds plausible but could easily be the wrong neighboring failure class.references/next-step-selection.mdUse when several probes are possible and the main job is choosing the one diagnostic step that best separates the live hypotheses.references/root-cause-quality-bar.mdUse when deciding whether the answer supports only triage, a leading hypothesis, a measurement gap, or a real root-cause claim.references/stack-specific-hard-anchors.mdUse when two theories are both plausible and the diagnosis turns on concrete Fastify, Prisma/PostgreSQL, Redis, outbound HTTP, streaming, timeout, readiness, or event-loop facts rather than method alone.
Relationship To Shared Research
Start with the local method and references in this skill.
This skill should not own a separate umbrella deep-research prompt.
Load references/investigation-checklist.md by default when the issue is not
already localized.
Load references/confusion-pairs.md for every non-trivial debugging task or
when the first theory feels plausible but unproven.
Load references/next-step-selection.md when the main risk is wasting time on
low-discrimination checks or multi-variable experiments.
Load references/root-cause-quality-bar.md before calling something root
cause, before suggesting a fix, or when deciding whether the honest output is
still a triage plan.
Load references/stack-specific-hard-anchors.md when the next narrowing step
depends on concrete runtime semantics and a wrong assumption about the stack
would send the investigation in the wrong direction.
Then load only the shared topic files that match the currently suspected surface:
../_shared-hyperresearch/deep-researches/fastify-runtime.mdUse for request lifecycle, hook order, decorator scope, reply ownership, and startup versus request-path failures.../_shared-hyperresearch/deep-researches/prisma-postgresql.mdUse for query shape, pool wait, transactions, migrations, locking, ordering, and data-shape issues.../_shared-hyperresearch/deep-researches/redis-runtime.mdUse for readiness, reconnect, TTL/state protocol, scripts, parser or reply shape, and key-design bugs.../_shared-hyperresearch/deep-researches/external-integration-adapter.mdUse for outbound timeout, retry, transport, error mapping, parse, or provider-drift issues.../_shared-hyperresearch/deep-researches/streaming-workers.mdUse for streaming lifecycle, abort, backpressure, queueing, worker pools, and response ownership.../_shared-hyperresearch/deep-researches/node-reliability.mdUse for deadline propagation, retries, readiness, shutdown, overload, and failure amplification.../_shared-hyperresearch/deep-researches/node-performance.mdUse for bottleneck localization, queueing chains, event-loop or worker-pool contention, Prisma wait, Redis RTT, and serialization cost.../_shared-hyperresearch/deep-researches/node-observability.mdUse for signal ownership, missing or misleading telemetry, and choosing the next probe.
Do not load all topics by default. Start with the most likely seam plus one adjacent seam only when the evidence crosses a boundary.
Scope
- debug incidents, regressions, flaky behavior, and unexpected runtime behavior in the TypeScript backend stack
- narrow the failure surface across HTTP, DB, Redis, outbound calls, streaming, workers, startup, and shutdown
- choose the next diagnostic step that best separates plausible mechanisms
- state what is known, what is inferred, and what still needs proof
- decide when the evidence is strong enough to call something root cause
Boundaries
Do not:
- guess fixes from the first plausible story
- turn the answer into a redesign or refactor plan
- treat symptoms, logs, or stack traces as full mechanism without boundary reasoning
- change several variables at once just to "see if it helps"
- recommend timeout, retry, cache, worker, schema, or pool changes before the failing surface is localized
- load every shared topic "for completeness"
Escalate When
Escalate if:
- the issue is already localized and the real task is design, review, or code implementation rather than debugging
- the dominant question is observability design, performance planning, or reliability policy rather than root-cause isolation
- the evidence is so thin that the honest answer is a triage plan instead of a root-cause claim
- the task becomes primarily security, product, or rollout analysis
Input Sufficiency
Before answering, identify the minimum known facts:
- what breaks and who feels it
- the first known failing phase: startup, request path, background work, streaming connection, or shutdown
- deterministic, intermittent, load-sensitive, deploy-sensitive, or data-dependent behavior
- the last known good signal and first bad signal
- which surfaces are plausibly touched: Fastify, Prisma/PostgreSQL, Redis, external integrations, streaming/workers, reliability, performance, observability
- what evidence already exists: repro steps, logs, traces, query data, metrics, recent diffs, timestamps
If those facts are missing, say so explicitly and lower confidence. Do not invent environment details, workload shape, or runtime behavior.
Core Defaults
- Symptoms are not mechanisms.
- One narrowed branch is better than five guesses.
- Prefer observation before mutation.
- Prefer one-variable-at-a-time checks.
- Prefer the diagnostic step that best separates the top hypotheses with the least blast radius.
- Keep facts, inferences, assumptions, and open questions separate.
- Lower confidence when the mechanism, trigger, or boundary is still inferred.
- Do not call something root cause until the nearby alternatives have been pressured.
- Prefer a more discriminating next step over a more comprehensive one.
- Prefer seam-local reasoning over stack-wide storytelling.
- Prefer killing the strongest wrong theory over collecting more plausible but non-separating detail.
Workflow
- Normalize the failure.
- Rewrite the problem as what breaks, where, when, how often, and for whom.
- Distinguish startup, request-path, streaming, background, and shutdown failures.
- Note whether the issue is deterministic, intermittent, load-sensitive, deploy-sensitive, or data-dependent.
- Classify the first likely failure surface.
- Fastify lifecycle or decorator scope
- Prisma/PostgreSQL query, pool, transaction, migration, or data shape
- Redis runtime state, TTL, Lua/script, key, readiness, or reconnect
- External integration transport, timeout, retry, mapping, or parsing
- Streaming or worker lifecycle, abort, backpressure, queue, or ownership
- Reliability budget, retry storm, readiness, shutdown, or degradation
- Performance bottleneck or hidden queue
- Observability gap or misleading signal
- Draw the minimal causal path.
- Name the path from trigger to failure.
- Mark handoffs, state transitions, and external boundaries.
- Identify the last point believed good and the first point believed bad.
- Inventory evidence.
- Separate hard facts from interpretation.
- Note which evidence is direct, indirect, stale, conflicting, or missing.
- If the codebase is unfamiliar, inspect the narrowest seam that could plausibly own the failure before widening search.
- Build competing hypotheses.
- Keep
2-4live hypotheses. - For each one, state: mechanism, expected evidence, strongest counter-signal, and cheapest discriminator.
- Reject hypotheses that do not explain the observed timing, scope, or boundary.
- Keep
- Choose the next diagnostic step.
Pick the step that separates the current hypotheses while changing the least.
Good next steps usually do one of:
- confirm the failing lifecycle phase
- compare queue wait versus execution time
- distinguish network failure from HTTP error
- distinguish client abort from server stall
- distinguish missing signal from missing behavior
- verify one boundary contract or state transition
- Update the failure surface.
- After each new observation, retire disproven branches.
- Shrink the suspected surface explicitly.
- If the surface widens instead of narrows, say why and load the next adjacent topic deliberately.
- Cross the root-cause threshold only when all are true.
- the failing surface is named precisely
- the mechanism explains the symptom and timing
- the trigger or precondition is identified
- the nearby alternative explanations were addressed
- the claim predicts what a confirming or disconfirming check should show
- Only then mention fix direction.
- Keep it minimal and surface-local.
- Pair it with a validation step that would confirm the mechanism, not just silence the symptom.
Reasoning Obligations
For any non-trivial debugging task, force all of these before sounding confident:
Primary Failure StoryName the currently leading mechanism and the first bad boundary or state transition.Strongest AlternativeName the neighboring explanation that a smart debugger could confuse with the primary one.Why The Primary WinsExplain what concrete observation currently favors the primary story.What Would Falsify ItName the observation that would demote or kill the current theory.Next Step ValueExplain why the chosen next step separates the hypotheses better than the obvious alternatives.
If one of those is missing, lower confidence or stay at triage/hypothesis rather than calling root cause.
Cross-Domain Routing Cues
Fastify Runtime
- Distinguish startup-time registration or decorator problems from request lifecycle failures.
- Hook order matters:
onRequest -> preParsing -> parsing -> preValidation -> validation -> preHandler -> handler -> preSerialization -> onSend -> onResponse. - Treat
asyncplusdone, earlyreply.send, raw-body reads, and decorator scope as separate failure classes.
Prisma / PostgreSQL
- Distinguish Prisma pool wait from slow SQL.
- Distinguish transaction or locking problems from data-shape or query-shape regressions.
- Treat migration drift, unstable ordering, JSON null semantics, and retry/isolation behavior as different classes of failure.
Redis Runtime
- Distinguish client readiness or reconnect issues from key or protocol logic bugs.
- Treat TTL as protocol state, not cleanup trivia.
- For scripts and guards, verify real reply shapes and truthiness semantics
rather than assuming string
'OK'.
External Integrations
- Distinguish network failure, timeout, cancellation, HTTP error response, parse failure, and provider semantic rejection.
- Keep retry ownership and idempotency explicit before blaming the provider or adapter.
Streaming / Workers
- Distinguish client abort, server stall, backpressure, queue growth, worker saturation, and response-ownership bugs.
reply.send()plus manual writes, ignoredwrite() -> false, and missing abort cleanup are different mechanisms, not one generic "streaming bug."
Reliability
- Distinguish the original failure from amplification caused by retries, hidden queues, long transactions, overload, bad readiness, or shutdown behavior.
- Treat deadline propagation and cancellation gaps as debugging surfaces, not only future hardening work.
Performance
- Distinguish symptom from bottleneck.
- Event loop, libuv worker pool, Prisma wait, PostgreSQL execution, Redis RTT, serialization or logging, and streaming backpressure are different queueing surfaces.
Observability
- Distinguish "the system is not telling us" from "the system is doing the wrong thing."
- Choose the next probe by question and truth owner, not by spraying random logs everywhere.
Quality Bar
A strong debugging answer should leave the reader with:
- a named failure surface, not only a symptom summary
- a compact set of live hypotheses, not a brainstorm dump
- one recommended next diagnostic step
- the reason that step best separates the current hypotheses
- the strongest nearby explanation and why it currently loses
- explicit assumptions and confidence
- a clear statement of what not to do yet
Reject answers that sound like:
- "Maybe increase the timeout."
- "Add retries and see."
- "It is probably Prisma."
- "Check the logs."
- "Let's rewrite this flow."
Those may become valid later, but not before the failure surface is narrowed.
Deliverable Shape
Return debugging help in this order:
SymptomFailure SurfaceKnown FactsLeading HypothesesNext Diagnostic StepWhy This StepAssumptions / ConfidenceDo Not Do Yet
Add these only when evidence supports them:
Disproved BranchesConfirmed Root CauseMinimal Fix DirectionValidation After Fix
Escalate Or Reject
- a user-proposed fix being treated as proof of mechanism
- cross-domain symptoms being collapsed into one vague "infra issue"
- root-cause claims that cannot name the first bad boundary or state transition
- shotgun debugging plans that change several variables at once
- architecture advice that appears before the next discriminating check is chosen