Async Correctness 非同期処理の正しさ検証 · v0.1.0 · 2026-07-10 · sha256 3c83cd795cfadcab

Async Correctness 非同期処理の正しさ検証 v0.1.0A

Immutable. This exact content is served forever at /api/v1/blob/3c83cd795cfadcab.

---
id: 'async-correctness'
name: 'Async Correctness 非同期処理の正しさ検証'
version: 0.1.0
description: 'await 漏れ・floating promise・並行競合など、非同期処理の correctness バグを検出する。並列化の効率提案(SIMPLIFY Efficiency)や配線断点(e2e-wiring)ではなく、「await を忘れて結果・順序・エラー伝播が壊れる」実装バグに限定する'
category: midstream
phase: [midstream]
applyTo:
  - 'src/**/*.{ts,tsx,js,jsx,mjs}'
tags: [async, await, promise, race-condition, correctness, midstream]
severity: major
inputContext: [diff, fullFile]
outputKind: [findings, questions]
modelHint: high-accuracy
dependencies: [code_search]
---

## Pattern declaration

Primary pattern: Reviewer
Secondary patterns: Inversion
Why: 非同期 correctness はチェックリスト型評価が主だが、async/await/Promise を含まない差分では実行を止めるゲートが必要

## Goal / 目的

- 差分に含まれる非同期処理の correctness バグ(await 漏れ・floating promise・並行競合)が本番で「たまにしか再現しない不具合」になるのを防ぐ。
- 「動いているように見えるが順序・エラー伝播が壊れている」実装を、差分の段階で検出する。

## Non-goals / 扱わないこと

- 宣言した処理の経路が末端まで配線されているかの確認(`e2e-wiring` の役割。本スキルは配線済みの非同期コードの**実行の正しさ**を見る)。
- 逐次 await の並列化提案(SIMPLIFY 観点 Efficiency の役割。本スキルは「速くできる」ではなく「壊れている」だけを指摘する)。
- テストコード内の un-awaited assertion(`vitest-mock-isolation` の役割)。
- null / undefined の伝播(`typescript-nullcheck` / `nullability-contract` の役割)。
- 設計判断そのものの論理検証(`logic-torturing` の役割)。

## Pre-execution Gate / 実行前ゲート

このスキルは以下の条件が**すべて**満たされない限り`NO_REVIEW`を返す。

- [ ] 差分の追加・変更行に `async` / `await` / `.then` / `.catch` / `.finally` / `Promise` のいずれかが出現する
- [ ] inputContext に diff が含まれている

ゲート不成立時の出力: `NO_REVIEW: async-correctness — 非同期処理を含む変更が検出されない`

## False-positive guards / 抑制条件

- 意図的な fire-and-forget(`void asyncFn()` 明示、またはコメント・命名で意図が明確なもの)は指摘しない。ただしエラーハンドリングが皆無なら questions として確認する。
- `@typescript-eslint/no-floating-promises` が有効なリポジトリでは、当該ルールが決定論で検出する単純な floating promise の severity を minor に落とす。順序・競合の問題はこの限りでない。
- フレームワークが await を要求しない規約(イベントハンドラ・ライフサイクルフック等)に従う呼び出しは指摘しない。
- 共有状態への並行アクセスは、差分内のコードだけで競合が確定する場合のみ findings とする。差分外の呼び出し文脈に依存する場合は questions に落とす。

抑制時の出力: 該当する指摘を出力しない(黙る)。

## Rule / ルール

- **await 漏れ**: Promise を返す呼び出しの結果を await / then せずに値として使用していないか(`if (asyncCheck())` は常に truthy、`const x = asyncGet()` の x は Promise)。
- **floating promise**: 結果もエラーも処理されない Promise が放置されていないか(unhandled rejection でプロセス・リクエストが不安定になる)。
- **エラー伝播の断絶**: `try` ブロック内で await せずに Promise を return し、catch が効かない構造になっていないか。
- **並行競合**: 同一リソースへの check-then-act(TOCTOU)、`Promise.all` 内での同一状態への書き込み、ループ内の共有変数への非同期書き込みがないか。
- **待たれないコレクション反復**: `forEach` に async コールバックを渡して完了を待たずに後続処理へ進んでいないか(`for...of` + await または `Promise.all(map(...))` が必要な文脈か確認)。
- **非同期コールバックの誤用**: `filter` に async コールバックを渡していないか(Promise は常に truthy のため全件が残り、フィルタリングが機能しない)。`reduce` で Promise のハンドリングが壊れていないか。
- 指摘は最大 5 件。データ破壊・順序依存バグに直結するものを優先する。

## Evidence / 根拠の取り方

- 指摘は差分内の該当行(`<file>:<line>`)に紐づける。
- 呼び出し先が Promise を返すことを、型シグネチャまたは code_search で確認してから指摘する(推測で「非同期のはず」と断定しない)。
- 「壊れる」と「壊れる可能性がある」を区別し、後者は入力条件・タイミング条件を明示する。

## Output / 出力(短文版の推奨)

River Review のコメントは`<file>:<line>: <message>`形式です。コメントは日本語で返す。

- Finding: 何が問題か(1文)
- Impact: 何が困るか(短く)
- Fix: 次の一手(最小の修正案)

例:

- `src/sync.ts:31: saveAll() の戻り値 Promise を await せず次の read が走る。書き込み前の古い値を読む競合。Fix: await saveAll() に変更`

## Heuristics / 判定の手がかり

- `async` 関数内で戻り値が使われない Promise 呼び出し(`.then` / `await` / `void` / 変数代入のいずれもない)
- `if` / `while` / `switch` / 三項演算子 / `!` の条件位置にある async 関数呼び出し
- `try { return asyncFn(); } catch` の形(await なし return)
- `forEach(async ...)` / `filter(async ...)` パターン
- ループ・`Promise.all` 内での同一変数・同一キーへの書き込み

## Good / Bad Examples

### Good

```text
src/jobs/cleanup.ts:18: if (isLocked(id)) は Promise を条件評価しており常に truthy。ロック確認が機能せず二重実行される。Fix: if (await isLocked(id))
```

### Bad

```text
src/jobs/cleanup.ts:18: 非同期処理に注意してください
```

(どの行の何が壊れるかの特定なし、Impact / Fix なし)

## 評価指標(Evaluation)

- 合格基準: 指摘が差分内の非同期コードに紐づき、呼び出し先が Promise を返す根拠と、壊れる条件・修正案が示されている。
- 不合格基準: 同期関数への誤指摘、意図的 fire-and-forget への指摘、効率(並列化)の提案の混入。

## 人間に返す条件(Human Handoff)

- 競合の成立が実行環境の並行度・呼び出し頻度に依存し、コードだけでは判定できない場合。
- キュー・ロック等の外部機構で直列化されている可能性がある場合(設計意図の確認が必要)。

## Execution Steps / 実行ステップ

1. **Gate**: 差分に async / await / Promise の追加・変更があるか確認。なければ`NO_REVIEW`を返す
2. **Analyze**: Rule の5パターンで差分を走査し、呼び出し先の Promise 性を code_search で確認。False-positive guards を適用
3. **Output**: 確定バグを findings、タイミング・文脈依存を questions として出力