2026-08-23 の全 open Issue トリアージ (#243) で #266 の棚卸し中に見つかった、独立した小さな設計ギャップ。
何が起きるか
proof.exam.examId / proof.exam.variant は proof 側の自己申告値で、exam 束縛の検証では manifest 側の値と突き合わされない。
- manifest 側の
examId / problemId / variant は署名 core に含まれる (packages/shared/src/exam/examPackage.ts:629-631) ので packageHash に束縛される
- しかし
verifyExamBinding (examPackage.ts:499-) が proof 側から読むのは packageHash / startToken / problemContentHash / rootBinding と、v2 の問題 lookup に使う problemId (:575) だけ。proof.exam.examId と proof.exam.variant はどこでも参照されない
- verify-cli は
verify.ts:171-173 で proof 側の値をそのまま CLIExamResult に載せ、output.ts:122-123 の Exam: … 行に表示する (manifest 側の値ではない)
影響
修正案
- package が提供されているときは
verifyExamBinding で proof.exam.examId === manifest.examId (と variant) を検査し、不一致は binding.valid = false (または warning) にする
- 表示は manifest 側の値を優先し、package 未提供時は「自己申告」と明示する
どちらも小さい (shared ~10 行 + CLI 表示 ~5 行 + テスト)。#266 の PR-B (CLI 出力境界サニタイズ) と同時に扱える。
関連
🤖 Assisted by Claude Code
2026-08-23 の全 open Issue トリアージ (#243) で #266 の棚卸し中に見つかった、独立した小さな設計ギャップ。
何が起きるか
proof.exam.examId/proof.exam.variantは proof 側の自己申告値で、exam 束縛の検証では manifest 側の値と突き合わされない。examId/problemId/variantは署名 core に含まれる (packages/shared/src/exam/examPackage.ts:629-631) ので packageHash に束縛されるverifyExamBinding(examPackage.ts:499-) が proof 側から読むのはpackageHash/startToken/problemContentHash/rootBindingと、v2 の問題 lookup に使うproblemId(:575) だけ。proof.exam.examIdとproof.exam.variantはどこでも参照されないverify.ts:171-173で proof 側の値をそのままCLIExamResultに載せ、output.ts:122-123のExam: …行に表示する (manifest 側の値ではない)影響
Exam:行に出るexamId/variantは自由文字列 (採点者が「この試験の proof だ」と読む根拠にならない)。[verify-cli] proof 由来の language が無検証で stdout に出る (偽の Checks 行を注入できる) #266 の制御文字注入の入口の 1 つでもある修正案
verifyExamBindingでproof.exam.examId === manifest.examId(とvariant) を検査し、不一致はbinding.valid = false(または warning) にするどちらも小さい (shared ~10 行 + CLI 表示 ~5 行 + テスト)。#266 の PR-B (CLI 出力境界サニタイズ) と同時に扱える。
関連
examId/variantは Bump @vitest/coverage-v8 from 2.1.9 to 4.0.16 #2 の項目)--exam-packageのサイレント無効化。同じverify.tsの exam 分岐)examIdの位置づけ)🤖 Assisted by Claude Code