code-review
Freeプロジェクトガイドラインへの準拠をチェックし、バグ、スタイル違反、コード品質問題を検出する。PRレビュー時に使用。
The English summary is being prepared. Showing the original description.
Enforces error handling standards: silent error prohibition, custom error class hierarchy (AppError base with category never-fallback / transient / permanent, cause preservation, ValidationError / UnauthorizedError / UpstreamError etc. — canonical definitions in ERRORS.md), external-boundary normalization (normalizeExternalError), Result pattern (Result.ok/Result.fail), proper try-catch with error type checking, structured error logging with a single Logger contract, fallback prohibition categories (isNeverFallback), and HTTP status code mapping. Use when implementing error handling, reviewing catch blocks, or designing error responses.
The English summary is being prepared. Showing the original description.
See how to installReview the instructions the agent will receive before you install.
サイレントエラーゼロトレランスを原則とし、すべてのエラーを適切に分類・処理・記録するためのスキル。 ERRORS.md、PATTERNS.md のセクション 9 および FALLBACK.md で定義されたパターンを適用する。
以下のパターンはすべて禁止:
// ❌ 空の catch ブロック
try {
doSomething();
} catch (e) {}
// ❌ console.log のみでエラーを握りつぶし
try {
doSomething();
} catch (e) {
console.log(e);
}
// ❌ エラーを無視して null/undefined を返す
try {
return fetchData();
} catch (e) {
return null;
}
// ❌ 汎用的すぎるエラーメッセージ
throw new Error("Something went wrong");
すべての catch ブロックは、エラーの記録、再スロー、またはResult.fail での返却のいずれかを行うこと。
例外: 環境分岐付きフォールバック(セクション8参照)は本番環境のみで許容される。無条件のフォールバックは禁止。
プロジェクトでは AppError を基底クラスとしたエラー階層を使用する。定義の正典は ERRORS.md(本ファイルには基底クラスと 1 例だけを載せ、サブクラスの全一覧は複製しない — 複製は必ずドリフトする):
// options.cause で元エラーを保持する(ES2022 Error.cause。tsconfig の lib に ES2022 が必要)
type AppErrorOptions = { cause?: unknown };
// 分類。フォールバック可否・再試行可否は statusCode から推測せず、各サブクラスが宣言する
type ErrorCategory = "never-fallback" | "transient" | "permanent";
abstract class AppError extends Error {
abstract readonly category: ErrorCategory;
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number,
options?: AppErrorOptions,
) {
super(message, options);
this.name = this.constructor.name;
}
}
// バリデーション詳細(any を使わない / MASTER.md)。ERRORS.md と同じ形状
interface ValidationDetail {
field: string;
message: string;
constraint?: string;
}
// サブクラスの例(他の NotFoundError / ForbiddenError / ConflictError / UnauthorizedError /
// SecurityError / InternalError / UpstreamError / UpstreamRejectedError / UnknownExternalError は ERRORS.md)
// HTTP_STATUS は ERRORS.md で定義(`./errors` から import)
class ValidationError extends AppError {
readonly category: ErrorCategory = "never-fallback";
constructor(
message: string,
public readonly details: readonly ValidationDetail[],
options?: AppErrorOptions,
) {
super(message, "VALIDATION_ERROR", HTTP_STATUS.BAD_REQUEST, options);
}
}
| エラークラス | エラーコード | HTTP ステータス | 分類 | 用途 |
|---|---|---|---|---|
| ValidationError | VALIDATION_ERROR | 400 | never-fallback | 入力バリデーション失敗 |
| UnauthorizedError | UNAUTHORIZED | 401 | never-fallback | 未認証 |
| ForbiddenError | FORBIDDEN | 403 | never-fallback | 権限不足 |
| SecurityError | SECURITY_VIOLATION | 403 | never-fallback | 署名不一致・改ざん検知 |
| NotFoundError | NOT_FOUND | 404 | permanent | リソース未検出 |
| ConflictError | CONFLICT | 409 | never-fallback | 重複・競合 |
| InternalError | INTERNAL_ERROR | 500 | permanent | 予期しない内部エラー |
| UpstreamError | UPSTREAM_UNAVAILABLE | 502 | transient | 外部サービスの一時障害(再試行可) |
| UpstreamRejectedError | UPSTREAM_REJECTED | 502 | never-fallback | 外部サービスによる恒久的な拒否(自コードの要求誤り。本番でフォールバックしない) |
| UnknownExternalError | UNKNOWN_EXTERNAL_ERROR | 502 | never-fallback | 原因不明の外部エラー(推測で再試行・フォールバックしない) |
すべて ERRORS.md で定義済み。新しいエラー種別が必要な場合は、必ず AppError を継承し category を宣言して作成する(宣言しないとコンパイルエラーになる)。
ビジネスロジックでは例外スローではなく Result パターンを優先する:
// Result 型
type Result<T> = { ok: true; value: T } | { ok: false; error: AppError };
const Result = {
ok: <T>(value: T): Result<T> => ({ ok: true, value }),
fail: <T>(error: AppError): Result<T> => ({ ok: false, error }),
};
// 使用例
async function processUser(userId: string): Promise<Result<User>> {
try {
const user = await userRepository.findById(userId);
if (!user) {
return Result.fail(new NotFoundError("User not found"));
}
const processed = await processUserData(user);
return Result.ok(processed);
} catch (error) {
logger.error("Failed to process user", error, { userId });
if (error instanceof AppError) {
return Result.fail(error);
}
return Result.fail(
new InternalError("Processing failed", { cause: error }),
);
}
}
Result パターンのメリット:
// ✅ 良い例: 外部 SDK / HTTP の境界で正規化し、エラー型に応じて処理
try {
await riskyOperation();
} catch (error) {
const normalized = normalizeExternalError(error);
if (normalized instanceof ValidationError) {
return Result.fail(normalized); // そのまま返却
}
if (normalized instanceof NotFoundError) {
// warn の meta に Error 実体は入れない(Logger 規約 / PATTERNS.md §9)
logger.warn("Resource not found", { code: normalized.code });
return Result.fail(normalized);
}
logger.error("External operation failed", error);
return Result.fail(normalized);
}
// ❌ 悪い例: 汎用的な catch のみ
try {
await riskyOperation();
} catch (error) {
throw new Error("Failed"); // 元のエラー情報が失われる
}
// ✅ 外部境界で再スローするなら分類と元の cause を保持する
try {
await riskyOperation();
} catch (error) {
throw normalizeExternalError(error);
}
ルール:
instanceof でエラー型をチェックInternalError でラップして再スロー({ cause } で元の値を保持)。分類不能な外部エラーは normalizeExternalError() に渡し UnknownExternalError(never-fallback)にするnormalizeExternalError()(ERRORS.md)により AppError へ正規化するエラーログは JSON 形式で構造化し、必要なコンテキストを含めること。呼び出し規約はテンプレート全体で 1 つで、**正典(interface Logger)と実装例(JsonLogger)は PATTERNS.md §9「ログパターン」**にある。ここには複製せず、規約だけを示す:
error(message, error, meta?) — 第 2 引数は unknown。元の値をそのまま渡し、PATTERNS.md §9 の serializeError で構造化するwarn(message, meta?) / info(message, meta?) — meta は構造化コンテキスト。Error 実体は入れない(name / code だけ載せる)// 使用例
try {
await riskyOperation(userId);
} catch (error) {
logger.error("Failed to process user", error, {
userId,
operation: "riskyOperation",
requestId: req.headers["x-request-id"],
});
}
ログの必須フィールド:
level: エラーレベル(error / warn / info)message: 人間が読めるエラー説明error: serializeError() が返す構造化情報。Error は name / message / stack、非 Error は status / body または shape など、実際に取得できたフィールドを記録する(欠けた情報を作らない)timestamp: ISO 8601 形式禁止事項:
エラーハンドリングのコードレビュー時に確認する項目:
instanceof でエラー型をチェックしているかInternalError、分類不能な外部エラーは UnknownExternalError として区別し、元の cause を保持しているか包括的なフォールバック戦略(階層モデル・レイヤー別パターン含む)は FALLBACK.md を参照。
AI(Claude Code, Copilot, Cursor等)は try-catch + デフォルト値返却を自動挿入する傾向がある。
このパターンは開発中のバグを隠蔽し、本番で初めて問題が発覚するリスクを生む。
// ❌ パターン1: 空 catch + デフォルト値
try {
return await fetchData();
} catch {
return defaultValue;
}
// ❌ パターン2: エラー無視 + 空配列/空文字
try {
return await getItems();
} catch {
return [];
}
// ❌ パターン3: catch 内で console.log のみ + フォールバック
try {
return await getData();
} catch (e) {
console.log(e);
return fallbackData;
}
// ❌ パターン4: Promise.catch() でサイレントフォールバック
const data = await fetchData().catch(() => defaultValue);
フォールバックが必要な場合は、fallbackInProdOnly() ユーティリティ(推奨)または環境分岐を使用する:
// ✅ 推奨: ユーティリティを使う(禁止カテゴリの判定を内蔵している)。
// 引数は AppError に限定されるので、HTTP 境界の生エラーは normalizeExternalError() を通す
try {
return await fetchData();
} catch (error) {
return fallbackInProdOnly(defaultValue, normalizeExternalError(error), {
operation: "fetchData",
});
}
// △ インライン環境分岐(カスタムログが必要な場合のみ)
// 素の環境分岐は「フォールバック禁止カテゴリ」の判定を持たないため、
// 認証・認可・バリデーション・データ整合性・セキュリティ・上流の恒久的な拒否のエラーが
// 本番で握りつぶされる。この形を使うなら禁止カテゴリの判定を必ず添える。
try {
return await fetchData();
} catch (error) {
const normalizedError = normalizeExternalError(error);
logger.error("Failed to fetch data", normalizedError, {
operation: "fetchData",
});
// 禁止カテゴリは環境に関係なく常にスロー(FALLBACK.md Section 1 / §4 の isNeverFallback)。
// 判定を自前で再実装しない — 禁止カテゴリの定義が変わったときに取り残される
if (isNeverFallback(normalizedError)) {
throw normalizedError;
}
const env = process.env.NODE_ENV;
if (env !== "production") {
throw normalizedError; // 未設定・未知の値・開発・テストは fail-fast
}
return defaultValue; // 本番時のみ: UX保護
}
| 状況 | 対応 |
|---|---|
| catch 内でデフォルト値を返している | 環境分岐を追加するよう指摘 |
.catch(() => default) パターン | try-catch + 環境分岐に書き換え |
| 認証/認可/バリデーション/データ整合性/セキュリティ/上流の恒久的な拒否のエラーにフォールバック | 環境問わずスローに修正 |
既に fallbackInProdOnly() を使用 | OK(ログ記録・エラー正規化を確認) |
| 環境分岐のみ(禁止カテゴリの判定なし) | 禁止カテゴリの判定を追加するよう指摘 |
| フォールバックが明示的にビジネス要件 | コメントで理由を明記させる |
No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
プロジェクトガイドラインへの準拠をチェックし、バグ、スタイル違反、コード品質問題を検出する。PRレビュー時に使用。
The English summary is being prepared. Showing the original description.
Enforces project coding standards during code review: naming conventions (PascalCase for classes, camelCase for methods/variables, UPPER_SNAKE_CASE for constants, kebab-case for files), standard file structure, anti-magic-number policy, file size limits (500/800 lines), security patterns, and design patterns. Use when reviewing code, writing new code, or checking adherence to project conventions.
The English summary is being prepared. Showing the original description.
機能を保持したまま不要な複雑性を排除し、コードの簡潔性と可読性を向上させる。30行超の関数や3段以上のネスト検出時に使用。
The English summary is being prepared. Showing the original description.
コードコメントの正確性、完全性、長期的な保守性を分析する。JSDoc、コメント、README等のドキュメントが変更された場合に使用。
The English summary is being prepared. Showing the original description.
サイレント失敗を検出し、堅牢なエラーハンドリングを確保する。PRレビューでのエラーハンドリング検査時に使用。
The English summary is being prepared. Showing the original description.
Creates and reviews agent skills safely by enforcing deletion-prevention harness rules: no fixed absolute temp paths, no cwd-dependent cleanup, no wildcard deletes, no workspace-external file operations, no silent cleanup failures, and mandatory temp-root validation before any destructive command. Use when creating a new skill, updating an existing SKILL.md, or reviewing prompts/runbooks that include temp files, extraction, cleanup, PowerShell, bash, rm, del, Remove-Item, or archive expansion.
The English summary is being prepared. Showing the original description.