sqldeadlock-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sqldeadlock-review (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Parse a SQL Server deadlock XML graph, identify the victim and winner processes, extract the queries and lock acquisition patterns involved, match against 16 known deadlock patterns (P1–P16), and produce a prioritized remediation plan.
Accept any of:
<deadlock> XML (from system_health XE session or SSMS deadlock graph Save As XML).xdl or .xml deadlock graph file<deadlock>
<victim-list>
<victimProcess id="process1a2b" />
</victim-list>
<process-list>
<process id="process1a2b" taskpriority="0" logused="0"
waitresource="KEY: 5:72057594038910976 (abc123)"
waittime="4023" ownerId="123456"
transactionname="user_transaction"
currentdb="5" spid="52" kpid="1234"
status="suspended" isolationlevel="read committed">
<executionStack>
<frame procname="adhoc" line="3" stmtstart="100" stmtend="200"
sqlhandle="0x...">
UPDATE Orders SET Status = 1 WHERE Id = @id
</frame>
</executionStack>
<inputbuf>UPDATE Orders SET Status = 1 WHERE Id = @id</inputbuf>
</process>
...
</process-list>
<resource-list>
<keylock hobtid="72057594038910976" dbid="5" objectname="dbo.Orders"
indexname="PK_Orders" id="lock1" mode="X" associatedObjectId="...">
<owner-list>
<owner id="process2c3d" mode="X" />
</owner-list>
<waiter-list>
<waiter id="process1a2b" mode="U" requestType="wait" />
</waiter-list>
</keylock>
...
</resource-list>
</deadlock>For each process:
<inputbuf> and <executionStack>)waitresource — what lock it is waiting fortransactionname — the transaction contextisolationlevel — READ COMMITTED, SNAPSHOT, SERIALIZABLE, etc.logused — how much log has been written (indicator of transaction size)For each resource:
keylock, pagelock, objectlock, ridlock, metadatalockALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON). Readers take no shared locks under RCSI — the most common fix for reader/writer deadlocks without changing application code.UPDATE statements taking U locks in different orders on the same table.WHERE clause columns so each update targets exactly one row (reduces lock scope). Consider using WITH (ROWLOCK) hint. Consistent access order also applies.objectlock or pagelock resource type (not keylock) in the resource list.keylock) locks instead of page locks. Use the sqlindex-advisor skill if an execution plan is available.keylock resources: one on a nonclustered index, one on the clustered index (PK). Process A holds lock on NC index, waits for PK. Process B holds lock on PK, waits for NC index.isolationlevel = serializable on one or more processes AND range locks (RangeX-X, RangeS-U) visible in the resource type.objectname in the resource list references a parent table, and one process is inserting into the child table while another deletes from the parent.victim-list and process-list contain only one process ID.READ_COMMITTED_SNAPSHOT is ON for the database yet the deadlock involves a reader (S lock) and a writer (X lock) in a cycle.WITH (HOLDLOCK) / WITH (UPDLOCK) hint overrides RCSI for that statement. RCSI only removes S locks for READ COMMITTED; higher isolation levels retain them.isolationlevel attribute). If REPEATABLE READ or SERIALIZABLE is not required by the application, downgrade to READ COMMITTED. Remove unnecessary WITH (HOLDLOCK) hints.<executionStack> as the active frame.WITH (TABLOCK) on the target as a short-term workaround (serializes all MERGE operations). Longer term, partition the target table or pre-stage source data to reduce concurrent overlap.ridlock entries instead of keylock entries./sqlindex-advisor to identify the best clustering key.transactionname containing "Distributed Transaction" or dtcState attribute present.objectname or indexname in their resource lists.objectname in the resource list is a tempdb object (tempdb.dbo.#temp or a system page like GAM, PFS, SGAM).objectlock (table-level lock) alongside keylock or ridlock entries on the same table, held by different sessions.ALTER TABLE ... SET (LOCK_ESCALATION = DISABLE) if read isolation allows. Alternatively, reduce transaction size so the 5,000-lock threshold is never reached. Enable RCSI to eliminate S locks from readers, reducing total lock count.objectname in the resource list references a ledger history table (named MSSQL_LedgerHistoryFor_...) or a temporal history table. Applies to SQL 2016+ (temporal) and SQL 2022+ (ledger).| Held \ Requested | S | U | X | IS | IX | SIX |
|---|---|---|---|---|---|---|
| S | ✓ | ✓ | ✗ | ✓ | ✗ | ✗ |
| U | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ |
| X | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| IS | ✓ | ✓ | ✗ | ✓ | ✓ | ✗ |
| IX | ✗ | ✗ | ✗ | ✓ | ✓ | ✗ |
| SIX | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ |
If the SQL Server version is known — from the ServerVersion attribute in the plan XML or stated by the user — read VERSION_COMPATIBILITY.md (~/.claude/skills/VERSION_COMPATIBILITY.md if installed, or skills/VERSION_COMPATIBILITY.md from the repo). If unavailable, skip silently. For checks whose minimum version exceeds the instance version: verbose mode → log as SKIP (version: requires SQL 20XX+, instance is SQL 20YY); standard report → omit entirely. Do not suppress NOT ASSESSED rows from missing input — only suppress version-inapplicable checks.
## Deadlock Analysis
### Deadlock Summary
| | Victim | Winner |
|--|--------|--------|
| **SPID** | X | Y |
| **Host** | [hostname] | [hostname] |
| **Procedure / Batch** | [proc name or first 80 chars of ad-hoc SQL, for display only] | [proc name or first 80 chars, for display only] |
| **Started** | [timestamp] | [timestamp] |
| **Log used** | [KB] | [KB] |
| **Pattern detected** | [P1–P8 or Unknown] | — |
### Lock Cycle
SPID X → holds [mode on object.index] → waits for [mode on object.index] SPID Y → holds [mode on object.index] → waits for [mode on object.index]
[One sentence confirming the circular wait and which SPID SQL Server chose as victim.]
### Pattern Match
**[Pattern name — e.g., P1 Classic Forward/Reverse Access Order]**
| Session | Step 1 | Step 2 |
|---------|--------|--------|
| SPID X — ProcA | [lock mode] on [Table1] ([index]) | Needs [lock mode] on [Table2] |
| SPID Y — ProcB | [lock mode] on [Table2] | Needs [lock mode] on [Table1] |
[One sentence explaining why this access order is deterministic and under what concurrency condition it fires.]
### Queries Involved
**Victim (SPID X) — [proc/batch name]**[query text]
[One sentence: what lock it acquires and on which resource.]
**Winner (SPID Y) — [proc/batch name]**[query text]
[One sentence: what lock it acquires first and what it then waits for.]
### Root Cause
[Pattern name, why the cycle is deterministic, which tables/indexes are involved, and what concurrent execution condition triggers it.]
### Remediation Plan
**Fix 1 (Recommended)** — [Action]
- Effort: Low / Medium / High
- Effectiveness: Eliminates / Reduces frequency / Hides symptom
- SQL: [DDL or setting change with code block if applicable]
**Fix 2** — [Action]
...
### Remediation Priority
| Fix | Effort | Effectiveness |
|-----|--------|--------------|
| Fix 1 — [name] | Low/Medium/High | Eliminates the deadlock |
| Fix 2 — [name] | Low | Reduces frequency; does not eliminate |
| Fix N — [name] | Low | Implement regardless as defensive coding |
---
*Analyzed by: [state the AI model and version you are running as, e.g. "Claude Sonnet 4.6", "DeepSeek R1", "GPT-4o"] · [current date and time in the user's local timezone, or UTC if timezone is unknown, e.g. "2026-05-16 20:15 NZST"]*`--brief` — Omit the Passed Checks table and attribution footer. Output the Summary, Findings, and Prioritized Fix Sequence sections only. Use when a quick scan of what fired is all that's needed.
`--critical-only` — Suppress Warning and Info findings. Show only Critical findings. The Passed Checks table is also omitted. Use when triaging an incident and only actionable blockers matter.
Both flags can be combined: --brief --critical-only produces the Summary section plus Critical findings only.
When neither flag is present, produce the full report as documented above.
When the user's request includes --verbose, --trace, or the word verbose:
1. Append a `## Check Evaluation Log` section after the Passed Checks table.
Include one row for every check in this skill's ruleset, in check-ID order:
| Check | Evidence | Threshold | Result |
|---|---|---|---|
| [ID — Name] | [key attribute(s) and value found, or "absent"] | [threshold or condition] | PASS / FIRE → [severity] / NOT ASSESSED |
Result conventions:
PASS — attribute present, threshold not met**FIRE → Critical/Warning/Info** — threshold met; bold to distinguish from passesNOT ASSESSED — required attribute absent from input2. Save both files to the current working directory using the Write tool:
output/<skill-name>/<YYYY-MM-DD-HHmmss>-<input-prefix>/analysis.md ← full report output/<skill-name>/<YYYY-MM-DD-HHmmss>-<input-prefix>/trace.md ← Check Evaluation Log
Derive <input-prefix>:
horrible.sqlplan → horrible)runSanitize: alphanumeric + hyphens/underscores only, max 32 chars.
File headers: analysis.md → # Analysis — <skill-name> / # Input: <first 80 chars> / # Generated: <UTC timestamp> trace.md → # Check Evaluation Log — <skill-name> / # Input: <first 80 chars> / # Generated: <UTC timestamp>
Create directories as needed. When --verbose is not present, write nothing to disk.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.