Skip to content

fix(shared): VALID_EVENT_TYPES を型から導出し isPureTyping 判定を一本化する (#222 #235) - #264

Merged
shinyaoguri merged 1 commit into
mainfrom
fix/shared-p3-event-types-and-puretyping
Aug 15, 2026
Merged

fix(shared): VALID_EVENT_TYPES を型から導出し isPureTyping 判定を一本化する (#222 #235)#264
shinyaoguri merged 1 commit into
mainfrom
fix/shared-p3-event-types-and-puretyping

Conversation

@shinyaoguri

Copy link
Copy Markdown
Owner

目的

2026-08 レビュー (#243) の残件のうち shared の 2 件。どちらも「同じことを決める式が複数箇所にあり、片方が取り残される」という同型の問題なので、文書ルールではなく機械 (tsc / 単一関数) で同期を強制する形に直す。

#222 — VALID_EVENT_TYPES が union から取り残されていた

InputTypeValidator.ts の手書き Set は 26 種types/events.tsEventType union は 29 種。機械差分の結果、欠落は次の 3 種ちょうど・余分は 0 種で、いずれも editor から実際に発火する:

欠落 発火元
environmentProbe tracking/EnvironmentTracker.ts:63
fullscreenChange tracking/FullscreenTracker.ts:143
examOpened ui/tabs/TabManager.ts:362

手書きをやめ Record<EventType, true> のキーから導出した。以後 union に型を足すと tsc が Set 側の記入漏れを検出するのが本質で、欠落 3 種が埋まるのは副産物。VALID_INPUT_TYPES は差分ゼロだったが、同じ drift を将来止めるため同じ形に揃えた。

現時点の実害はゼロであることの確認

validateEventTypeどの検証経路にも配線されていません (定義と re-export のみ)。本 PR でも配線しません — 未知イベント型を持つ将来 proof を fail-closed で弾く判断には後方互換の議論が要り、#223 と同じ論点になるためです。危険なのは「#246 で構造検証の置き場ができたので、誰かが何気なく配線した瞬間に exam proof が全滅する」という時限性で、そこは本 PR で解消されます。

#235 — isPureTyping の判定が 3 箇所にあった

場所 benign 除外
verification.ts recomputeProofMetadata (採点側の正) 非 benign bulk + 乖離 snapshot を除外 あり
TypingProof.ts:822 (export 時の自己申告) bulkInsertEvents === 0 なし
TypingProof.ts:867 付近 (自己検証) metadata.bulkInsertEvents === 0 なし

Monaco の括弧自動閉じは既定 on (monaco.editor.createautoClosingBrackets を指定しておらず 'languageDefined') なので、( を 1 つ打つだけで自己申告が false に落ち、採点側の true と食い違う値が proof に焼かれていた。

structuralEdit.tsevaluatePureTyping(events) を新設し、SessionProvenanceLedger の replay と isSuspiciousBulkInsert / isBenignEditorInsert / isFlaggedBulkInsert / isDivergentContentSnapshot の組み合わせをこの関数だけが持つ状態にした。recomputeProofMetadataTypingProof の双方がこれを呼ぶ。

副次的な効果: export 側は逆に緩すぎた面もあり、複数行の一括投入 (Monaco が insertParagraph で記録するため isSuspiciousBulkInsert に載らない) が申告に反映されていなかった。一本化でこちらも塞がる。

TypingProof.ts:867 の扱い

呼び出し元を全パッケージで grep したところ このメソッドは未使用で、引数は proofData のみ・events を入手する経路がありません (任意の proof を受ける API なので this.events を代用するのは不正)。そのため寄せず、JSDoc に「3 つ目の定義ではない。events が無いためメタデータのみの粗い自己チェックで、採点側とは一致しない (こちらの方が厳しく false に倒れる)。判定値は verifyProofMetadata から取ること」を明記した。

後方互換

  • metadata.isPureTypingtypingProofData に含まれず typingProofHash の入力ではない (types/proof.ts の 154-177 行 vs 245-249 行で確認) → 値が変わっても既存 proof のハッシュ照合に影響しない
  • metadata.bulkInsertEventsisSuspiciousBulkInsert の素のカウントのまま。verifyProofMetadata の完全一致検査は不変 (ここを変えると既存 proof が invalid になる)
  • isSuspiciousBulkInsert 本体も未変更

確認方法

テストを先に書き、実装前に赤くなることを実測してから仕上げた。

テスト 修正前 内容
括弧自動閉じだけのセッション → isPureTyping true 🔴 expected false to be true 本命 (#235 の再現)
複数行の一括投入 → false 🔴 expected true to be false 境界。export 側が素通しだった laundering 口
evaluatePureTypingrecomputeProofMetadata の結論一致 🔴 expected true to be false 2 経路の固定
VALID_EVENT_TYPES が union と同集合 🔴 environmentProbe: expected false to be true #222 の回帰

修正前から緑だったケース (input types 側) は、INPUT_TYPE_MEMBERS から要素を削る / union 外の値を混ぜる、を実際に試して赤くなることを確認済み。

npm run lint && npm run test:run --workspaces --if-present && npm run build

すべて green。shared は 475 passed (修正前 468 + 新規 7)。webCliParity.test.ts は 12 件 green のまま — ここが赤くなったら判定の一本化に失敗しているという意味で、本 PR の一番重要なゲート。

packages/shared/CLAUDE.md に不変条件 8 (isPureTyping の判定点は 1 つ) を追記し、型導出で不要になった手動同期の記述を更新した。

Closes #222
Closes #235

#222: VALID_EVENT_TYPES が 26 種の手書き Set で、EventType union の 29 種から
取り残されていた (environmentProbe / fullscreenChange / examOpened が欠落。
いずれも editor から実際に発火する)。手書きをやめ Record<EventType, true> の
キーから導出することで、以後 union に型を足すと tsc が記入漏れを検出する。
VALID_INPUT_TYPES は差分ゼロだったが、同じ drift を将来止めるため同じ型導出に
揃えた。validateEventType の検証経路への配線は行わない (未知イベント型を
fail-closed で弾く判断は後方互換の議論が要る。#223 と同じ論点)。

#235: isPureTyping に 3 つの別々の式があり、export 時の自己申告だけが benign
除外なしの bulkInsertEvents === 0 だった。Monaco の括弧自動閉じ (既定 on) で
"(" を 1 つ打つだけで自己申告が false に落ち、採点側の true と食い違う値が
proof に焼かれていた。判定を structuralEdit の evaluatePureTyping に集約し、
verifyProofMetadata と TypingProof の双方がこれを呼ぶ。副次的に、export 側で
素通しだった複数行の一括投入 (insertParagraph) も申告に反映されるようになる。

後方互換: metadata.isPureTyping は typingProofData に含まれず typingProofHash
の入力ではないため、値が変わっても既存 proof のハッシュ照合に影響しない。
metadata.bulkInsertEvents は isSuspiciousBulkInsert の素のカウントのままで、
verifyProofMetadata の完全一致検査も不変。webCliParity は 12 件 green。

Closes #222
Closes #235

Assisted-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation pkg:shared packages/shared labels Aug 15, 2026
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Name URL
Preview https://8a668932.typedcode.pages.dev

Deployed from commit 1231213
API: staging Workers

@shinyaoguri
shinyaoguri merged commit b152ad0 into main Aug 15, 2026
8 checks passed
@shinyaoguri
shinyaoguri deleted the fix/shared-p3-event-types-and-puretyping branch August 15, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation pkg:shared packages/shared

Projects

None yet

1 participant