sota-async-concurrency — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sota-async-concurrency (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.
Concurrency bugs are the most expensive class of defect: they pass tests, ship, and then corrupt data or hang production under load. This skill encodes the 2026 state of the art for concurrent design and the bug catalog auditors need to spot defects by reading code, without reproducing them. Concepts are cross-language; per-runtime notes are inlined where semantics genuinely differ (GIL, goroutine scheduling, tokio executors, Node's single loop).
Two operating modes. Pick one explicitly before starting.
When writing new concurrent code:
threads (if runtime has real parallelism) or processes. Mixed → async front-end + bounded worker pool. Read rules/01 before choosing.
(TaskGroup / nursery / errgroup / JoinSet) that joins or cancels it. Spawning a task with no owner is a design smell requiring written justification.
request set, and spawn loop gets an explicit capacity. Unbounded = OOM with a delay timer.
why it inherits one from an enclosing scope.
Propagate context/AbortSignal/CancelledError; clean up in finally blocks; design shutdown order (stop intake → drain → deadline → force).
single-owner tasks; if you must lock, define lock ordering and never hold a lock across an await.
diff before declaring done.
When auditing existing code, you find races, deadlocks, and leaks by reading — grep is your debugger. Workflow:
state? What are the queues and their bounds? Draw the lock set and the channel graph mentally before judging any line.
create_task( / ensure_future( without a storedhandle; bare go func(; .then( with no .catch(; floating promises; tokio::spawn whose JoinHandle is dropped.
time.sleep, requests., open( , sync DB drivers,fs.readFileSync, bcrypt.hashSync, std::thread::sleep inside async fns.
async with lock: / mutex.lock() bodies containingawait / .await.
Queue() with no maxsize, make(chan T) fed by fastproducers, unbounded_channel, spawn-in-loop with no semaphore.
if x in d: … d[x], exists-then-create, read-modify-writeon shared counters without atomics/locks.
execution orders and which one breaks. A finding without an interleaving is a style note, not a concurrency bug.
rules/07 for the full bug catalog with signatures.| Severity | Criteria | Examples |
|---|---|---|
| CRITICAL | Data corruption, deadlock, or unbounded resource growth reachable under normal load | Lost-update race on money/state; lock-ordering deadlock on hot path; unbounded queue fed by network input |
| HIGH | Hang, leak, or wrong result under plausible (load/error/timeout) conditions | Fire-and-forget swallowing exceptions; no timeout on external call; lock held across await; blocking call on event loop |
| MEDIUM | Degraded behavior, starvation, or fragility under contention | Writer starvation on RwLock; missing jitter on retries; thundering herd on cache expiry; spurious-wakeup-unsafe condvar wait |
| LOW | Latent hazard or convention violation with no current trigger | Orphanable task that today happens to finish first; missing cancellation propagation in a path that is never cancelled yet |
Escalate one level when the affected state is money, auth, or durability.
[SEVERITY] file:line — short title
Race window / failure mode: the exact interleaving or condition (T1 does X,
T2 does Y between X and Z → consequence).
Trigger likelihood: what load/error pattern makes it fire.
Fix: concrete minimal change (primitive, bound, timeout value, scope).| File | Read this when... |
|---|---|
rules/01-models-and-structure.md | Choosing event loop vs threads vs processes vs actors; CPU/I-O decision tree; structured concurrency, task groups, no orphaned tasks |
rules/02-correctness.md | Reasoning about data races vs race conditions, atomicity, memory ordering/visibility, TOCTOU, deadlock prevention, livelock, starvation, idempotency under retries |
rules/03-primitives.md | Picking or reviewing mutexes, RwLocks, semaphores, condition variables, channels (bounded vs unbounded), select/race, once/lazy init |
rules/04-event-loop-hygiene.md | Anything runs on an event loop: blocking calls, CPU work, offloading to pools, long-task chunking, microtask vs macrotask |
rules/05-cancellation-timeouts-shutdown.md | Timeout policy, propagating cancellation (context/AbortSignal/CancelledError), cleanup on cancel, graceful shutdown sequencing |
rules/06-backpressure-flow-control.md | Queues between components, producer/consumer rate mismatch, load shedding, token buckets, pull-based streaming |
rules/07-audit-bug-catalog.md | AUDIT mode: the signature, severity, and fix for every common async bug — fire-and-forget, missing await, lock-across-await, retry storms, thundering herd, unbounded spawns |
or cancels it on scope exit. Fire-and-forget requires an error handler and a written reason.
with extra steps. Choose a capacity and a full-policy (block, drop, shed).
the loop thread — offload to a worker pool.
best and deadlocks it at worst.
internal ones inherit a scope deadline. "Forever" is a decision, not a default.
one lock region, an atomic primitive, or a DB constraint/UPSERT.
while holding a lock.
pass context/AbortSignal down every call chain that can block.
full jitter + retry budget; never retry a non-idempotent operation without a dedupe key.
wait()`), and shutdown follows the sequence: stop accepting → drain with deadline → cancel stragglers → release resources.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.