キヨさんからの「SPI模試の仕様」照会への回答。コンテンツ(能力検査・性格検査)/供給システム(API・問題バンク配信基盤)/現時点の課題を一枚にまとめました。課題は隠さず全件記載しています(§4に23件)。記載はすべて 2026-07-23 時点の一次現物(本番URL実測・コード・データファイル)で裏どりし、確認できなかったものは unknown と明記しています。
v1.3(07-23夕方 更新)=本日の改修で解決した項目に「解決済み」を付け、実測で判明した数値の訂正と、検証で新たに見つかった課題を追記しました。
v1.4(2026-07-24 追記)=「Phase C=配信のサーバ一本化」に着手(当時ブランチ段階)。
v1.5(2026-07-25 追記)=Phase C を本番反映完了(LIVE)。あわせて第三者監査(GPT系)で見つかった公務員解説の選択肢番号バグを恒久修正し、再発防止の配信前ゲートを常設しました。詳細は §1 末尾の追記ブロックをご覧ください。外部提供API(B)の仕様・キーには一切影響しません(別線・変更なし)。
SPI模試は「①問題を作る」「②正本として版を固める」「③配る」の3層で構成されています。現在配信経路は4系統が並存しており、これが§4の課題の主因にもなっています。
current.json を CAS で切替qb-r2-20260724d を (A) 経由で配信api/exam/set/api/grade/finish を叩く。| 系統 | 実体 | いま何が起きているか(2026-07-25 実測) |
|---|---|---|
| (A) 出題worker spi-questions | spi-questions.komuin-sukima.workers.dev | fact稼働中・自社フロントの唯一の出題元。現行版 qb-r2-20260724d。本番で出題セット取得→60秒床→終了時採点を実測し、セット応答に答え・解説が含まれないことを確認。 |
| (B) 外部提供API SPI Platform API | educare-cbt-ingest.komuin-sukima.workers.dev | fact稼働中。/healthz 200・/openapi.json が OpenAPI 3.1.0 を返す。キヨさんが叩けるのはこれ。今回のフロント一本化とは別線・仕様/キー変更なし。 |
| (C) 自社フロント 体験模試(Web) | educarelog.net/spi-taiken/ | fact稼働中・一般公開。埋め込みバンクを全廃し (A) から取得(questions-api チャンクが (A) の api/exam/set/api/grade/finish を叩く・受験用チャンク約55KB・問題IDの同梱ゼロを本番実測)。 |
| (D) LINE内受験 LIFF版 | educare-poc.komuin-sukima.workers.dev | fact稼働中。同梱バンクを全廃し (A) から取得(SPAバンドルが (A) の api/exam/set/api/grade/finish を叩く・問題IDの同梱ゼロを本番実測)。 |
※ 4系統すべてが正本 (A/B は worker、C/D は (A) 経由) から同世代を配っている状態を本番実測で確認しました。かつての「正本と実配信のねじれ」(§4-1/§4-2 の直接原因)は解消されています。
上の (C)(D) が抱える2つの構造欠陥 ―― ①ブラウザに問題バンクを丸ごと同梱(16.4MB・世代ズレ/§4-8)、②答え・解説をクライアントに配って採点もクライアント側(§4-1) ―― を、フロントを (A) 出題worker へ配線し直すことで根絶しました。敏さんの決裁「答えはクライアントへ渡さない・採点はサーバ・オフライン非対応でよい」に基づく設計で、全工程を本番反映済みです。本番URLで実測(出題セット取得→60秒床→終了時採点)し、出題セット応答に答え・解説が含まれないことを確認しています。
| 工程 | 状態(2026-07-25) | 内容 |
|---|---|---|
| C-0 採点線の新設 | LIVE本番反映済 | 答えを読むのは非公開の採点専用worker(qb-scorer)だけにし、公開workerからは答えバケットのバインディングを物理的に外しました。出題セットに署名トークンを付け、「配られたセットの問題しか採点を受け付けない」ことで、§4系で指摘された正答の機械的な一括抽出(オラクル)を構造的に遮断。模試モードは終了時、単元練習モードのみ回答直後に正誤・解説を返します。第三者監査(GPT系)が1度差し戻し→是正→2回目で全項目クリア。 |
| C-1 Web体験模試(C)のfetch化 | LIVE本番反映済 | 埋め込みバンクを全廃し開始時に (A) から取得。受験用JSチャンクは 16.4MB → 55KB に激減(実測)。採点はサーバの採点APIへ。監査指摘の「通信失敗時に採点要求を再送し続ける」実バグは「失敗時は明示エラーで停止(再送しない)」に是正済み。 |
| C-2 LINE内受験(D)のfetch化 | LIVE本番反映済 | (C) と同型で LIFF 版の同梱バンクを廃止し (A) へ配線しました。C-1 の是正型を横展開。これにより (C)(D) の古いスナップショットは解消され、自社フロントは (A) 出題worker+サーバ採点の1経路へ統合されました。 |
※ 本番反映はデプロイゲート経由で完了しています。キヨさんが使う (B) 外部提供API には影響しません(別線・変更なし)。現行の正本リリースは qb-r2-20260724d です。
Phase C 本番反映後の第三者監査(GPT系の実受験チェック)で、公務員ラインの解説文が、答え自体は正しいのに「選択肢3は…」の番号が正答位置とずれ、範囲外の「選択肢0」を参照する不具合が見つかりました(採点は正常・解説文だけ誤り)。原因は、正答位置の偏りを直す並べ替えの際に、元の解説が問題ごとに「0から数える/1から数える」を混在させていた(1問の中で混在するものすらあった)ため、番号だけが取り残されたことです。SPI本体・SCOAは番号参照を使っておらず無傷でした。
| 対策 | 内容 |
|---|---|
| 解説の番号非依存化 | 「選択肢3」のような番号参照そのものを廃止し、選択肢の本文を引用する形(例:「〇〇である」の肢は誤り)へ機械変換。並べ替えても壊れない構造にしました。公務員538問を変換し、バンク全体の番号参照はゼロ(答え・選択肢の中身は変更なし)。 |
| 配信前ゲートの常設 | 版を組む段階で、解説に選択肢の番号参照が残っていないか+引用が答え・選択肢と一致するかを機械照合し、1問でも不整合があれば版を出せない(fail-closed)ようにしました。今後の生成でも番号参照は受け付けません。 |
| 本番実測 | 本番の出題→採点を実際に叩き、解説に番号参照0行・引用型解説で配信されていることを確認済み。系譜台帳(版の履歴)も更新済み。 |
※ あわせて、図から積み木の総数を一意に数えられない「積み木数え」40問(判断推理・空間把握の一部)を暫定で配信除外しています(図の作り方の改修は別工程)。この不具合は能力検査の非言語=(B) 外部提供APIにも同じ問題製造基盤を使うため、上記の番号非依存化とゲートは外部提供分にも同様に効きます(キー・エンドポイントの仕様変更はありません)。
fact全問が自社オリジナル生成(source: original/educare が7,537件中7,537件)。既存教材の複製は含みません。全問5択・全問解説ステップ付き(平均5.0ステップ・欠落0件)。
| 分野 | トピック | 問題数 | サブパターン(=出題型) |
|---|---|---|---|
| 非言語 6,765問 | 推論 | 1,000 | 10型:順序関係/位置関係/対応関係/リーグ戦/発言推理/正誤推論/命題と論理/数値推論/平均・順位推論/物の個数 |
| 旅人算 | 500 | 5型:出会い/追いつき/周回/通過算/流水算 | |
| 表の読み取り | 500 | 5型:合計・平均/増加額/増減率/構成比/比較・順位 | |
| 損益算 | 400 | 4型:基本損益/割引・値引/原価or定価の逆算/複数個・複数商品 | |
| 仕事算 | 400 | 4型:基本(2人共同)/3人以上/途中で人数変動/水槽 | |
| 確率 | 400 | 4型:基本確率/余事象/独立試行/反復試行 | |
| 整数の性質 | 400 | 4型:約数倍数/素因数分解/剰余/N進法 | |
| 割合と比 | 370 | 4型:増減率/比例配分/連比/食塩水濃度 | |
| 場合の数 | 344 | 4型:順列P/組合せC/円順列/重複順列 | |
| 集合 | 300 | 3型:2集合/3集合/キャロル表 | |
| 代金の精算 | 300 | 3型:割り勘(余り含む)/立替精算/複数人立替の最終精算 | |
| 分割払い | 300 | 3型:頭金+均等分割/手数料込み総額/分割回数を求める | |
| 鶴亀算 | 300 | 3型:基本(頭と足)/3種類/得点型(正解+・不正解−) | |
| 平均算 | 300 | 3型:加重平均/平均から合計や個別値/平均の増減から個別値 | |
| ニュートン算 | 300 | 3型:牧草と牛/給排水型/行列(窓口処理) | |
| 料金割引 | 250 | 3型:団体割引/セット割引/複数プラン比較 | |
| 年齢算 | 232 | 3型:現在年齢を比から/何年後に○倍/年齢差一定の応用 | |
| 時計算 | 169 | 3型:長針短針の角度/針が重なる時刻/針が直角or一直線 | |
| 言語 772問 | 文の並べ替え | 200 | 2型:正しい順序選択/N番目選択 |
| 空欄補充(接続詞) | 160 | 2型:接続詞補充/論理関係補充 | |
| 語句の意味 | 120 | 2型:文脈語義選択/近義語選択 | |
| 二語の関係 | 96 | 1型 | |
| 熟語の成り立ち | 84 | 1型 | |
| 語句の用法 | 80 | 1型:下線部用法選択 | |
| 文章理解 | 32 | 空欄補充12/内容合致・趣旨14/指示語6(長文14本・本文はsha256参照で別管理) |
| 分野 | 難易度1 | 2 | 3 | 4 | 5 | 計 |
|---|---|---|---|---|---|---|
| 非言語 | 1,174 | 2,348 | 2,185 | 709 | 349 | 6,765 |
| 言語 | 24 | 378 | 370 | 0 | 0 | 772 |
課題言語は難易度4・5が1問も存在しない(§4-6)。
解説は自由記述の文章ではなく5ステップの定型構造を持ちます(実測平均5.0ステップ)。①何の単元か → ②定義・考え方の言語化 → ③立式と時短のコツ → ④答え → ⑤ありがちミス、という並びです。この構造化により、後段のAI講師・図解生成の「燃料」として機械的に扱える設計にしています。
fact本番 educarelog.net で稼働中(本日、配信中のJSバンドルから45項目の実データを直接抽出して確認)。受験モードは体験/本番/単元練習/性格検査の4つで、性格検査は無料会員登録(LINEまたはGoogle)で解放される設計です。
| 項目 | 仕様 |
|---|---|
| 設問数・形式 | 45問/5件法リッカート(「まったく当てはまらない」〜「非常に当てはまる」) |
| 因子(ビッグファイブ) | 開放性8問/誠実性10問/外向性8問/協調性10問/情緒安定性9問 |
| SPI側面へのマッピング | 各因子スコアを重み付けして行動的側面・意欲的側面・情緒的側面・社会関係的側面の4側面へ変換(項目側にも aspect タグを保持:行動的12/意欲的8/情緒的12/社会関係的13) |
| 逆転項目 | 12問(スコア計算時に 6 − 回答値 で反転) |
| ライスケール(虚偽検出) | 5問。合計が閾値20を超えると「回答の一貫性に注意」の警告を結果画面に表示 |
| スコア算出 | 因子別平均 → 平均3・SD1を基準に偏差値換算(20〜80でクランプ) |
| 結果表示 | レーダーチャート+因子ごとの「強み/注意点/面接でのヒント」テキスト |
| 計測 | 1問回答ごとに personality_item_answered、完了時に personality_survey_complete(ライスケール合計・警告フラグ付き)を本番ingestへ送信。CBTイベントの domain は personality |
| 免責 | UI上に「ビッグファイブ理論に基づく簡易性格診断であり、採用結果や本番の判定を保証するものではない」旨を明示 |
結論:自作です。公開尺度を土台にはしていますが、項目文そのものは既存尺度の翻訳・翻案ではなく書き下ろしです。
id / factor / aspect / statement / reverse / lie_scale の6フィールドのみで、出典・ライセンスのメタデータ欄自体が存在しません。実装コミットのメッセージに「IPIP/Big Five土台」という一言があるだけで、どの項目がどの原典に対応するかの対応表はありません。結論:されていません。未実施のまま公開しています。
結論:受験者集団との比較ではありません。「5件法の理論的中点」との比較です。ここは誤解を招きやすいので明確にお伝えします。
偏差値 = 50 + 10 × (因子の平均回答値 − 3) ÷ 1 (20〜80でクランプ)結論:文言は既に存在し本番表示されていますが、出るのは結果画面だけです。受験前・受験中には保証を否定する文言がありません。
| 表示箇所 | 現行の文言(逐語) | 表示条件 |
|---|---|---|
| 能力検査トップの導入カード | ビッグファイブ理論に基づく簡易性格診断(SPI性格検査の練習用)。タイマーなし・戻る自由・正誤なし。 | 常時。保証否定の文言なし |
| 受験画面バッジ | ビッグファイブ理論に基づく簡易性格診断 | 回答中は常時 |
| 受験画面リード文 | 正誤やタイマーはありません。直感に近い選択肢を選んでください。戻って回答を変更できます。 | 回答中は常時。操作説明のみで免責語なし |
| 結果画面(唯一の実質的免責) | ビッグファイブ理論に基づく練習用の自己申告プロフィールです。採用結果や本番の判定を保証するものではありません。 | 45問完答後の結果画面のみ |
| ライスケール警告 | ライスケールが高めです。よく見せようとした回答が混ざると、面接準備に使う自己理解がずれやすくなります。 | ライスケール合計20以上のときのみ |
当社としての想定(ご意見をいただきたい点):現状は「結果を見た人にだけ免責が届く」構造なので、受験を開始する前の画面に同等の文言を出すのが妥当と考えています。あわせて、②③の実態を踏まえて次の3点を明示する案です。
※ 有料商材として提供する場合は、上記に加えて利用規約側にも同趣旨の条項が要ります(法務レーンで別途整理中)。
fact一般公開中の体験模試(/spi-taiken/)は、サーバに問題を取りに行かずビルド時にJSバンドルへ同梱された6,536問から出題しています。SPIだけでなく公務員試験科目も含むのが特徴です。
| 系統 | 分野 | 問題数 | 主なトピック |
|---|---|---|---|
| SPI系 (4,369問) | 非言語 | 3,839 | 推論1,050/集合350/損益算・旅人算・仕事算・料金割引・割合と比・場合の数・確率・表の読み取り・整数の性質 各250 ほか |
| 語彙 | 500 | 二語の関係250/熟語の成り立ち250 | |
| 言語 | 30 | 文章理解30 | |
| 公務員系 (2,167問) | 判断推理 | 955 | 位置関係106/対応関係103/順位100/嘘つき100/試合100/方位100/命題100/空間把握134 ほか |
| 資料解釈 | 519 | 実数割合144/構成比141/増加率125/指数109 | |
| 文章理解 | 351 | 現代文191/英文160 | |
| 自然科学 | 110 | 生物37/地学35 ほか | |
| 社会科学 | 110 | 経済37/法律29/政治28 ほか | |
| 人文科学/時事 | 110/12 | 日本史35 ほか/時事12 |
※ このバンクは正本(7,537問)とID体系は同じですが中身は別世代です。共通IDは3,408件ありますが、うち3,407件が別の問題を指しています(§4-1)。
komuin-webtest)はSPIと同一のバンクファイルを分野タグでフィルタして出題しています。公務員専用の問題ファイルは存在しません。さらに、試験種タグ(地方上級・警察・消防・国家一般・特別区・市役所)が付いている問題は6,536問中134問だけ(各試験種50〜72問)で、残りは試験種を問わない汎用出題です。これが意図的な設計か暫定措置かは、当社内でも記録が残っていません(§4-17)。
factSCOA(自治体で採用が広がっている総合適性検査)向けの体験模試を別ラインで開発済みですが、本番未公開(公開フラグ未反転・masterへ未マージ)。10問10分の軽量ランナーと段階アニメーション図解まで実装済みで、リリース前監査で公開ブロッカー4件が出て止めている状態です(§4-10)。
| 軸 | 内訳(全145問・全問5択・SCOA-A形式) |
|---|---|
| 尺度 | 論理 75/数理 36/常識 34 |
| 問題型 | 空間把握51・推論24・常識(自然科学)12・常識(社会科学)12・四則計算12・割合損益12・数列12・常識(時事)10 |
| 難易度 | 2:39/3:63/4:43 |
| 正答位置 | 0:31/1:34/2:33/3:18/4:29(偏りは軽微=SPI文章理解のような欠陥はなし) |
| 体験版レシピ | 10問=数理3+論理3(空間は最大1)+常識4/10分 |
| 検品 | 全数の機械検査PASS+外部AIによる抜き取り32/32一致。ブロッカー11件は在庫不足由来(正多面体型の枯渇9・時事在庫2)で誤答由来ではない |
課題SCOAは言語・英語の尺度が未開発のため体験版に含まれていません(§4-18)。
「どの単元をどれだけ持っているか/本試験でどれだけ出るか」を1系統で管理する台帳を正本化しています。感覚ではなく出題実績データで補充優先度を決めるための装置です。
| 構成要素 | 内容 |
|---|---|
| 単元マトリクス | 396行(数的処理88/言語7/自然科学301)。列=SPI在庫(完全一致/関連)×公務員出題頻度×出題周期×タネ状態×SCOA適用 |
| 出題実績インデックス | 数的処理3,977件(1994–2018・10試験種)/論文416設問(2009–2026)/自然科学200件/文章理解365行(2010–2025)=計4,958行 |
| 試験ブループリント | 試験種別(行政・国家総合・警察消防など)の単元重み表。重み合計=1.0に正規化。出題サンプラがこの重みで比例配分する |
| 台帳の実体 | 正本=Gitリポジトリ、D1(educare-content-ledger)は一方向レプリカ。全再構築方式で冪等性を担保 |
この台帳から出てくる示唆の例:計量図形は公務員試験で実績337回・ほぼ毎年出題(平均1.1年に1回)なのにSPI側の在庫は0問。不定方程式は2変数型が約1.4年に1回、3変数型が約3.7年に1回。こうした「頻度×在庫」の突き合わせで補充計画を機械的に立てています。
問題データの唯一の正本(SSOT)は、Cloudflare R2 に置く版ごとに不変なリリースです。D1・静的JSON・管理画面などのコピーはすべて「リリースIDで系譜が辿れる派生キャッシュ」に格下げしました。
| 設計要素 | 仕様 |
|---|---|
| バケット2本分離 | educare-question-bank(配信用)と educare-question-bank-answers(答え専用)を物理的に別バケットに。「配信・採点はAPI、答えは壁の裏」というIP境界を、アプリのロジックではなくデータの置き場所で強制する設計 |
| シャード分割軸 | group(arithmetic/inference/verbal)× topic の直積。NDJSON形式 |
| 長文の扱い | passages/{sha256}.json と content-addressed 化。同一本文の重複保存が原理的に起きない |
| 統一エンベロープ | record_type / schema_version / id / exam_family / scale / group / topic / subtype / bank_release_id / taxonomy_version / unit_id / mapping_accuracy / difficulty / stem / choices / passage_ref / figures / methods / family_ext / provenance |
| 単元系譜の焼き込み | リリース生成時に bank_release_id・taxonomy_version・unit_id・mapping_accuracy の4フィールドを単元マスタから機械導出して全問に付与。承認済みマッピングのみ採用し、未マップは null+unmapped と正直に記録 |
| 決定論性 | JSONは sort_keys, compact, ensure_ascii=false に正規化、行順はID昇順固定。同じ入力からは必ずバイト単位で同一のリリースが再生成される(2回ビルドしてバイト一致を検証済み) |
| 完全性検証 | manifest に全ファイルの sha256 と件数を事前集計。さらにシャードごとに id_set_sha256(含まれる問題ID集合のハッシュ)を持ち、配信用シャードと答えシャードのID整合を機械照合 |
| 版の切替 | current.json を ETag条件付き更新(Compare-And-Swap)で切替。競合時は412で失敗させる。オブジェクト投入は If-None-Match: * で新規のみ許可=既存版の上書きは不可能 |
| ロールバック | current.json に previous_release_id を保持。旧リリース本体はR2に残るので、ポインタを書き戻すだけで即座に戻せる |
| 現行版 | qb-r1-20260723(本日公開・65オブジェクト/10.8MB。前版 qb-r1-20260721) |
R2のリリースを読んで実際に問題を選ぶ層です。単なるランダムではなく、試験種の出題重みに比例した配分を行います。
| 機能 | 仕様 |
|---|---|
| データ解決 | current.json(60秒TTLでキャッシュ)→ manifest.json(sha256照合)→ 該当シャード。manifestのハッシュが合わなければ即エラー |
| 試験種重み駆動 | exam 指定時、ブループリントの単元重みに count × weight/総重み で比例配分。端数は重み降順に決定論的に配分 |
| 単元指定 | unit 指定時は mapping_accuracy = exact のみ採用(関連単元での代替はしない)。0件なら暗黙のフォールバックをせず空を返す |
| トピック偏り防止 | 1トピックが出題数の30%を超えないよう上限キャップ |
| 重複回避 | exclude_ids(最大200件)をクエリで受け取りステートレスに除外 |
| 既定配分 | 無指定時は arithmetic:inference:verbal = 50:25:25(単元練習モードのみ arithmetic 100%) |
| 障害時 | R2オブジェクト欠落・ハッシュ不一致・パース失敗はすべて HTTP 503。部分縮退やサイレントフォールバックはしないフェイルクローズ設計 |
fact本日 /healthz 200・/openapi.json(OpenAPI 3.1.0, title="SPI Platform API")配信を実測確認。Swagger UI も /docs で閲覧できます。
GET /v1/questions?limit=1 の pagination.total で実測。id / field / topic / difficulty / methods / stem / choices / source のみで、answer・explanation_steps の露出ゼロを実測確認。son-eki-0001 の問題文がローカル正本と完全一致(=§4-1の世代ズレはAPI経路では発生していない)。topic=文章理解 で total=0)。長文本文を保持する仕組みがAPI側テーブルに無いため、seed時に除外されています(§4-16)。二語の関係96問・推論1,000問は正本どおり配信。| メソッド/パス | 認証 | 概要 |
|---|---|---|
GET /healthz / GET /openapi.json / GET /docs | 不要 | ヘルスチェック・仕様書・Swagger UI |
GET /v1/questions | Bearer | 問題一覧(topic/limit≤50/offset)。ページング付き |
GET /v1/questions/{id} | Bearer | 問題単体取得 |
POST /v1/sessions | Bearer | 受験セッション開始。mode=taiken/honban/tanren。201+Location |
GET /v1/sessions/{id} | Bearer | セッション状態(出題数・回答数・ステータス) |
POST /v1/sessions/{id}/questions | Bearer | 次の設問を要求。未回答の保留設問があれば200で再返却(冪等)、新規は201 |
PUT /v1/sessions/{id}/questions/{item_id}/answer | Bearer | 解答送信(choice/elapsed_ms/timed_out)。即時正誤を返す。冪等 |
POST /v1/sessions/{id}/result | Bearer | 採点確定(初回201・以降200で同じ結果)。偏差値・グレード・分野別内訳 |
POST /v1/scores | Bearer | ステートレス採点(セッションを作らず解答配列を渡して採点)。domain=spi/personality |
POST /v1/events / POST /ingest | 任意/不要 | 受験テレメトリ受信(202)。/ingestはレガシー互換 |
SHA-256(salt:key) でハッシュ化して保存(平文は保持しない)。失効フラグ(key_status=revoked)で即時無効化可能。answer と explanation_steps を除去。OpenAPIスキーマ側にも「このキーを含んではならない」制約を明記。例外は単元練習モードで「即時解説表示」を有効にした時のみ(仕様上の意図的挙動)。allowed_origins を持ち、一致しないOriginは403。ブラウザ直叩きが必要ならドメイン登録が要ります。Retry-After。UNIQUE(session_id, item_id) 制約で同一設問の二重配信・二重採点を防止。{error:{code,message}} の構造化形式。codeは列挙固定(invalid_api_key/rate_limited/session_complete など12種)。calibration_optin フラグを持ち、キヨさんのテナントは現在OFF(受験データを当社の較正母集団に混ぜない設定)。混ぜるかどうかは契約時の握り事項。| テーブル | 主な列 |
|---|---|
tenants | tenant_id / name / api_key_hash / allowed_origins / rate_limit_per_minute / tier / calibration_optin / key_status / key_issued_at |
api_sessions | session_id / tenant_id / domain / mode / topic_filter / policy_json(採用した出題ポリシーのスナップショット)/ status / created_at / finished_at |
api_session_items | session_id / item_id / served_at / selected_choice / is_correct / elapsed_ms / timed_out / answered_at + UNIQUE(session_id,item_id) |
events / item_responses | 受験テレメトリ。domain/type/session_id/地理情報(CF由来)/ip_hash/tenant_id。設問単位の正誤・所要時間を item_responses に蓄積 |
questions | API側が持つ問題テーブル(answer・explanation_stepsを平文保持=サーバ内部専用) |
fact体験模試は問題バンクをビルド時に取り込み、ブラウザへ丸ごと配布しています(JSバンドル1本=展開16.4MB/gzip転送1.6MB/6,536問・答えと解説を含む)。実行時に問題APIを叩くコードはゼロ件です。サーバ通信は「LINE認証」と「受験結果の送信」のみ。
重大度は当社評価です。2026-07-23 に解決した項目は §7 にまとめています。
factR2の版付きリリースを唯一の正本にする設計は完成し、それを読む出題workerも本番稼働していますが、一般ユーザーが受けている体験模試はそこを見ておらず、ビルド時同梱の旧スナップショットで動いています。正本にしか無い問題が4,129問、フロントにしか無い問題が3,128問あります。
影響:正本を直しても本番の受験体験は直りません(§4-3の正答位置リークも、正本を直しただけでは公開面に反映されない)。改善のリードタイムが常にフロントの再ビルド・再デプロイ待ちになります。
| 判定基準 | 正本7,537 | 公開面6,536 |
|---|---|---|
| 問題文+選択肢が完全一致(=真の重複) | 0問 | 6問 |
| 問題文が完全一致(選択肢違い) | 0問 | 799問 |
| 冒頭60字が一致(同型の数値違い) | 500問 | 1,855問 |
fact体感の主犯は実在します。「二語の関係」250問は問題文ユニークがわずか94で、同一の語ペア(日照:発芽/大豆:豆腐 など)が6回ずつ、選択肢だけ差し替えて登場します。問題文が完全一致する重複799問の内訳は熟語166/二語156/英文120/現代文92が主で、サーバ側の分類ミスではなく公開面のバンクが旧世代だったことが機序でした(正本側の二語は96問で健全)。
fact正本7,537問すべての methods が [testcenter, web, paper] の一律値です。一方、外部10ソースの調査では「二語の関係」はテストセンター専用(WEBテスティングでは出ない)/「文の並べ替え」「空欄補充」はWEBテスティング専用(ペーパーでは出ない)と確認しています。つまり現状は本番では出るはずのない形式が混ざって出題される状態です。
methods を読める構造になっているので、データ側の是正が主)。factSPI適用95単元のうち、完全一致・関連ともに在庫0が55単元(完全一致だけで見れば78単元が0)。実際に問題を持っているのは17単元に集中しています。とくに公務員試験で実績337回・ほぼ毎年出る計量図形が0問、資料解釈の実数228回・判断推理の対応186回なども0問です。言語は772問=全体の10.2%にとどまり、言語には難易度4・5が1問もありません。
fact「文の並べ替え」200問は100%が同一の足場テンプレート(「〜について、まず現状を確認した→その結果→そこで→その後→以上から」)で、本番SPIの長文分割型とは乖離しています。フロント側の公務員現代文20問も同一雛形の本文使い回しです。
fact公開中の体験模試は、6,536問を正答インデックスと解説ステップ込みでJSバンドルに同梱して配布しています(展開16.4MB/gzip転送1.6MB)。API側では「答えは壁の裏、配信と採点だけをAPIで出す」というIP境界を、バケット分離とレスポンスフィルタで厳格に守っているのに、自社の公開面ではその境界が存在しません。
※これは「無料体験の問題文は公開物」という割り切りとしては一応筋が通りますが、境界の設計が経路ごとにバラバラであること自体がリスクです。あわせて初回ロード16.4MBはモバイル体験としても重い。
mode=taiken は無認証のまま答えと解説を返しており、URLにパラメータを1つ足すだけで1リクエスト100問を答えつきで収集できる状態でした。公開workerから答えバケットのバインディングを物理削除し(アプリ層のフィルタだけに依存しない構成)、本番で全モードの非露出を実測確認しています。fact①項目45問は書き下ろしの自作で、成果物側に出典表記が無い(設計調査は残っているがコードから参照されていない)。②信頼性係数の検証コードはリポジトリ全体で0件、構想メモのみで未着手。③偏差値は受験者集団ではなく理論的中点(平均3・SD1のハードコード)との比較で、設計意図(受検者集団で正規化)と実装が乖離。4側面への重み係数とライスケール閾値20は根拠の記録が無い裁量値。④保証を否定する免責文は結果画面にしか出ない(受験前・受験中は操作説明のみ)。
fact外部監査2社(sol/Gemini)を通し、solは「現状のまま一般公開は不可」(条件付きGO)。公開前必須のHigh4件は次のとおり。①SVGサニタイザが名前付き実体参照(( 等)を未デコードで通す(現バンクは自社決定論生成のため実害は「悪性SVGが混入した場合」に限定)/②プレビュー公開ゲートがクライアントJS同梱トークンで実質ゲートになっておらず、sitemapにプレビューURLが載る/③量産CLIが検品不合格でも公開用バンクを書き出して正常終了する(fail-closedでない)/④知識系34問が内容監査をスキップしたまま「監査済み」の由来情報を付与される。
fact公開LPは「合計4,000問超」と表記していますが、実体は正本7,537問/同梱6,536問。また「算術10トピック・推論7型」と記載していますが、実際には非言語18トピック・推論10型です。実力を過小に伝えている方向の乖離です。
unknown設問単位の応答データ(正誤・所要時間)を蓄積する仕組みは動いていますが、IRT較正(項目反応理論による難易度・識別力の推定)を実装したコードは今回の調査範囲では確認できませんでした。現在の難易度1〜5は生成時の設計値であり、実データによる較正値ではありません。
factLIFF版に同梱しているバンクは5,343問・最終更新 2026-06-22で、Web版(6,536問・7月3日更新)よりさらに古い断面です。1ヶ月以上同期されていません。内訳も語彙501・文章理解50と薄く、非言語3,550に偏っています。
影響:LINE経由で受験した方だけ、より偏った・より古い出題を受け続けます。同じ「Educareの模試」なのに経路によって中身が違う状態です。
fact試験種ごとの単元重みは最新リリース(qb-r1-20260723)に焼き込み済みで、それを使って出題する新サンプラも実装・テスト完了していますが、まだ本番へデプロイしていません(デプロイ経路の再整備が先行条件)。現在配信中のworkerは新フィールドを剥がして返すため、実際の出題は従来どおりの配分です。
影響:「出題実績データで在庫と配分を機械制御する」という設計の本丸が、まだ受験体験に届いていません。
fact本日の実測どおり、API経由で配信できるのは7,505問で、文章理解32問は0件です。API側の問題テーブルが長文本文を保持する構造を持たないため、投入時に除外されています。正本リリース側では長文を content-addressed で分離管理できているので、データ側ではなくAPI側の実装が追いついていない形です。
fact公務員模試はSPIバンクを分野タグでフィルタして代用しており、試験種タグが付いた問題は6,536問中134問のみ。地方上級・警察・消防・国家一般・特別区・市役所それぞれ50〜72問しかありません。残りは試験種を問わない汎用出題です。
factSPIの英語(ENG)検査、およびSCOAの言語・英語尺度は問題型の開発自体が未着手です。社内の商品計画書でも「英語対策=真の穴」と明記しています。
fact①人文科学・社会科学・時事は単元taxonomyが未構築で、周期・在庫分析の対象外です(時事は「周期」ではなく「鮮度」で管理すべきという性質の違いもあり別建て設計が必要)。②数的処理の出題実績インデックスは2018年までで止まっており、2019〜2025年の補完が残っています。③そもそもこの実績データは本試験の悉皆リストではなく、市販模試が参照した過去問の実績であり、強いプロキシではあるが上限のある推定値です。
fact本番で実証しました。ステートレス採点 POST /v1/scores に、同じ問題を選択肢0〜4で並べて1回投げるだけで正答が返ります(son-eki-0001 → 応答から正答3が確定・正本の答えと一致)。同一問題の重複送信を禁止しておらず、送信件数の上限もセッション所有の確認もありません。
影響:認証キーを持つテナントが7,537問の答えを機械的に全部抜けます。1リクエストで1問確定するため、後述4-21(レート制限が機能していない)と組み合わさると実質無制限です。外販商材としての価値を失う経路です。
これは今回の改修で入ったものではなく従来からある穴ですが、外販開始と同時に顕在化します。
factテナントごとに120リクエスト/分の制限を持つ設計ですが、実装は「直近1分のイベント数」を数えており、通常のAPIリクエストではイベントが追加されません。したがってイベントが120件に満たないテナントは、セッション作成も問題取得も採点も何回呼んでも制限に到達しません。テストも「既に999件ある」状態のモックだけで、リクエストによる増加を検証していませんでした。
fact解答の記録が成功した直後にイベント書き込みが失敗すると、APIは500を返します。クライアントが再試行しても「回答済み」の分岐で早期に返るため、イベントは二度と生成されません。結果として回答自体は確定しているのに、版情報つきの証跡だけが永久に欠ける状態になります。受験の完了処理にも同じ構造があります。
これは本資料が最重要課題としている「どの世代の問題への回答か特定できない」問題(§4-1)を、これから防ごうとしている当の仕組みに空いていた穴です。
fact改修後の外販APIは正本リリースから出題してセッションに固定しますが、ロールバック先の旧版は別系統のコピーから取得・採点します。改修後にセッションを作った後で旧版へ戻すと、旧版に存在しない問題は404になり、世代衝突があれば別問題として採点されます。「戻せる」つもりの手段が、実は戻せません。
| 論点 | 現状 | お伺いしたいこと |
|---|---|---|
| ① 版のピン留め | リリースは版ごと不変・current.json で切替。テナント別に別の版を指すことも追加コストゼロで可能 | キヨさん側は「常に最新版」でよいか、それとも特定版に固定したいか。§4-1(ID再利用)を踏まえると、外部提供では版固定を推奨します |
| ② 較正データの合流 | テナント行の calibration_optin は現在 OFF | そちらの受験データを当社の較正母集団に合流させるか。合流するならデータ所有・保持期間・越境の扱いを先に定義したい |
| ③ 利用形態 | REST+OpenAPIで提供中。ブラウザ直叩きはCORS許可ドメイン登録が必要 | サーバ間連携かブラウザ直叩きか。後者ならドメインをご指定ください |
| ④ 性格検査の提供可否 | APIのセッションは現状 domain=spi のみ。性格検査はフロント実装+ステートレス採点は domain=personality 対応済み | 性格検査もAPI提供対象に含めるか。含めるならセッション方式への拡張が必要。§2-2 のとおり規範集団なし・信頼性未検証・出典表記なしという状態なので、外部提供する場合は先に「規範集団つき偏差値への移行」と「免責の前置き表示」を済ませたいと考えています |
| ⑤ 是正の優先順位 | §4-1〜4-3が最優先という当社評価 | 外部提供の観点から見て、この優先順位でよいか。ご意見をいただきたい |
本資料の数値は、以下の一次確認で裏どりしています。推定は inference、確認できなかったものは unknown と明記しました。
# 1. API・出題workerの本番稼働確認(本日実測)
curl -s https://educare-cbt-ingest.komuin-sukima.workers.dev/healthz
→ {"status":"ok","time":"2026-07-23T00:49:30Z"}
curl -s https://educare-cbt-ingest.komuin-sukima.workers.dev/openapi.json
→ OpenAPI 3.1.0 / title="SPI Platform API" / 14パス・17スキーマ
curl -s https://spi-questions.komuin-sukima.workers.dev/api/spi/pool/stats
→ {"total":7537, "by_topic_subpattern":[...]}
# 2. 正本バンクの内訳(ローカル正本JSONを直接集計)
spi_bank_build/spi-questions.full.v2.json → 7,537問/非言語6,765・言語772
トピック25・サブパターン80・全問5択・解説欠落0・平均5.0ステップ
# 3. 正答位置の偏り(正本・トピック別)
文章理解のみ 32問中27問が index 0(84%)/他トピックは全て20%前後で一様
# 4. 公開面の実バンク(本番配信中のJSバンドルを取得して解析)
curl https://educarelog.net/_astro/ExamStartGate.*.js
→ 6,536問を JSON.parse で同梱(answer・explanation_steps 込み)
→ gzip転送 1.60MB/展開 16.4MB
→ 問題文先頭60字ユニーク 4,581件=重複1,955問
# 5. ID衝突の実証(公開面バンク × 正本の突合)
共通ID 3,408件 → stem または answer が不一致 3,407件
例)son-eki-0001 が両者で全く別の問題
# 6. 性格検査(本番配信中バンドルから項目データを直接抽出)
45項目/開放性8・誠実性10・外向性8・協調性10・情緒安定性9
逆転12・ライスケール5/5件法/aspect=行動的12・意欲的8・情緒的12・社会関係的13
# 7. APIバンクの断面(キヨさんのテナントキーで実弾)
GET /v1/questions?limit=1 → pagination.total = 7505
GET /v1/questions?topic=文章理解 → total = 0(長文はAPI側テーブル非対応のため除外)
GET /v1/questions?topic=二語の関係 → total = 96(正本と一致)
GET /v1/questions/son-eki-0001 → 問題文がローカル正本と完全一致
返却フィールド: id/field/topic/difficulty/methods/stem/choices/source
(answer・explanation_steps は含まれない=答え非露出を実測)
# 8. 性格検査の採点仕様(本番配信中バンドルのコードから抽出)
定数: 理論平均=3 / 理論SD=1 / ライスケール閾値=20(いずれもハードコード)
偏差値 = clamp(50 + 10*((因子平均 - 3)/1), 20, 80) ※受験者集団の統計を参照しない
4側面 = 因子偏差値の重み付き平均
行動的{外向性.45,誠実性.35,開放性.2} 意欲的{誠実性.45,外向性.3,開放性.25}
情緒的{情緒安定性1.0} 社会関係的{協調性.7,外向性.3}
免責(結果画面のみ): 「ビッグファイブ理論に基づく練習用の自己申告プロフィールです。
採用結果や本番の判定を保証するものではありません。」
リポジトリ全体grep: cronbach|α係数|信頼性係数|因子分析 → 一致0件
# 9. SCOA・LIFF(ローカル正本ファイルを集計)
scoa-questions.bank.json → 145問(論理75/数理36/常識34・全問5択)
LIFF apps/liff .../spi-questions.bank.json → 5,343問(最終更新 2026-06-22)
| 項目 | 状態 | 内容 |
|---|---|---|
| 出題workerの無認証での答え露出 | ✅ 本番反映済み | 公開workerから答えバケットのバインディングを物理削除。全モードで answer/explanation_steps が返らないことを本番実測で確認(version 0eb60a71・13:12反映) |
| §4-1 問題IDの世代衝突 | ✅ 台帳側は完了 | UUIDv7の恒久ID(item_family_id/item_version_id)と系譜台帳を新設し、正本7,537問すべてに付与。過去の応答ログ1,428行のうち88.1%を遡及救済(残り170行は世代間で内容が変わっており憶測で割り当てていない)。今後のログに版情報を刻む配線はデプロイ待ち |
| §4-3 文章理解の正答位置リーク | ✅ 正本は是正済み | 新リリース qb-r1-20260723r2 が本番稼働。最大シェア28%へ一様化。再発防止ゲート2本を追加。公開面のバンドルは未反映 |
| §4-11 本番コードがメインライン未統合 | ⚠️ 半分解決 | 本番稼働中のコミットが origin に存在しなかった状態を解消(push済み)。ブランチのメインラインへのマージは未実施 |
| デプロイ正路の不在 (初版では未記載) | ✅ 解決 | 出題worker・外販APIともデプロイゲートに未登録で、事故時に戻す手段が存在しませんでした。両者を登録し本番の現状を台帳に記録。実際に1回通して昇格・検証まで成功 |
以下は本資料の初版で課題として挙げ、同日中に対応した項目です。経緯の記録として残します。
fact本番配信中の体験模試バンク(6,536問)とサーバ正本リリース(7,537問)でIDを突き合わせたところ、共通ID 3,408件のうち 3,407件で問題文または正答が一致しません。例:ID son-eki-0001 は、フロントでは「2400円で仕入れ20%の利益を見込み…」、正本では「定価2100円をまず20%引き…」と全く別の問題。
影響:設問単位で蓄積している応答ログ(item_responses.item_id)がどの世代の問題への回答か特定できません。正答率・難易度較正・IRT較正といったデータ資産の土台が崩れます。キヨさんが叩くAPI経路そのものは正本と同世代なので現時点で実害は出ていませんが、当社が版を更新した際に「同じIDで違う問題が返る」事故が起きうる構造です。
bank_release_id を必須で紐付ける(リリース側にはすでに bank_release_id を全問へ焼き込み済みなので、配信・記録側を合わせれば解消可能)。③移行期は旧IDを別名前空間に隔離。qb-r1-20260723r2 が本番の current.json に切り替わっています。本番R2から答えシャードを直接取得して確認したところ、文章理解32問の正答位置は 0:7/1:6/2:7/3:9/4:3(最大28%) と一様化されていました。あわせてリリースビルドに恒久ゲート2本(トピック単位の正答位置一様性・最大40%/トピック内の重複問題文の遮断)が追加されています。以下は是正前(本日午前)の実測記録です。fact正本の文章理解32問のうち27問(84%)の正答が選択肢index 0(=一番上)。他の全トピックは正答位置がきれいに一様(各20%前後)なので、文章理解だけの偏りです。クライアント側に選択肢シャッフルの実装が無く並び順のまま表示されるため、受験者から見て「一番上を選べば当たる」状態です。フロント同梱バンク側も、SPI文章理解30問の57%が1番目、公務員文章理解351問は3番目に43%集中(5番目はわずか3%)という偏りがあります。
影響:模試としての妥当性が壊れます。正答率・偏差値も過大評価になります。
factSPI Platform API(feat/spi-api-platform-phase1)も出題worker(feat/spi-infinite-serving)も、リポジトリの develop/main に未マージのまま本番へデプロイされています。
影響:本番で動いているコードがどのコミットか、リポジトリの正史から辿れません。並行開発時の先祖返り事故(過去に実例あり)の温床です。
本仕様書が定義するAPI・バンクに共通する契約です。「選択肢を何番目として数えるか」「正答値の基準」「送信する回答値の意味」「宣言の在り処」を、実装側の解釈違いを防ぐために明文化します(2026-07-31 確定・ANSWER_BASE_MIGRATION_PLAN_20260730.md §10-8)。
| ID | 項目 | 定義 |
|---|---|---|
| DC-1 | 選択肢の数え方 | 選択肢配列は先頭を0とする配列添字で数えます。choices[0] が1番目の選択肢です。画面表示の「選択肢1」は添字0の投影(表示専用の変換)です。 |
| DC-2 | 正答の基準 | バンク内部の answer は1基準へ切替済みです(2026-08-01 完了)。切替は当社内部の是正であり、本仕様のAPI挙動・採点結果は切替前後で同一であることを機械検査(全問題×全choice点の突合)で保証済みです。 |
| DC-3 | 解答送信の意味 | choice は当APIが返した choices 配列の位置(0始まりの配列添字)です(2026-07-31 確定)。-1 は「未回答」を表す正規のセンチネル値です。 |
| DC-4 | 宣言の在り処 | 正答を含むデータは manifest トップレベルの answer_base 宣言と同伴でのみ解釈します。宣言の無いデータは読みません(fail-closed・既定値で補いません)。 |
※ この節は共有済みの4仕様書(SPI/公務員/SCOA/適性)すべてに同一内容で追記しています。