Skip to content

静的検索の修飾付き検索を search_init 側の拡張で修理する#280

Merged
znz merged 1 commit into
rurema:masterfrom
znz:static-search-qualified
Jul 22, 2026
Merged

静的検索の修飾付き検索を search_init 側の拡張で修理する#280
znz merged 1 commit into
rurema:masterfrom
znz:static-search-qualified

Conversation

@znz

@znz znz commented Jul 22, 2026

Copy link
Copy Markdown
Member

概要

#279 の選択肢1(rurema 所有の初期化側のみでの対応)を実装しました(refs #279)。vendored の search_controller.js / search_navigation.js / search_ranker.js は byte 単位で無変更です(git diff master で確認済み)。

  • 原因: vendored の parseQuery() はクエリの全ての .:: に書き換えますが(RDoc の full_name 表記に合わせた挙動)、BitClust の full_name はシングルトンメソッド/モジュール関数を . / .# / ?. のまま保持するため(bitclust から生成される見た目も .# から ?. に移行したい #250)、File.open などの修飾クエリが自分自身のエントリにすら一致しませんでした
  • 対応:
    • SearchIndexGenerator が該当エントリ(typemark に . を含むもの)に match_name(?..# 畳み込み後、全 .:: 化= parseQuery の書き換えを鏡写しにした文字列)を追加
    • search_init.js / search_page.js が、既存の 特殊変数の検索 #194($ 対応)と同じ機能検出付きグローバル差し替えの手法で parseQuery(クエリの ?..# 畳み込み+q.original 復元)と computeScore(match_name を持つエントリのみ、full_name を差し替えた浅いクローンを採点)をラップ
    • 元の entry オブジェクトには一切触れないため、検索結果の表示ラベル(full_name)は不変.#/?. は同じ match_name に畳まれるため、版をまたいだクロス表記のマッチも成立します
    • フックが将来の上流更新で無くなっていた場合は機能検出により無変更でスキップ(クラッシュせず、従来動作への劣化のみ)

検証

  • JS(qjs・rake test:js): 素の vendored ランカーでのバグ再現テスト+パッチ後の File.openKernel.#openKernel?.open クロスマッチ・String#size/open/Net::HTTP の無影響・返却エントリの同一性(表示安全)・フォールバック(フック不在スタブでも無事故)まで 29 アサーション。実装前 red → green を確認
  • Ruby: match_name の生成規則(singleton/モジュール関数のみ付与・instance/定数/特殊変数には付かない・merge 透過)のテスト追加。17794 tests / 0 failures・rbs validatesteep check クリーン

既知の制限

ハイライト(<em> 強調)は vendored の highlightMatch がそのまま full_name を参照するため、修飾クエリでヒットしたエントリは強調なしの平文表示になります(マッチ・順位・表示テキスト自体は正常)。ハイライトまで対応するには vendored 側の変更(fork か上流提案)が必要なため、本 PR では見送りです。

refs #279

🤖 Generated with Claude Code

rurema#279 の選択肢1(まず初期化側の拡張で対応可能か試す)を実装。vendored
な search_controller.js/search_navigation.js/search_ranker.js の3本は
一切変更していない(git diff master で空を確認)。

根本原因: vendored な parseQuery() はクエリ中の全ての "." を "::" に
書き換える(RDoc の full_name はクラスメソッドを "::" で表す)。一方
BitClust の full_name はシングルトンメソッド/module function を
リテラルな "."/".#"/"?." のまま保持する(rurema#250)。そのため "File.open"
"Kernel.#open" "Kernel?.open" のような修飾クエリは自分自身の
エントリにすら一致しなくなっていた。

設計: SearchIndexGenerator が該当エントリ(typemark に "." を含むもの)
に match_name を追加する。match_name は full_name の "?." を ".#" に
畳んでから全ての "." を "::" に置換したもの(= parseQuery がクエリに
対して行うのと同じ書き換え)。search_init.js/search_page.js は
`typeof parseQuery === 'function'`/`typeof computeScore === 'function'`
で機能検出した上でグローバル関数を差し替える(rurema#194 の $ プレフィックス
対応と同じ手法): parseQuery 側はクエリの "?." を ".#" に畳んでから
vendored 本体に渡し、computeScore 側は entry.match_name を持つ
エントリだけ full_name を match_name に差し替えたシャロークローンで
採点する。オリジナルの entry オブジェクトには一切触れないため、検索
結果として返る full_name(表示ラベル)は不変。フックが将来なくなって
いた場合(将来の Aliki 更新で closure 化されるなど)は if ガードが
false になり無変更でスキップする(クラッシュしない・従来動作に劣化
するだけ)。".#"/"?." の両表記は同じ match_name に畳まれるため、
バージョンをまたいだ統合インデックス(search_page.js)でクロス表記の
マッチも成立する。

t_wada 式 TDD で実装: JS 側は qjs(test/js/test_search.mjs)に
未パッチ状態での再現(red)→ パッチ後に green を確認するテストを追加
(修飾クエリの一致・クロス表記・表示安全性の恒等性チェック・
フォールバック時に例外を投げず無修飾検索が動くことの確認)。Ruby 側は
test_search_index_generator.rb に match_name の付与/非付与/マージ
保持のテストを追加。bundle exec rake test(17794 tests, 0 failures)・
rake test:js・rbs validate・steep check すべて green(steep の
whole_file_gate.rb まわりの ERROR ログは master でも再現する既知の
無関係な背景ノイズ)。

refs rurema#279

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@znz
znz merged commit b423e4e into rurema:master Jul 22, 2026
10 checks passed
@znz
znz deleted the static-search-qualified branch July 22, 2026 10:51
znz added a commit that referenced this pull request Jul 22, 2026
#279 のコメント対応(2件)。vendored な search_ranker.js /
search_controller.js / search_navigation.js は引き続き一切変更して
いない(git diff で無改変を確認)。

1. /ja/search/ の統合インデックスで、同じ module function が版によって
   "Kernel.#open"(4.0 より前)と "Kernel?.open"(4.0 以降)の2行に
   分かれて出ていた。SearchIndexGenerator.merge で match_name を持つ
   エントリの full_name の ".#" を "?." に畳んでからマージキーを
   計算するようにし、現行表記の1行(版リストも合流)に統一する。
   name/type/path/match_name は表記に依らず同一なので畳むだけで
   キーが一致する。match_name を持たない散文見出しは字面がページ
   本文と一致していることに意味があるため畳まない。単一版ページ
   (search_init.js 経由)の表示はその版の表記のまま。

2. 修飾付きクエリ(File.open / Kernel.#open / Kernel?.open)は #280
   でヒットするようにはなったが、ハイライトされないままだった。
   vendored の highlightMatch() は "." を "::" に書き換えた後の
   q.normalized を表示用 full_name と比較するため連続一致せず、
   fuzzy fallback も最初の ":" で必ず脱落する。search_init.js /
   search_page.js に highlightMatch のラップを追加し、vendored が
   マークを付けられなかった場合のみ、parseQuery ラップが保存して
   いる q.original(生のクエリ)と表示文字列を ".#"/"?." 同一視で
   突き合わせて連続一致をハイライトする。両表記とも2文字なので
   畳んだ文字列のインデックスがそのまま表示文字列に流用できる。
   従来ハイライトできていたクエリの挙動は不変(vendored の結果を
   優先して返す)。

テスト: test_search_index_generator.rb(merge の畳み込み3件)、
test_searchpage_command.rb(実 DB 2版からの統合で ?. 1エントリに
なること)、test/js/test_search.mjs(highlightMatch の両表記×両方向・
部分一致・fuzzy 素通し・search_page.js の end-to-end・ラップ不能時の
フォールバック)。全 Ruby テスト 17799 件・JS テスト・steep check green。

refs #279

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant