/**
* `devices.maker_id` / `model_name` の組み合わせが、対応機種レジストリ(`ROBOT_MODELS`)に
* 登録済みかどうかを判定する(指示書N / D-087)。
*
* ★設定値は `lib/config`、それを読む純粋関数は `lib/format`★ — `lib/format/contract.ts` と
* 同じ分け方。機種の組み合わせをこの関数の中に直書きしないこと。
*
* ★`lib/judge/` には置かない★ — あそこは ◎○△× / L1〜L3 / KPI / 丸めの置き場所(CLAUDE.md §9.1)。
* こちらは「静的な対応表を引くだけ」で、DB由来の実測値に対する評価ではない。
*
* 実データの表記ゆれに備え、比較前に前後の空白を除去し大文字小文字を揃えてから
* 完全一致で判定する(指示書K の B2 判定と同じ考え方 — 実データが何を返すか
* 分からないので、正規化してから完全一致で判定する)。部分一致はしない
* ("CC10" が "CC1" にヒットしてはいけない)。
*/
import { ROBOT_MODELS } from "@/lib/config";
function normalize(value: string): string {
return value.trim().toUpperCase();
}
/**
* DB アクセスなし・例外を投げない純粋関数。
* レジストリに無い組み合わせ(完全に未知の機種を含む)は `false` を返す。
*/
export function isSupportedModel(maker: string, model: string): boolean {
const normalizedMaker = normalize(maker);
const normalizedModel = normalize(model);
return ROBOT_MODELS.some(
(entry) =>
entry.supported &&
normalize(entry.maker) === normalizedMaker &&
normalize(entry.model) === normalizedModel
);
}
/**
* `devices.model_name` の先頭にメーカー名が入っていたら外す(例 メーカー `"PUDU"`・機種 `"PUDU CC1"` → `"CC1"`)。
*
* ★ステージングの `devices.model_name` は `"PUDU CC1"`(メーカー名込み)★(2026-10-29 実測・先方投入)。
* そのまま `"<メーカー名> <機種名>"` に連結すると「PUDU PUDU CC1」になり、`isSupportedModel()` も
* 機種 `"PUDU CC1"` を `ROBOT_MODELS` の `"CC1"` と照合できない(ユーザー指示 2026-10-29「アプリ側でメーカー名を重ねないようにして」)。
* - 大文字小文字・前後の空白を無視して「メーカー名+空白」で始まるときだけ外す(`"PUDUX1"` は外さない)
* - 外した残りが空なら元の値のまま返す。メーカー名で始まらなければ元の値のまま返す
*/
export function stripMakerPrefix(maker: string, model: string): string {
const trimmedModel = model.trim();
const prefix = `${normalize(maker)} `;
if (normalize(maker) === "" || !trimmedModel.toUpperCase().startsWith(prefix)) return model;
const rest = trimmedModel.slice(prefix.length).trim();
return rest === "" ? model : rest;
}