ヘルスケア評価ハーネス — 患者安全検証 は何をしますか?
医療アプリケーションのデプロイメントのための自動検証システム。1つのCRITICAL障害でデプロイがブロックされます。患者安全は譲れません。
注: 例ではJestを参照テストランナーとして使用しています。コマンドは使用しているフレームワーク(Vitest、pytest、PHPUnitなど)に合わせて適宜変更してください。テストカテゴリと合格率のしきい値はフレームワークに依存しません。
使用すべきタイミング
- EMR/EHRアプリケーションのデプロイメント前
- CDSSロジック(薬物相互作用、投与量検証、スコアリング)を変更した後
- 患者データに触れるデータベーススキーマを変更した後
- 認証またはアクセス制御を変更した後
- 医療アプリケーションのCI/CDパイプライン設定時
- 臨床モジュールのマージコンフリクト解決後
仕組み
評価ハーネスは5つのテストカテゴリを順番に実行します。最初の3つ(CDSS精度、PHI露呈、データ整合性)はCRITICALゲートで、100%の合格率が必須です。1つでも失敗するとデプロイがブロックされます。残りの2つ(臨床ワークフロー、統合)はHIGHゲートで、95%以上の合格率が必要です。
各カテゴリはJestのテストパスパターンに対応しています。CIパイプラインはCRITICALゲートを--bail(最初の失敗で停止)で実行し、--coverage --coverageThresholdでカバレッジしきい値を適用します。
評価カテゴリ
1. CDSS精度 (CRITICAL — 100%必須)
すべての臨床意思決定支援ロジックをテストします:薬物相互作用ペア(双方向)、投与量検証ルール、公開仕様との臨床スコアリング、偽陰性なし、サイレント障害なし。
npx jest --testPathPattern='tests/cdss' --bail --ci --coverage
2. PHI露呈 (CRITICAL — 100%必須)
保護健康情報の漏洩をテストします:APIエラーレスポンス、コンソール出力、URLパラメータ、ブラウザストレージ、施設間の分離、未認証アクセス、サービスロールキーの不在。
npx jest --testPathPattern='tests/security/phi' --bail --ci
3. データ整合性 (CRITICAL — 100%必須)
臨床データの安全性をテストします:ロックされた encounters、監査証跡エントリ、カスケード削除保護、同時編集処理、孤立レコードなし。
npx jest --testPathPattern='tests/data-integrity' --bail --ci
4. 臨床ワークフロー (HIGH — 95%以上必須)
エンドツーエンドのフローをテストします:encounter ライフサイクル、テンプレートレンダリング、投薬セット、薬物/診断検索、処方PDF、警告フラグアラート。
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$tmp_json" || true
total=$(jq '.numTotalTests // 0' "$tmp_json")
passed=$(jq '.numPassedTests // 0' "$tmp_json")
if [ "$total" -eq 0 ]; then
echo "No clinical tests found" >&2
exit 1
fi
rate=$(echo "scale=2; $passed * 100 / $total" | bc)
echo "Clinical pass rate: ${rate}% ($passed/$total)"
5. 統合コンプライアンス (HIGH — 95%以上必須)
外部システムをテストします:HL7メッセージ解析 (v2.x)、FHIR検証、ラボ結果マッピング、不正形式メッセージ処理。
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/integration' --ci --json --outputFile="$tmp_json" || true
total=$(jq '.numTotalTests // 0' "$tmp_json")
passed=$(jq '.numPassedTests // 0' "$tmp_json")
if [ "$total" -eq 0 ]; then
echo "No integration tests found" >&2
exit 1
fi
rate=$(echo "scale=2; $passed * 100 / $total" | bc)
echo "Integration pass rate: ${rate}% ($passed/$total)"
合格/不合格マトリックス
| カテゴリ | しきい値 | 失敗時の動作 |
|---|---|---|
| CDSS精度 | 100% | デプロイをブロック |
| PHI露呈 | 100% | デプロイをブロック |
| データ整合性 | 100% | デプロイをブロック |
| 臨床ワークフロー | 95%+ | 警告、レビュー付きで許可 |
| 統合 | 95%+ | 警告、レビュー付きで許可 |
CI/CD連携
name: Healthcare Safety Gate
on: [push, pull_request]
jobs:
safety-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
# CRITICAL gates — 100% required, bail on first failure
- name: CDSS Accuracy
run: npx jest --testPathPattern='tests/cdss' --bail --ci --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'
- name: PHI Exposure Check
run: npx jest --testPathPattern='tests/security/phi' --bail --ci
- name: Data Integrity
run: npx jest --testPathPattern='tests/data-integrity' --bail --ci
# HIGH gates — 95%+ required, custom threshold check
- name: Clinical Workflows
run: |
TMP_JSON=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$TMP_JSON" || true
TOTAL=$(jq '.numTotalTests // 0' "$TMP_JSON")
PASSED=$(jq '.numPassedTests // 0' "$TMP_JSON")
if [ "$TOTAL" -eq 0 ]; then
echo "::error::No clinical tests found"; exit 1
fi
RATE=$(echo "scale=2; $PASSED * 100 / $TOTAL" | bc)
echo "Pass rate: ${RATE}% ($PASSED/$TOTAL)"
if (( $(echo "$RATE < 95" | bc -l) )); then
echo "::warning::Clinical pass rate ${RATE}% below 95%"
fi
- name: Integration Compliance
run: |
TMP_JSON=$(mktemp)
npx jest --testPathPattern='tests/integration' --ci --json --outputFile="$TMP_JSON" || true
TOTAL=$(jq '.numTotalTests // 0' "$TMP_JSON")
PASSED=$(jq '.numPassedTests // 0' "$TMP_JSON")
if [ "$TOTAL" -eq 0 ]; then
echo "::error::No integration tests found"; exit 1
fi
RATE=$(echo "scale=2; $PASSED * 100 / $TOTAL" | bc)
echo "Pass rate: ${RATE}% ($PASSED/$TOTAL)"
if (( $(echo "$RATE < 95" | bc -l) )); then
echo "::warning::Integration pass rate ${RATE}% below 95%"
fi
アンチパターン
- 「前回パスしたから」という理由でCDSSテストをスキップする
- CRITICALのしきい値を100%未満に設定する
- CRITICALテストスイートで
--no-bailを使用する - 統合テストでCDSSエンジンをモックする(実際のロジックをテストする必要あり)
- 安全ゲートが赤の状態でデプロイを許可する
- CDSSスイートで
--coverageなしでテストを実行する
例
例1: すべてのクリティカルゲートをローカルで実行
npx jest --testPathPattern='tests/cdss' --bail --ci --coverage && \
npx jest --testPathPattern='tests/security/phi' --bail --ci && \
npx jest --testPathPattern='tests/data-integrity' --bail --ci
例2: HIGHゲートの合格率を確認
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$tmp_json" || true
jq '{
passed: (.numPassedTests // 0),
total: (.numTotalTests // 0),
rate: (if (.numTotalTests // 0) == 0 then 0 else ((.numPassedTests // 0) / (.numTotalTests // 1) * 100) end)
}' "$tmp_json"
# Expected: { "passed": 21, "total": 22, "rate": 95.45 }
例3: 評価レポート
## Healthcare Eval: 2026-03-27 [commit abc1234]
### Patient Safety: PASS
| カテゴリ | テスト数 | パス | 失敗 | ステータス |
|----------|---------|------|------|----------|
| CDSS精度 | 39 | 39 | 0 | PASS |
| PHI露呈 | 8 | 8 | 0 | PASS |
| データ整合性 | 12 | 12 | 0 | PASS |
| 臨床ワークフロー | 22 | 21 | 1 | 95.5% PASS |
| 統合 | 6 | 6 | 0 | PASS |
### カバレッジ: 84% (目標: 80%以上)
### 判定: 安全にデプロイ可能