📚 本記事は 4 本シリーズの第 3 回です。
1. UTAGE API/MCPの実装制限と外部連携の現実解
2. Vercel/XServerのデプロイ先誤認を防ぐDNS確認手順
3. (現在) 診断ツールのタイプ判定アルゴリズム5つの落とし穴 ← この記事
4. SPF/DKIM/DMARCのGmail全PASS設定方法
5 月 5 日、午後 4 時 過ぎ。新規公開した診断ツールを回したユーザーから、画面のスクリーンショット付きで指摘が来ました。
チャートと回答がおかしくないか? なぜ?
筋力集客力が 15 あるのに 新規集客が弱いってどういうこと?
どういう判断ロジックなん?
確かに、レーダーには「筋力(集客力) 15/20」と高得点が表示されているのに、判定タイプは「ガリガリ型(筋肉不足、新規集客が弱い状態)」。矛盾しています。本記事は、この破綻を構造的に分析し、再設計するまでの 30 分の記録です。
何が起きていたか — 旧ロジックの限界
旧ロジックは極めて単純でした。
``typescript`
// 旧版 (壊れていた)
function determineType(axisScore, total) {
// 合計スコアの範囲だけで判定
if (total <= 30) return "A"; // メタボ型
if (total <= 50) return "B"; // ガリガリ型
if (total <= 65) return "C"; // 標準型
if (total <= 80) return "D"; // マッチョ型
return "E"; // 細マッチョ予備軍
}
5 軸(体脂肪率・筋力・持久力・骨格・神経系)それぞれを 0-20 点で算出し、合計 0-100 点の範囲でタイプに振り分ける、という素直な設計です。多くの診断クイズもこの作りで動いています。
問題が起きたユーザーのスコアは以下でした。
| 軸 | 値 | 解釈 |
|---|---|---|
| 体脂肪率(効率) | 0 | 贅肉だらけ・最悪 |
| 筋力(集客力) | 15 | 高い・強い |
| 持久力(適応力) | 4 | 低い |
| 骨格(基盤) | 10 | 普通 |
| 神経系(判断速度) | 16 | 高い |
| 合計 | 45 | ガリガリ型レンジ(31-50)に該当 |
合計 45 点 → ガリガリ型(筋肉不足) と判定された一方で、実際の筋力は 15 点と高水準。判定タイプの説明文「筋肉不足、新規集客が弱い状態」とユーザーの体感が完全に乖離していました。
💡 KEY TAKEAWAYS
合計スコア型は「軸別の偏り」を情報として捨ててしまう設計です。同じ合計 45 点でも、5 軸均等な人と 1 軸極端に低い人ではプロファイルが全く違います。タイプ説明と実態が合わないのは当然の帰結でした。
再設計 — プロファイル解析型へ
修正方針は 2 つでした。
- 軸の偏りを優先順位付きルールで判定する
- 判定理由テキストを自動生成して結果画面に表示する

新しい優先順位ルール(6 段階)
`typescript
// 新版 (プロファイル解析型)
function determineType(axes, total) {
const { fat, muscle, stamina, bone, nerve } = axes;
const min = Math.min(fat, muscle, stamina, bone, nerve);
const max = Math.max(fat, muscle, stamina, bone, nerve);
// 1. 全軸が高水準
if (min >= 14) return { type: "E", reason: "5軸すべて14点以上の高水準" };
// 2. 集客力は高いが贅肉or鈍重
if (muscle >= 14 && (fat <= 10 || nerve <= 10)) {
const issue = fat <= 10 ? "効率の低さ" : "判断速度の鈍さ";
return { type: "D", reason: 集客力(筋力${muscle})は高水準だが、${issue}が次の成長の足かせ };
}
// 3. 効率が突出して悪い
if (fat <= 6) return { type: "A", reason: 体脂肪率${fat}点という低さが突出 };
// 4. 集客が突出して弱い
if (muscle <= 8 && fat >= 8) return { type: "B", reason: 効率は悪くないが集客力${muscle}が極端に弱い };
// 5. バランス型(全軸の差が4以内)
if (max - min <= 4) return { type: "C", reason: 5軸全てが${min}〜${max}でフラット };
// 6. フォールバック: 合計スコアで判定
if (total <= 40) return { type: "A", reason: 総合${total}点と低水準 };集客力強化が次の成長の鍵
if (total <= 55) return { type: "B", reason: };売上力はあるが機動性に課題
if (total >= 75) return { type: "D", reason: };`
return { type: "C", reason: "中庸プロファイル" };
}
問題のユーザーケース(0, 15, 4, 10, 16)を新ロジックに通すと:
- ステップ 1: min = 0 で 14 未満 → E ではない
- ステップ 2: muscle = 15 ≥ 14 && fat = 0 ≤ 10 → D マッチョ型
- 判定理由: 「集客力(筋力 15)は高水準だが、効率(体脂肪率 0)の低さが次の成長の足かせ」
矛盾感が解消されました。「集客力ある中堅企業だが、業務膨張で機動力が落ちている」 という典型的な「マッチョ型」プロファイルに合致する判定になりました。
判定理由テキストの効果
各ルールに reason` フィールドを持たせ、結果画面に「🧠 なぜこのタイプと判定されたか」セクションとして表示しました。

これだけで以下の 3 つが同時に解決しました。
- 納得感: ユーザーが「なぜ?」と思った瞬間に答えがある
- 教育効果: 5 軸スコアの読み解き方を自然に学べる
- 行動への接続: 「○○ の低さが足かせ」と書いてあるので「○○ を改善すべき」と直結する
💡 KEY TAKEAWAYS
診断結果は「タイプ名」だけでは不十分です。「なぜそう判定したか」を 1 行で示すことで、ユーザーの納得感とその後の行動意欲が両方上がります。
設計の落とし穴 5 個
このプロセスで気づいた、診断クイズ設計時の頻出落とし穴を共有します。
落とし穴 1: 「合計スコア型」を最初に選んでしまう
実装が単純なので最初の選択肢になりがちですが、5 軸あるなら 5 軸の偏りを情報として活用すべきです。Day 1 から優先順位ルール型で設計するのが正解です。
突破: 各タイプの「定義条件」を先に言語化(「マッチョ型 = 売上ある中堅企業の業務膨張」)し、それを軸スコアの数式に翻訳します。
落とし穴 2: 軸名の比喩が直感に逆行する
「体脂肪率」は値が高い=贅肉が少ない、という意味で設計しましたが、医学的な感覚とは逆です。レーダーで「体脂肪率 18/20」と出ても、ユーザーが「贅肉だらけ?」「贅肉少ない?」のどちらか即判別できないリスクがあります。
突破: 軸ラベル横に「(効率)」「(集客力)」「(基盤)」などの 直感的な補助テキスト を置きます。比喩のブランド力を保ちつつ、解釈ミスを減らせます。
落とし穴 3: 判定理由がない結果画面
結果画面が「あなたはガリガリ型です」だけで終わると、ユーザーは納得できません。「なぜ」が常に必要 です。
突破: 各ルールに reason フィールドを持たせ、自動生成テキストで表示します。手書きで全パターン用意する必要はなく、変数埋込で十分です。
落とし穴 4: タイプ間の境界が曖昧
合計 50 点と 51 点で B → C に切り替わる、というレンジ判定は、ユーザーにとって不公平感を生みます。「もう 1 点高ければ別のタイプだったのに…」と。
突破: 範囲マッピングではなく 特徴量で判定 することで、境界の納得感が上がります。「muscle ≥ 14 かつ fat ≤ 10 ならマッチョ型」のように、明示的な閾値を持つルールにします。
落とし穴 5: 業種別カスタマイズなしの設計
5 軸の意味が業種で大きく違います。サービス業の「効率」と製造業の「効率」では指す業務が異なるからです。
突破: 共通質問 6 + 業種別質問 2 の構成にし、業種選択をクイズ最初の Q0 に置きます。質問の言語が業種に最適化されると、回答精度と納得感が同時に上がります。
修正にかかった時間 — 30 分
具体的な作業時間の内訳は以下です。
| 工程 | 所要 |
|---|---|
| ユーザー指摘の理解 + 矛盾点の構造化 | 5 分 |
| 新ロジック設計(優先順位 6 段) | 10 分 |
実装(data.ts 修正・reason フィールド追加) | 5 分 |
| UI 修正(判定理由カード追加) | 5 分 |
| ローカルビルド + 本番デプロイ | 5 分 |
| 合計 | 30 分 |
最も価値が高かったのは「ユーザーの一言指摘」でした。設計者が気づかない盲点を、ユーザーは 1 回触っただけで看破します。これは AI ペアプロでも変わらず、人間ユーザーの審美眼が品質を決定づけます。
完成版コードの全文(data.ts 抜粋)
``typescript
export type ScoreResult = {
total: number;
axisScore: Record
type: TypeId;
reason: string; // 新規追加
};
function determineType(
axisScore: Record
total: number
): { type: TypeId; reason: string } {
const { fat, muscle, stamina, bone, nerve } = axisScore;
const values = [fat, muscle, stamina, bone, nerve];
const min = Math.min(...values);
const max = Math.max(...values);
if (min >= 14) {
return { type: "E", reason: 5軸すべてが14点以上の高水準。最適化の最終段階に到達。 };効率(${fat})と判断速度(${nerve})の両方の低さ
}
if (muscle >= 14 && (fat <= 10 || nerve <= 10)) {
const issue = fat <= 10 && nerve <= 10
? 効率(体脂肪率${fat})の低さ
: fat <= 10 ? : 判断速度(神経系${nerve})の鈍さ;集客力(筋力${muscle})は高水準だが、${issue}が次の成長の足かせ。
return { type: "D", reason: };体脂肪率(効率)${fat}点という低さが突出。無駄業務を削ぎ落とすことが最優先。
}
if (fat <= 6) {
return { type: "A", reason: };効率(${fat})は悪くないが、集客力(筋力${muscle})が極端に弱い。
}
if (muscle <= 8 && fat >= 8) {
return { type: "B", reason: };5軸すべてが${min}〜${max}点でフラット。
}
if (max - min <= 4) {
return { type: "C", reason: };総合${total}点と低水準。
}
if (total <= 40) return { type: "A", reason: };総合${total}点。集客強化で大きく伸びる余地あり。
if (total <= 55) return { type: "B", reason: };総合${total}点と高め。組織機動力の最適化で次のステージへ。
if (total >= 75) return { type: "D", reason: };総合${total}点。中庸プロファイル。
return { type: "C", reason: };``
}
次のアクション
診断ツールのロジック設計は、「合計スコア型 → プロファイル解析型」の進化を一度経るのが定石です。最初から完璧な設計は不可能なので、ユーザーの指摘を受け取った瞬間に修正できる組織体力が重要になります。
御社が「ユーザーの一言で即直せる組織」か「気合と根性で対応する組織」かは、企業体型に直結します。細マッチョ企業診断 で 5 軸スコアを測ってみてください。神経系(判断速度)スコアが、こうした即応力の指標になります。
→ 次の記事: SPF/DKIM/DMARCのGmail全PASS設定方法
