Repository navigation
Bump the npm-minor-patch group across 1 directory with 10 updates - #38
Closed
dependabot[bot] wants to merge 1528 commits into
Closed
dependabot[bot] wants to merge 1528 commits into
dependabot[bot] wants to merge 1528 commits into
Conversation
初期取得の完了を待たずに画面を可視化する変更の下準備。 挙動は変えず、E2Eが「操作してよい状態」を決定論的に待てる信号だけを足す。 ページ全体オーバーレイが初期検索の完了を待たなくなると、E2Eの waitForLoadingOverlayToFinish が掴む `.v-overlay .v-progress-circular` の .first() は列ごとのスピナーを指すようになる。列スピナーは1tick遅れて 出るので「出る前に toBeHidden が通る」窓ができ、navigateTo 経由の 140箇所超が行の出る前に次の操作へ進んでしまう。 - is_restoring_columns / running_search_count と、その合成である is_view_ready を rykv / mi に追加する。表示制御には一切使わない - running_search_count は世代番号を採番できた回だけ数える (deep_equals の早期returnは seq=-1 のままなので数えない) - init() の再入ガードを同期で立てる。nextTickの中で立てると その1tickの間にもう一度呼ばれたとき二重初期化できてしまう - dashboard は is_fetching を足し、追い越された取得が 自分では準備完了を宣言しないようにする - ルート要素に data-gkill-view-ready を出す。真偽値をそのまま bindするとVueがfalseで属性ごと消すので文字列の三項で書く - waitForColumnViewReady を足し、rykv / mi の遷移と searchByKeyword / clickSidebarSearchButton で待つ - rykv.spec.ts / mi-board.spec.ts の生goto+waitForTimeout(2000)を navigateToRykv / navigateToMi へ置換し、playwright-not-migrated から外す
初期化の起動条件がサイドバーの @inited だったのを、 props.application_config.is_loaded の watch へ移す。 @inited は子クエリビューの「その節が描けた」の集約でしかなく、 「設定が来た」を表していたのは 「immediateの付いていない application_config watch から emit する子がいる」 という偶然だった。実際に律速していたのは rykv では rep/timeis/calendar/map の 4節、mi では CalendarQuery ただ1つで、しかもその節は application_config の フィールドを1つも読まない。そのため節を1つ画面から外すだけで @inited が 永久に飛ばなくなり、画面ごとスピナーで固まっていた (mi-sidebar-inited.test.ts がその事故を記録していた)。 - use-rykv-view.ts / use-mi-view.ts に is_loaded の watch を足し、 received_init_request で1回だけ init() する。共有rykvは既存の Shared view init が担当するので watch からは抜ける - onSidebarInited と @inited の配線、サイドバーの inited 集約 computed と emit する watch、emits の 'inited' 宣言を削除 - inited_*_for_query_sidebar フラグは残す。子へ :inited prop として降り、 子が「初回同期か再同期か」の判定に使っている(消すと props 同期のたびに チェックが列をまたいで累積する) - init() の query_editor_sidebar.value! を実ガードへ書き換える。起動条件が サイドバー自身でなくなったのでrefの存在を型の上で当てにできない。 空のFindKyouQueryへフォールバックすると既定期間も強制非表示タグも 落ちた列ができる(しかもエラーは出ない)ので、列を作らずに戻して 次のApplicationConfig再取得でやり直せるようにする - ハーネスに makeColumnViewProps / finish_application_config_load / attachFakeKyouListViews を足し、既存テストの onSidebarInited() 直呼びを is_loaded 経由の起動へ差し替える(アサート内容は変えない) - mi-sidebar-inited.test.ts を「各節のフラグが立つこと」と 「集約が復活していないこと」の検査へ作り替える
load_application_config() は res.errors があると write_errors して 早期returnし、ApplicationConfig の ref を差し替えない。さらに .catch() が 無く呼び出し元も await/catch していないので、通信例外は unhandled rejection になって同じく ref が差し替わらない。 いずれの場合も application_config.is_loaded が永久に false のままで、 画面の初期化(is_loaded の watch)が一度も走らず読み込み中オーバーレイの スピナーで固まる。エラーはスナックバーに出るが、画面は二度と使えない。 - rykv / mi / dashboard の3ページに application_config_load_failed を足し、 errors 経路と新設の .catch() で立てる。取得を始めるたびに倒す - オーバーレイの中身を v-if で差し替え、失敗時は文言と「再読込」ボタンを出す。 再試行は既存の requested_reload_application_config (dashboard は load_application_config) に乗せるので新しい経路を作らない - 文言は既存の i18n キーで足りる。7ロケール全てに FAILED_GET_APPLICATION_CONFIG_MESSAGE と RELOAD_TITLE がある - 共有rykvは設定を待たずに初期化するので false 固定で渡す
画面を開いたときの全画面オーバーレイは2段階あった。
(1) ApplicationConfig の読み込みを待つ
(2) 初期検索(rykv/mi) または初期fetch(dashboard) の完了まで待ち、
待ち終えてから QueryEditorSidebar 含めて画面全体を可視化する
このうち (2) を外す。
(2) は QueryEditorSidebar と KyouListView が密結合だったころの防御だが、
いまは列ごとの世代番号 search_seqs / query_id キーの abort_controllers /
emits_current_query の値比較ガード / run_with_sidebar_search_suppressed /
子クエリビューの props同期非emit が揃っていて、初期検索の飛行中に
サイドバーへ触られても取り違えない。むしろ待つほうが害で、検索が1本でも
解決しないだけで画面全体が固まる。進行は KyouListView の列スピナーと
フッタの「取得中」、dashboard は DnoteView / KyouListView の
ローディングで見せる。
rykv / mi:
- init() の hot reload ON/OFF の分岐を畳み、列の骨組み(querys /
querys_backup / match_kyous_list)を検索より前に確定させる。
1本ずつ足していくと「列が確定した瞬間」が定義できず、復元中に
ユーザが列を足したとき search(i, ...) の固定indexと衝突する。
querys_backup を先に埋めることで、機械的な残響が search() の
deep_equals 早期returnで確実に落ちるようにもなる
- 初期化の間じゅう skip_search_this_tick を立てっぱなしにするのをやめ、
run_with_sidebar_search_suppressed へ統一する。立てっぱなしだと
機械的なemitが1つ届いただけで onSidebarUpdatedQuery が消費し、
複数列のとき1列目の完了で抑止が途中で解ける
- 復元の検索を preserve_scroll=true で呼ぶ。inited が早期に立つので、
これを落とすと search() が scroll_to(0) を撃って復元先を潰す
- onSidebarUpdatedQuery の !inited 早期returnを外す。初期検索の飛行中でも
ユーザの編集を通す。同じ query_id を共有するので abort_controllers が
復元を中断し、search_seqs の世代照合が遅れて届いた復元結果を捨てる
- onColumnScrollList を「検索中の列の通知は捨てる」に置き換える。
リストを空にした副作用のスクロール通知を取り込むと、preserve_scroll の
復元先が0で潰れ保存位置にも焼き付く(定常状態の再検索でも同じ事故が
起きていたので純粋な改善)
dashboard:
- 初回の watch を fetch_for_date() へ寄せる。日付変更時の経路が既に
全画面オーバーレイなしのパネル単位ローディングで、そちらが理想形だった
初期取得の完了を待たずに画面を可視化する変更を、戻されないように固定する。 - rykv-view-initial-load.test.ts / mi-view-initial-load.test.ts (対)。 初期検索を pending のままにして「飛行中でも見えていること」 「1本も解決しなくても固まらないこと」「列の骨組みが検索より前に 確定していること」「飛行中のサイドバー編集が勝ち、遅れて着地した 初期検索の結果で上書きされないこと」「1列目の完了で抑止が解けて 2列目が誤検索されないこと」「検索中のスクロール通知が保存位置を 壊さないこと」「is_view_ready の3状態」「init のトリガが is_loaded で あること」「is_loaded が複数回立っても init は1回」「hot reload OFF でも即可視で検索は飛ばさないこと」を固定する - column-view-init-source-scan.test.ts。戻されると静かに壊れる4点 (initのトリガ / onSidebarUpdatedQueryの早期return / initでの skip_search_this_tick の立てっぱなし / data-gkill-view-ready の有無)を ソース走査で検出する - e2e/column-view-initial-load.spec.ts。get_kyous を遅延させて 「初期検索の飛行中にサイドバーと列が見えてハンバーガーも押せる」 ことを実ブラウザで見る。固定の待ち時間は使わない - CLAUDE.md の「列×検索の不変条件」の隣に初期化順序の節を足す - ABOUT_TEST.md / testing-guide.md の件数を verify_docs の実測へ更新
IDリストは各repのSQLへ ID IN (?, ?, ...) として展開される。Mi / MiReKyou は 5射影のUNIONで5本それぞれに同じリストを丸ごと展開するので、バインド変数は 5N+5 になり、 SQLiteの上限(SQLITE_MAX_VARIABLE_NUMBER=32766)を N=6553 で超えてPrepareが落ちる。 しかも失敗が GkillError にならず、/api/get_kyous も /api/get_kyous_mcp も HTTP 200 + errors:null + 0件で返っていた(内部のerrはDebugログにしか出ない)ので、 呼び出し側からは「成功・該当0件」と区別が付かなかった。実データでは確認待ちの記録 数千件のIDを一度に渡して踏んだ。 - reps 側の入口に findChunkedByIDs を置き、4000件ずつに割って和を取る。 IDリストはORの羅列なので分割しても結果は変わらない(塊どうしでIDが重ならないので 重複も出ない)。かかっているのは Repositories.findKyous / MiRepositories.FindMi / MiReKyouRepositories.FindMiReKyou と、GkillRepositories.FindTags / FindTexts の 最新版アドレスからIDリストを作っている箇所 - 検索が失敗したのに GkillError が空のときは message.EnsureNotEmpty で ERR000410 FindKyousError を必ず立てる gkill_repositories.go には、同じファイルにある最新版アドレスの一括読み取りヘルパと メモリキャッシュDBの MaxIdleConns 調整(どちらも次のパフォーマンス改修の一部)が 同居している。
実測では検索のCPUの約4割がGCで、SQLが遅いのではなく「1回の検索で作って捨てる オブジェクトが多すぎる」のが実体だった。効いた手だけを、ベンチと EXPLAIN QUERY PLAN で確認したうえで入れる。このマシンは同じコードでも ns/op が 倍近くぶれるので、判断は allocs/op・B/op・クエリプランで行った。 後段パイプライン(api/find_filter.go) — 20万IDで 329MB/503,202確保 → 156MB/1,062確保 - sortAndTrimKyousMap に len==1 の高速路。OnlyLatestData は usecase/kyou.go で 常にtrueに固定され、メモリキャッシュでは型ごとにrepが1つなので、実データでは IDの大半がバケツ1件。それでもIDごとにマップを作って slices.Collect で 集め直していた(121MB/401,045確保 → 12.6MB/514確保) - replaceLatestKyouInfos は入力スライスを再利用(73MB/201,045確保 → 12.6MB/515確保) - filterTagsKyous のOR分岐を「3マップ生成」から「1周して delete」へ。 結果マップと ResultKyous を事前確保 - AllTags(Tag構造体240B×全件)を48バイトの中間表現へ。用途は RelatedTagIDs を 埋めることだけだった - 結果ソートを32バイトのキー配列+その場でのサイクル置換へ。232バイト構造体の memmove が n回で済む ロックとプール - GkillRepositories.BeginLatestDataRepositoryAddressRead() を新設。結果1件ごとに syncState()(プロセス共有の sync.Mutex。遅延初期化のためだけに存在し本番では常に空振り) と RLock を取っていたのをループ1回に。並列ベンチで 3.44ms → 1.84ms - メモリキャッシュDBの MaxIdleConns を 1 から NumCPU へ。1だと2本目以降の接続が 返却のたびに閉じられ、プリペアドステートメントが毎回捨てられていた SQLと索引 - TIMEISキャッシュに START_TIME_UNIX / END_TIME_UNIX 索引。期間絞り込みが SCAN → SEARCH USING INDEX になる(plaing判定は逆に悪化するが、期間絞り込みは 検索のたび、plaingは show_attached_timeis が真の面だけなので採用)。 NOTIFICATION / GIT_COMMIT_LOG / TAG / MIREKYOU にも不足していた索引を追加 - UNION → UNION ALL(TimeIs 4箇所・MiReKyou 2箇所)。腕ごとに DATA_TYPE リテラルが 違うので腕をまたぐ重複は原理的に出ない。Mi だけは不可(下記) - timeis cached FindKyous の死んだ ORDER BY を除去(結果はマップに入るので捨てられる) - ? AS DATA_TYPE を FindKyous の経路から除去(kmemo / kc / lantana / nlog / git_commit_log / idf / urlog)。コンパイル時定数のために1行ごとに文字列を 確保し直していた - 空スライスの事前確保を20箇所から除去、GetAllTagNames の二重dedupを除去 - filterMiForMi の同一クエリ2回検索を IncludeCreateMi が真のときだけに - ReKyou の per-row 線形ID一致を集合へ、MiReKyou の WHERE無し全表スキャンを allowAll のとき省略 ログ - TraceSQL のログ引数の先行評価を停止(約1,092箇所)。Goは引数を呼び出し前に 評価するので、既定レベル none でも %q と reflect 整形が必ず走っていた (1行あたり約1.5〜2KB。キャッシュ再構築1回で GB 級)。 gkill_log の4ヘルパへ寄せ、出力はバイト単位で不変。 再発は no_eager_sql_format_test.go がソース走査で落とす 併せて GetKyou が最新版でないバージョンを返しうる不具合を18実装で修正した。 GenerateFindSQLCommon は query.OnlyLatestData ではなく引数の onlyLatestData しか 見ないのに false 固定で渡していたため、updateTime 未指定のときそのIDの全バージョンを 無順序で読み、格納順の先頭(多くの場合いちばん古い版)を返していた。 計測で否決したものは根拠をベンチに残した。 - multi-row INSERT は2万行で17倍遅い(bulk_insert_bench_test.go) - Mi の UNION ALL 化は不可。キャッシュ側の最新版判定が秒精度なので、同じ秒に 複数版があると腕の中で行が増える(mi_find_kyous_parity_test.go が落ちる) - Kyou への手書き MarshalJSON は確保が 600k → 200k に減るのに1.6倍遅い。 encoding/json が戻り値を compact() へ通すため(kyou_json_bench_test.go) pprof のリスナーは GKILL_PPROF_ADDR が設定されたときだけ立てる。未設定なら 現状とバイト単位で同一。
検索前後の無駄な往復と、数十万件配列の扱いを直す。 検索のたびに走っていた4往復を止める - delete_updated_gkill_caches() は rykv / mi / dashboard / plaing / ryuu の 検索のたびに呼ばれるのに、(1)空判定のために Cache の全 Request を実体化し (コード自身が「でかすぎると例外が飛ぶ」と認めていた)、 (2)get_application_config を not_load_all 無しで呼ぶので内部の load_all() が get_all_rep_names / get_all_tag_names / get_mi_board_list を追加で引き、 (3)キャッシュ削除を1IDにつき16回・逐次 await していた (既定の cache_clear_count_limit=3000 なら最大48,000回)。 cache_clear_count_limit を1つ読むためだけに毎回4往復していたことになる - ServiceWorker が同じ応答を2回パースしていたのを1回へ - get_session_id の cookie 走査から配列生成とクロージャを除去 数十万件配列 - 読み取り専用の全件走査を toRaw() 越しへ(局所挿入・reload・scroll×2・ 件数カレンダー・列走査)。deep reactive な配列は1要素読むたびに Proxy と WeakMap エントリを確保する。書き込みは今までどおりリアクティブ側に残す - 1行更新のたびの数十万件コピー2回を in-place splice へ。 これは正しさの修正でもある —— 配列を作り直すと focused_kyous_list (= match_kyous_list[focused_column_index] のエイリアス)が黙って切れ、 行を1件リロードしたあと件数カレンダーと Dnote がフォーカス列に追随しなくなっていた。 CLAUDE.md の「Ref を持つページは replace で copy-on-write する」を、 エイリアスされない dashboard / plaing / shared-mi に限る形へ更新した - refresh_kyou_in_list は書き戻す位置を await のあとに id で取り直す。 待っている間に局所挿入や削除でリストが動くと、待つ前のインデックスで splice して 別の行を潰す - InfoBase の attached 配列5本を遅延確保へ。検索応答には attached_* が 1つも含まれないので、数十万件ではその数倍の使い捨てになっていた - 画像モードの三重リロード(同じ reload() を呼ぶ watcher 3本)を1本へ - load_typed_datas を単一ディスパッチへ。11本の startsWith を並べたうえで 末尾のプラグイン判定で同じ11個をもう一度評価していた。 「mirekyou を mi より先に判定する」は宣言順ではなく、判定表を長い順に 並べ替えることで構造的に保証する - *_histories の二重 hydrate 11箇所を除去(API層が既に hydrate 済みだった) - dnote-list-aggregator の Array.find を Map へ 期間窓での分割取得(classes/kyou-search-windows.ts) 狙いは総処理量の削減ではなく、最初の行が出るまでの時間とサーバのピークメモリ。 全期間を1回で引くとサーバは全件を作ってから返す。7日 → 14 → 30 … と 新しい順に窓を切り、列へ追記していく。 分割してよいのは「レコード単体で合否が決まる検索」だけなので、for_mi・ TimeIs絞り込み・地図・plaing_time・is_image_only・上限なしは分割しない (緩めるとエラーも出ないまま結果が欠ける)。窓の境界を1秒ずらすのは、サーバが time.Unix() で比べるため。
保存マーカーの判定を「末尾がマーカーか」から「確定したマーカー行が前より増えたか」 (count_save_marker_lines)へ変えた。 原因は watch が flush: 'post' であること。1回のフラッシュ窓の中で本文が2回変わると watch は1回しか呼ばれず、**中間の値(マーカーで終わっている本文)は一度も観測されない**。 行数の多いタブでは行ラベル更新と不正行判定(get_invalid_line_indexs は行ごとに await)が メインスレッドを掴むので、その間に打たれたキーがまとめて着地して現実に起きる。 末尾で見ていると、この取りこぼしはエラーも出ずに黙って落ちる。 増分で見ることで次も同時に成り立つ。 - 1行目のマーカーも拾える(以前は先頭行だと末尾判定に当たらなかった) - 既にマーカーが残っている本文を編集しただけでは再送信しない 「確定した」= その行の後ろに改行がある、なので `!` を打った時点では走らない。 自動送信の入口が textarea の @input とテンプレート貼り付けの2つだけである点は そのまま。
verify_docs が測る件数のうち、今回追加したテスト/ベンチのぶんを反映する。 Go 889→891テスト・115→117ファイル、フロント 1851→1854テスト宣言・157→158ファイル、 合計 3,846→3,851 / 347→350。reps のテストファイルは40→41、 client/classes/datas は34→35。 ついでに、verify_docs の検査対象外でドリフトしていた2箇所も直した (src/ABOUT_TEST.md の「Go バックエンド全体(817テスト / 30パッケージ)」、 src/client/ABOUT_TEST.md の「データモデル | 29ファイル」)。
実機で「IMEから順当に入力すると発火せず、バックスペースを押すと発火する」と
報告された形を固定する。原因は既に直した flush:'post' の取りこぼしと同じで、
IMEは「変換の確定Enter」と「改行Enter」が別のキー入力になるため、
マーカー行の後ろに空行がもう1本入りやすい。
てすと
!
(空行)
旧実装の末尾一致(endsWith("(改行)!(改行)"))では、この本文の末尾は空行なので
打った時点で発火せず、バックスペースで最後の改行を消した瞬間にだけ発火していた。
行数の増分で見ている現行実装はどちらでも正しく1回だけ発火する。
追加したのは4本。
- マーカー行の後ろに空行が続いても保存が走る(報告された形そのもの)
- マーカーの後ろをバックスペースで消しても再送信しない(旧実装はここで発火していた)
- IMEの確定と改行が別々に着地しても保存が走る
- IME変換中(本文が変わらない)は発火せず、確定したら発火する
歯があることは、実装を一時的に末尾一致へ戻して確認した(4本中3本+既存2本が落ちる)。
E2Eには足していない。Playwrightは打鍵ごとにイベントループを回すので、
中間の「マーカーで終わっている本文」を必ず観測してしまい、
この取りこぼし(1回のフラッシュ窓に2つの変更が入ること)を再現できない。
既存の `保存マーカーで終わる本文を打つと自動で保存される` が経路の疎通を見ている。
前回の修正(末尾一致 → 行数の増分)でも直っていなかった。判定を watch に置いたままだったのが原因。
**同じ `input` イベントのリスナーとリスナーの間ではマイクロタスクが走る**(DOMの仕様上、
各リスナーの呼び出しごとに microtask checkpoint が入る)。そのため Vue の post flush
=本文の watch が、`@input` ハンドラより**先**に新しい本文を観測することがある。
IMEで「変換の確定」と「改行」を続けて打つとこの順序になり、
watch 側の「利用者が打った印」を中間の値を見た回が食べてしまって、
確定した値を見る回には印が残らず**判定そのものが走っていなかった**。
CDPで実際にIME合成を起こして再現させ、実装へ一時ログを入れて確定させた。
input てすと\n! ← compositionend からVueが合成したinput
watch てすと\n! ← ここで印を消費(増分0なので発火しない)
watch てすと\n!\n ← 印が無いので判定に入らない
input てすと\n!\n ← @input はこの後に走る
判定を `beforeinput` → `input` の対へ移した。この2つの間には何も割り込めないので、
フラッシュ窓の張り方にもリスナーの実行順にも依存しない。
- `beforeinput` で「変わる直前の本文」を控え、`input` で増分を見る
- watch は行ラベルと不正行の再計算だけに戻した
- タブ切替・localStorage からの復元では両イベントとも発生しないので、
「マーカーの残ったタブをクリックしただけで保存が走る」は構造的に起きないまま
- テンプレート貼り付けはイベントを通らないので、従来どおり直接判定する
E2Eに回帰テストを追加した(`IMEで確定してから改行しても自動で保存される`)。
**IMEはCDPの `Input.imeSetComposition` でしか再現しない** —— `pressSequentially` は
打鍵ごとにイベントループが回るので中間の本文を必ず観測してしまい、常に緑になる。
単体テストは実際のDOMの順序(v-model がモデルを更新 → `@input`)に合わせて
`beforeinput` → 代入 → `input` の形へ直した。
2026-08-18 に入れた「期間を窓へ刻んで複数回 get_kyous を投げる」 (classes/kyou-search-windows.ts)を撤去する。狙いは「最初の行が出るまでの時間」と サーバのピークメモリだったが、3つとも外していた。 - **総時間が伸びていた。** 1リクエストぶんの固定費が窓の数だけ掛かる。とくに getAllTags(全repの全タグ走査)は rykv の既定クエリでは tags が非nullなので find_filter.go:106 の条件が必ず真になり**毎回**走る。repのファンアウトと 最新版アドレスのスナップショットも同じ。窓数は既定31日で3、1年で6、下限なしで10 - **「検索が終わってもスピナーが回り続ける」ように見えた。** 1窓目の結果を列へ入れて 表示するのに、スピナーを消すのは全窓が終わったあとだから(実機で報告された症状) - **静かに取りこぼしていた。** サーバの期間判定は2段階で精度が違う ―― SQLは .Unix() (秒切り捨て)、passesPeriodFilter は time.Before/After (ナノ秒)。境界を1秒ずらすと、 境界Sに対する S-0.5秒 のレコードが新しい側では Before(S) に弾かれ、 古い側では After(S-1秒) に弾かれて**どちらの窓にも入らない** (秒未満を保持できるプラグイン・gitの記録が対象) あわせて「全件揃うまで件数を出さない」を明示した。読み込み中のフッタは LOADING_MESSAGE のままにし、has_loaded が立つまで「N件」を出さない。 件数カレンダー・Dnote・Ryuu・フッタ件数はどれも「列が全件を持っている」前提で 書かれていて、部分状態ではエラーも出さずに間違える (Ryuu は列の配列をサーバ検索の代わりに使うので、間違った「近くの記録」を返す)。 テストは窓分割の2本を「検索は期間が広くても1回で引く」 「mi板の列も期間が広くても1回で引く」へ置き換え、 「検索中の列に部分的な結果を出さない」を足した。 ピークメモリのために分割するなら、固定費を1回で済ませられるサーバの中でやること。 その判断は実データのプロファイルを取ってから行う。
find_filter.go の getAllTags は**全repの全タグ**を集めて RelatedTagIDs
(= タグが1つでも付いているIDの集合)を作る。実データでは1検索あたり数十万行になる。
ところが RelatedTagIDs の読み手は filterTagsKyous / filterTagsTimeIs の
NoTags("no tags" 仮想タグ)分岐しか無い(OR・ANDそれぞれ2箇所)。
つまり NoTags が条件に入っていなければ、この全走査は結果に一切影響しない。
起動条件が `Tags != nil || (HasTimeIsFilter() && TimeIsTags != nil)` だったので、
rykv の既定クエリは tags が常に非null(コンストラクタ既定が [] )ぶん、
タグを明示的に選んだだけの検索でも毎回まるごと無駄に走っていた。
条件を containsNoTags ベースへ絞る。タグ条件が空配列(= フィルタ有効かつ0件指定)の
ケースも走らなくなる。
非表示タグの集合(getAllHideTagsWhenUnChecked)は NoTags と無関係なので、
同じ if から切り出して従来の条件のまま残した。RelatedTagIDs には依存していない。
**壊れ方が静かなので両方向を固定した。** 走らせ忘れると RelatedTagIDs が空になり、
全件が「タグなし」扱いになってタグの付いた記録まで返る。
get_kyous_tag_filter_test.go を追加し、
「タグ名で絞る」「タグ無しで絞る」「両方(OR)」「空配列は0件」を固定した。
実装を `if false` にすると
「タグ無しで絞ると、タグの付いていない記録だけが返る」と、既存の
TestHandleGetKyous_TimeIsTagsFilterWorksWithoutKyouTagFilter が落ちることを確認済み。
削減幅は実データのプロファイルで確認する。ここで消しているのは
「結果に影響しないと確認できた仕事」なので、量に関係なく消してよい。
本番データのプロファイルで、rykv の検索の**実質CPUの半分近く(数十秒)が
タグ名の絞り込み**だった。内訳は cached SQLite tag rep が過半、
プラグインのタグアダプタが残りで、うち sqlite の _lowerFunc が全体の4割ほど。
tag rep のワード検索は findWordUseLike=false / ignoreCase=true なので
`LOWER(TAG) = LOWER(?) OR LOWER(ID) = LOWER(?)` を出す。列に関数がかかるため索引が効かず、
**全行に LOWER() を適用**したうえで、それをクエリのタグ名の数だけ繰り返す
(O(行数 × 名前の数))。利用者はサイドバーで多数のタグにチェックが入る構成なので、
名前の数がそのまま倍率になっていた。
「全部取ってGoで照合」に一本化しようとしたが、**ベンチで否決した**。
名前が少ないうちは全タグの実体化(reps.Tag は240B + 文字列10本)のほうが高い。
2万タグでの実測:
タグ名 SQLで絞る 全部取ってGoで照合
1 12.5ms 91確保 141.8ms 580,074確保
10 69.2ms 425確保 153.2ms 580,074確保
30 197.6ms 1,148確保 180.5ms 580,074確保 ← ここで交差
100 724.7ms 3,684確保 257.0ms 580,076確保
SQL側は名前の数に比例、Go側はほぼ一定。どちらも行数には比例するので、
**交差する「名前の個数」は行数によらずほぼ一定**。よって固定の閾値で切り替える
(maxTagNamesForSQLFilter = 32。確保の少ないSQL側へ寄せて交差点よりやや上に置いた)。
さらに、**「タグ無し」仮想タグを使う検索では名前の個数によらずGo側で照合する**。
RelatedTagIDs のために結局は全タグを取るので、そこから名前を拾うぶんはタダになる。
以前は「全タグの取得」と「名前で絞る検索」を別々に投げていた。
rykv の既定クエリはタグ条件に「タグ無し」が入るので、この経路が効く。
getAllTags と findTags を collectTagsForFilter へ統合した。
照合は strings.EqualFold の完全一致・大小無視で、filterTagsKyous のAND分岐と同じ意味論。
SQL は TAG 列だけでなく ID 列とも突き合わせていたので、そこも写してある。
**2経路が同じ結果を出すことを find_filter_test.go で固定した。**
ずれるとタグの個数によって検索結果が変わるという静かな壊れ方になる。
実測表は dao/reps/tag_find_bench_test.go に残した。
ns/op はこのマシンで倍近くぶれるので、判断は allocs/op と B/op で行っている。
前回の改修(タグ絞り込みの切り替え)の再測定で、次に浮上したのが
getAllHideTagsWhenUnChecked のぶんだった。実質CPUのうち、
起動直後にだけ出る git のフォールバックを除いたぶんの**約半分**。
これは直したばかりのものと同じ病気で、非表示タグの名前を1つずつ
GetTagsByTagName で引いており、その各回が `LOWER(TAG) = LOWER(?)` の全行スキャンになる
(findWordUseLike=false / ignoreCase=true。findTags とまったく同じ形)。
hide_tags の個数がそのまま倍率。
collectTagsForFilter へ畳んだ。「タグ無し」仮想タグを使う検索では
RelatedTagIDs のためにどうせ全タグを取るので、そこから非表示タグを拾うぶんはタダになる。
rykv の既定クエリはこの経路に入る。
閾値(maxTagNamesForSQLFilter = 32)は**クエリのタグ名と非表示タグ名の合計**で見るようにした。
どちらもSQLへ降ろすと全表を1回ずつ舐めるので、合計で数えるのが正しい。
**2経路が同じ結果を出すことを TestHandleGetKyous_HideTagsBothPaths で固定した。**
名前を33個にして閾値を越えさせ、SQL経路と同じ結果になることを見る。
ずれると「チェックしているタグの個数によって非表示が効いたり効かなかったりする」
という静かな壊れ方になる。Go側の収集を止めると実際に落ちることを確認済み。
前回の改修の効果(実測、180秒の窓・プラグイン読み取り待ちを除外):
実質CPU合計 90.9s → 52.3s (-42%)
タグ名の絞り込み 40.4s → 5.8s (-85%)
sqlite の _lowerFunc 17.1s → 3.6s (-79%)
プラグインのタグアダプタ 16.1s → 消滅
本番プロファイルで残っていた最大の項目が git rep の十数秒(実質CPUの過半)で、 go-git の Repository.Log() が全コミットをディスクから読み直していた。 「キャッシュ構築中だけ」「repの配線ミス」の2説は一時ログとinfoログでどちらも否定 (Reps に入っているのはキャッシュrep、isCacheBuilding は偽)。 真因は selectMatchRepsFromQuery の Step4。クエリが rep名を指定していると matchRep.UnWrap() でラッパーを剥がし、**生のディスクrepを MatchReps に登録して検索に使う**。 すぐ上の Step3 には「ここで UnWrap() してはいけない」と理由まで書いてあるのに、 Step4 には適用されていなかった。 **GUIは常に非nullの reps を送る**(FindKyouQuery のコンストラクタ既定が [] で、 apply_rep_summary_sets_to_detaul が必ず配列を入れる)ので、rykv/mi の検索は毎回この経路。 rykv は rep_types を送らないため、十数個のキャッシュrepが数百個の生repに展開される (実データの一例では数百rep の大半が端末別の重複登録)。 --cache_reps_local のローカルコピー層も剥がれ、クエリが外付けUSB上の元DBへ戻っていた。 影響はgitだけでなく全型に及ぶ(プロファイルにキャッシュ版でない idfKyouRepositorySQLite3Impl.FindKyous が数秒で出ていた)。 ## 直し方 rep名の絞り込みを「どのrepを検索するか」から「どの結果を残すか」へ移した。 FindQuery.Reps はSQLに降りていない(GenerateFindSQLCommon に参照0件)が、 キャッシュ表は行ごとに実rep名の REP_NAME を持ち Kyou.RepName に入るので結果側で絞れる。 - selectMatchRepsFromQuery … ラッパーのまま MatchReps へ入れる。 UnWrap() は「そのラッパに選ばれた実repが1つでもあるか」の**枝刈り判定だけ**に使う。 この枝刈りは省けない(省くとキャッシュOFF・「1種別だけチェック」・「一致0件」が悪化する) - findKyous … filterKyousByRepName で Kyou.RepName により結果を絞る。 本文ヒット由来の2本目の検索にも同じ絞り込みをかける - プラグインの Kyou.RepName が空なら manifest の rep_name で埋める。 申告をそのまま写しているだけだったので、結果側で絞ると rep_name を返さないプラグインの記録が丸ごと消えてしまう ## 意味論が変わらない根拠 OnlyLatestData は本番の全経路で true 固定。ID X について M=全rep横断の最大UpdateTime、 I=指定rep とすると、旧は「各leafの自表内MAXの行」、新は「横断MAX(=M)の行のうち RepName∈I」。 replaceLatestKyouInfos が全rep由来のアドレス表と突き合わせて 「最大がMに届かなければレコードごと落とし、届けば UpdateTime==M の行だけ残す」ので、 どちらも同じ集合に収束する。キャッシュOFFでは UnWrap() が自分自身を返すので完全一致。 ## 落とし穴(コメントとテストで固定した) 1. 本文ヒット由来の2本目の検索にも絞り込みが要る 2. 全部落ちたIDはキーごと消す(空スライスを残すと kyous[0] を見る後段が panic する) 3. Reps == nil は「未指定」。len() で判定すると全件消える 4. **RepName が空の行は残す。** キャッシュrepへの write-through は呼び出し側の値を そのまま INSERT するので追加直後の行は REP_NAME が空(実rep名が入るのは次の UpdateCache)。 落とすと**いま追加した記録が最大1分間一覧から消える**。 残しすぎても「チェックを外したrepの、たった今書いた記録が1分だけ残る」で済む 5. dao/reps 側には置かない。ReKyou/MiReKyou のワード委譲が利用者のクエリを そのまま FindKyousSequential へ渡すので、そこで絞るとチェックしていないrepに 参照先があるリポストが黙って語句検索に当たらなくなる キャッシュONでの rep絞り込みは今まで未テストだった(既存の TestHandleGetKyous_RepFilter は キャッシュOFFかつ「存在しないrep名で0件」しか見ていない)。ON/OFF両方で回すテストを足した。 SQLへの REP_NAME IN (...) 押し込みはやらない。leaf表に REP_NAME 列が無く (? AS REP_NAME でバインドしている)、REP_NAME は索引されておらず、 onlyLatestData の相関サブクエリにも足したくなる誘惑がすぐ隣にある(やると repごとの最新版が復活して古い版が現在版として見える)。必要なら実測してから別起案。
## 製品の不具合
**利用者がその場で作ったタグを、開いている列の検索条件へ足す**
(`classes/use-registered-tag-column-filter.ts` 新設、rykv / mi 共通)。
既定クエリは「絞らない」を `tags = null` ではなく「そのときの
`check_when_inited` タグ名の列挙」として物質化するので、localStorage に凍った
列の条件だけがタグ宇宙の成長に取り残される。タグが1つも無い時期に作られた列は
`tags = ["no tags"]` の1件だけになり、タグの付いた記録がサーバ検索でも
局所挿入でも1件も通らなくなっていた(エラーも警告も出ない)。
使うのは「そのタグがタグツリーに無かった」という決定可能な事実だけで、
既知のタグは利用者が外したのかもしれないので触らない。
`tags_and` の列は積が必ず空になるため対象外。ポートへは変更バスで配る。
**ログイン画面ではセッション無効の飛ばしを止める**(`is_on_login_page`)。
ログイン失敗も `check_auth` と同じエラーコード(存在しないユーザIDは ERR000002)を
通るので、素直に飛ばすと `location.replace("/")` でページごと作り直され、
出したばかりのエラー表示が消えていた。利用者からは「画面が一瞬光って、
理由も出ないまま元のまま」に見える。
## E2E
3件の失敗と2系統のフレークを解消し、フルランを 260/260 緑にした。
- `mi-operations` 2件: 仮想スクロールの描画窓(8行)を超えていたので
`searchByKeyword` を挟む(同ファイル4本目と同じ形、規約は pages/ABOUT_TEST.md)
- `kftl-multi-dialog` 2系統: Vuetify の reopenLock(50ms) がクリックを黙って捨てる。
aria-expanded が "false" になる時刻はその窓の始まりそのものなので
「閉じきるのを待ってから押す」では塞げない。開くまで押し直す形にした。
併せて `CONTEXT_MENU_ITEM` を `.v-overlay--active` まで絞り、
閉じかけのメニューを構造的に掴めなくした
## そのほか
保守棚卸し(コンポーザブル抽出・`any` 除去・命名規約の機械検査・MCP の
ライブラリ分割・重複ヘルパの一元化など)と、それに伴う資料の件数更新。
ユニット 161ファイル/2177テスト・E2E 260件・type-check・ESLint・verify_docs すべて緑。
## Go `4457a1b2`(rep名の絞り込みを結果側へ移した改修)のコミットメッセージが挙げる 5つの落とし穴のうち、**(5)だけ何の担保も無かった**。他にも実データ破損に直結する 経路が無防備だったので、まとめて固定する。 - `TestNoRepNameFilterInDaoReps` … `dao/reps` で `FindQuery.Reps` による絞り込みを しないこと。ReKyou/MiReKyou のワード委譲が利用者のクエリをそのまま `FindKyousSequential` へ渡すので、ここで絞ると**チェックしていないrepに参照先を持つ リポストが黙って語句検索に当たらなくなる** - `TestCommitTxSetsRealRepNameBeforeWriteThrough` … 13型すべてが、キャッシュへ 書き戻す直前に実rep名を入れること。コピペ形なので1型だけ抜けても他の12型は緑のまま - `TestCommitTxRestoresIDFTargetRepNameBeforeRealWrite` / `TestIDFKyouAddPersistsRepNameAsTargetRepName` … IDF だけは `TargetRepName` を **実DBへ書く前に**戻すこと。leaf の `AddIDFKyouInfo` が `TARGET_REP_NAME` 列として 永続化するので、一時repの合成名が入るとファイルの所在が実データごと壊れ、 `UpdateCache` でも直らない。この範囲で唯一の不可逆な失敗モード - `TestSelectMatchRepsFromQuery_PartiallyMatchedWrapperKeepsCachedRep` … キャッシュラッパが N 個の生repを持ち一部だけ指定されたとき。これが本番の形で、 「意味論が変わらない根拠」がまさにこのケースに依存しているのに未テストだった - `TestWarnPluginRepNameMismatchOnce_WarnsOncePerPair` … 不一致警告が組み合わせごと 1回だけであること(`sync.Map` の存在理由。レコードごとに出すと数十万行になる) `TestHandleGetKyous_RepFilter_CacheInMemory` を **UpdateCache の前後で2回**見る形へ 作り直した。追加直後はキャッシュ表の `REP_NAME` が空で、`filterKyousByRepName` の 「空の行は残す」分岐で全部素通りするため、**許可リスト側の分岐を一度も検証できていなかった** (`filterKyousByRepName` の許可リストを潰すと、cache_in_memory=true では 追加した段のアサーションだけが素通りし、新しく足した UpdateCache 後の段だけが落ちる)。 `gkill_server_api_test.go` の `TestHandleGetKyous_RepFilter` は 「キャッシュOFFで存在しないrep名を渡すと0件」しか見ておらず、上記に完全に包含される。 セットアップ費用だけが残るので削除した。 ## クライアント - `abort-error.test.ts` … 中断判定。**20箇所の手書きを集約した先**で、壊れると全箇所へ 同時に波及するのに、集約先の実装を実行するテストが無かった。判定はブラウザごとに 文言が違うのでメッセージで見るしかない(Chrome / Firefox 両方を固定) - `web-push-key.test.ts` … VAPID公開鍵のバイト列化。6ページ分の重複を集約した先。 なお `=` パディングの補完は `atob` が未パディングを許容するため観測できない (消しても全テストが通ることを実測した)。テストで固定できるのは URL-safe の記号変換とバイト列の中身だけなので、そう書いてある - `browse-zip-contents-dialog.test.ts` … 365行あってテストが1本も無かった。 しかも `src/client/ABOUT_TEST.md` は「ZIPファイルブラウズダイアログをE2Eでカバー」と 書いていたが、**E2Eに zip という語は1つも無い**(虚偽のカバレッジ申告) - `plugin-config-dialog.test.ts` … iframe からの保存依頼を親が肩代わりする経路。 `e.source` の判定を緩めると無関係なウィンドウから設定を書き換えられる 新設コンポーザブル69本のうち49本は40行未満の `useFloatingDialog` 薄いラッパで、 `src/ABOUT_TEST.md` の方針(型やコンパイラが保証済みのものは書かない)に反するため 意図的にテストを書いていない。判断理由は `classes/ABOUT_TEST.md` に明記した。 追加した各テストは、対応する製品コードを壊すと落ちることを1本ずつ確認してある。
`npm test` の最後2ステップが、この開発機では毎回こう落ちていた:
'gradlew.bat' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
`gradle_test.mjs` が `spawnSync('gradlew.bat', args, { cwd: projectDir, shell: true })` と
**裸のファイル名**を cmd へ渡していたのが原因。この機は
`NoDefaultCurrentDirectoryInExePath=1` で、cmd がカレントディレクトリを実行ファイルの
探索対象から外している。**探索順の問題であって作業ディレクトリの問題ではない**ので、
`cwd` を渡していても見つからない。
`.\gradlew.bat` も効かない ―― `shell: true` は引数をエスケープせず連結するだけなので
(Node が DEP0190 で警告する)、バックスラッシュが落ちて `.gradlew.bat` に化ける。
cmd を明示的に起動して**絶対パス**を渡す形へ直した(`shell` は付けない)。
エスケープの余地が無く、`cwd` の解釈にも依存しない。
spawnSync(comspec, ['/d', '/s', '/c', path.join(dir, 'gradlew.bat'), ...args],
{ cwd: dir, stdio: 'inherit' })
実測: 修正前は Gradle まで到達せず即失敗、修正後は
`BUILD SUCCESSFUL`(android 27秒 / wear_os 1分34秒)。
Gradle へ到達しないので「SDK が無い」等の見当違いな方向へ調査が向かいやすい。
同じ形を二度書かないよう `src/tools/README.md` に理由ごと残した。
今回の資料点検で出たドリフトは**例外なく verify_docs の assertion に登録されていない
箇所**に集中していた。数字を直すだけでは次回また同じところがずれるので、検査の穴を塞ぐ。
## 資料に載っているファイル名の実在検査(新設)
件数だけを検査していると「数は合っているのに一覧は古い」が通り抜ける。実例:
`classes/dnote/README.md` は `dnote-predicate/(31ファイル)` の件数検査を通ったまま、
削除済みの述語2件を表に載せ続けていた。
`documents/reverse/*.md` と `src/**/{README,ABOUT_TEST}.md` の本文から
`*.go` `*.ts` `*.vue` `*.mjs` `*.kt` を拾い、同名ファイルがリポジトリのどこにも
無ければ落とす。**入れた瞬間に17件のゴーストが出た。**
除外は2種類だけ。先頭が `_` の接尾辞パターン(`_repository.go`)と、
`xxx`/`yyy`/`zzz` を含むプレースホルダ。この2つを外すと55件に膨らみ、
うち38件は資料が意図して使っている記法だった。
## checkPaths のバッククォート対のバグ
`/`([^`]+)`/g` を生テキストへ当てていたので、コードフェンス(3連バッククォート)の
3本目と閉じフェンスの1本目が対になり、以降の対応が全部ずれていた。
実測で **223個中78個(35%)しか見ていなかった**
(`frontend-architecture.md` は528スパン中**0個**)。
フェンスを先に落としてから `[^`\n]+` で拾うように直し、対象も
`documents/reverse` + `CLAUDE.md` から `docMarkdownFiles()`(README / ABOUT_TEST 群を
含む)へ広げた。これだけで実在しない `public/sw.js` の参照が検出できるようになった。
## マニュアルの用語lint
- 禁止語に `Rudbeckia` / `rudbeckia` を追加(ポート画面の開発コード名。
現状マニュアル本文に漏れは無いが止め金が無かった)
- `<code>` の剥がしを `<code>` 完全一致から `<code` 始まりへ。
属性を1つ足すだけで遮蔽が外れて用語が露出するのに、検査は素通りしていた
- ただし `href` / `src` の値は落とす。ページのファイル名は開発コード名のままでよく
(`rudbeckia.html`)、利用者に見えるのはリンクの文字のほう。
これを入れずに `rudbeckia` を禁止語へ足すと、リンクを1本張っただけで7言語ぶん落ちる
## 数字の登録
ドリフトしていたものを assertion に足した。マニュアルのページ数、`CLAUDE.md` の
ビュー数(ダイアログ数だけ検査していた)、ルータのルート数(コンポーネント/リダイレクト
専用を別々に)、`screen-specs.md` の合計行の**括弧の中**、`documents/reverse/README.md` の
コンポーネント合計、`testing-guide.md` 本文の spec数・宣言数、`src/ABOUT_TEST.md` の
索引表、`src/client/ABOUT_TEST.md` のツリー内の件数、`src/server/ABOUT_TEST.md` の
カテゴリ表(合計行が「verify_docs と一致する」と自称していたのに未検査で、
実測125に対して78のまま放置されていた)。
検査を足したあと、わざと壊して落ちることを確かめてある。
## 事実として誤っていたもの - `screen-transition.md` の `OldSharedMiPage` の節。「マウント時に `router.replace` する だけのリダイレクタ」と書いてあったが、**それがまさに `bd9e8d43` で直したバグ**。 共有ページは `<script setup>` に top-level await のある非同期コンポーネントで、 初回ナビゲーションの解決中にその中から新しいナビゲーションを始めると遷移が完了しない。 いまはルータの `redirect` で、コンポーネントは存在しない - `error-handling-and-security.md` の「期限切れならクライアント側でログイン画面へ リダイレクト」。**ログイン画面では飛ばさない**(`is_on_login_page`)。ログイン失敗も 同じコード帯(存在しないユーザIDは `ERR000002`)を通るので、飛ばすと出したばかりの エラー表示がページごと作り直されて消える - プラグインの `cache_path.go` が「各プラグインにある」(6本が1文字違わず同じものを 持っていたので SDK へ集約済み)。`plugin-system.md` / `folder-structure.md` / `testing-guide.md` / `CLAUDE.md` / `src/plugins/README.md` のツリー6箇所 / 各プラグイン README 6本 - `program-spec.md` の `gkill_dao_manager.go:1081-1087`(実際は `:1118` / `:1129`)。 さらに `Reps` への追加は `EmitsKyouOrDefault()` でガードされている - `activity-diagrams.md` の `find_filter.go:513,624,656`(3つとも別の行を指していた)。 行番号は改修のたびに動くので落とした - 削除済みファイル17件が表やASCIIツリーに残っていた(`old-shared-mi-page.vue` / `edit-folder-dialog.vue` / `mood-operator.ts` / `text-content-*-predicate.ts` ほか) ## 自己矛盾していた数字 `CLAUDE.md` のビュー数203(実測202)、`screen-specs.md` の合計行の括弧が 「ビュー203 + ダイアログ116 + ページ15」で **334≠333**、 `documents/reverse/README.md` の307(実測333)、`testing-guide.md` 本文の 「40 specファイル・215テスト宣言」(同ファイル冒頭の表は44/250)、 `src/ABOUT_TEST.md` 索引表の894/719/18/1342、マニュアル21ページ(実測22)、 ルート数が「13」「14」「表14行」で三重に食い違い。 ## 挙動が資料に無かったもの - `sequence-diagrams.md` §7(Kyou検索)に `selectMatchRepsFromQuery` と 結果側の `filterKyousByRepName` を追加。この改修で最も影響を受ける図が未更新だった。 5つの落とし穴も表にした - `program-spec.md` §7 に「`UnWrap()` するとキャッシュ層を丸ごと飛び越える」罠 - `api-endpoints.md` の `reps` の意味論(null / 非nil空 / 指定、空 `rep_name` は残る) - `frontend-architecture.md` §12 に `use-registered-tag-column-filter.ts` - `screen-specs.md` §2.13 にホストしたビューの `fill_height` の約束(`d9a5ae6f`) - `plugin-system.md` にプラグイン `Kyou.RepName` の manifest 埋め - `CLAUDE.md` に `is_on_login_page` の約束 ## 古い一覧・欠落 未掲載のテストファイルを全部足した(Go: api 3 / gkill_server_api 4 / reps 9 / usecase 2 / sdk 4テスト、クライアント: classes 14 / api 3 / datas 5 / spec 6 / composable 35)。`usecase/ABOUT_TEST.md` は「専用テストは無い」と 書いてあったので書き起こした。`src/mcp/README.md` と `folder-structure.md` に 新設の `lib/` 8モジュールを追加(3サーバは1200〜1600行削られて薄いディスパッチャに なっている)。`src/client/ABOUT_TEST.md` の E2E baseURL は `localhost:5173` ではなく gkill_server 側。 `testing-guide.md` にあった spec ファイルごとの一覧は `src/client/pages/ABOUT_TEST.md` へのポインタに置き換えた。二重管理で 実際に取り残されていたため。 ## そのほか - `tsconfig.app.json` の `public/sw.js` は実在しない(`public/` は favicon のみ)。 ServiceWorker の実体は `src/client/serviceWorker.ts` で、vite-plugin-pwa が injectManifest 戦略でビルドする。幻の include を除去 - lint 表の「未移行E2Eのみ warn」は免除リストごと撤去済みなので全 spec error へ - `npm run vet_plugins` と CI の gofmt / `--max-warnings 0` / vet ステップを反映 `npm run verify_docs` は強化後の検査で緑。
## たどり着けないページがあった `rudbeckia.html`(ポート画面のヘルプ)は7言語ぶん存在するのに、「はじめに」の 画面一覧から一度もリンクされていなかった。実質たどり着けないページだったので、 ダッシュボードの次に行を足した。 `documents/reverse/user-guide.md` §5「各画面の使い方」にもポート画面が無く、 **ユーザ向け導入資料だけが抜けている唯一の画面**だった。節を新設した。 ## 同梱プラグインが5本しか載っていない 実際は6本。Codex が7言語すべての `plugin.html` から欠落していた。 `user-guide.md` §5.1 の表はさらに少なく3本だけで、Fitbit と Google ロケーション履歴も無かった。Takeout 系2本の「ZIPを解凍せず置く」注意も `plugin.html` にはあるのに `user-guide.md` には無かったので足した。 `user-guide.md` の「プラグインの設定を画面から変更する導線はありません」も誤り。 記録を右クリック →「プラグイン設定」で開ける(`plugin.html` には書いてあった)。 ## 新しく作ったタグの挙動 その場で作ったタグは、開いている絞り込み列の条件にも自動で加わる。 タグで絞り込んでいる一覧に、作ったばかりのタグを付けた記録を追加しても その記録が消えないようにするため。利用者から見える側の説明として `rykv.html`(7言語)と `user-guide.md` の「タグの付与」に1〜2文を足した。 ## メモ帳を複数枚開ける `kftl.html`(7言語)に節を新設。タブの一覧は全ウィンドウで共通で、 ウィンドウを閉じても書きかけは消えない。「いまどのタブを映しているか」だけが ウィンドウごと。同じタブを2枚から保存しても記録は1回しか作られない。 知らないと「閉じたら消えたと思って書き直す」ことになる。 ## 検査 編集は `manual_src` のみで、`npm run build_manuals` で154ページを再生成。 `verify_docs` の生成鮮度・言語構成一致・a11y・用語lintすべて緑。 `--parity`(日本語=正本に対する見出し/表構造)も全ページ一致。
`$HOME/Git/*` のような glob は zglob が**ファイルも返す**ので、Git フォルダに
`bash.exe.stackdump` のような非gitのファイルが1つ混ざることがある
(Git Bash のクラッシュダンプ。このリポジトリにも実在する)。
`gkill_dao_manager.go` は `errors.Is(err, reps.ErrNotGitRepository)` のときだけ
そのrepをスキップし、それ以外は `GetRepositories` を丸ごと失敗させる。
コメントにもあるとおり、失敗すると**そのユーザの全APIが ERR000018 になって
何もできなくなる**。
ところが `NewGitRep` は `git.PlainOpen` のエラーを `%w` で包み直すだけで、
**その型が OS で違う**:
Windows … ErrRepositoryNotExists(判別できる)
Linux … lstat <path>/.git: not a directory(ENOTDIR の *fs.PathError)
つまり Linux では `errors.Is(err, ErrNotGitRepository)` が偽になり、
スキップされずに `return nil, err` へ落ちる。**`a9b168d2` で直したはずの不具合が
Linux では直っていなかった**(配布物のうち linux_amd64 / linux_arm64 / linux_arm /
android_arm / android_arm64 のサーバがこれに当たる)。
gitリポジトリは必ずディレクトリなので、`PlainOpen` の前に `os.Stat` で
ディレクトリかを確かめ、ファイルなら `ErrNotGitRepository` を包んで返す。
OSに依存しない判定で、意図もそのまま読める。
`PlainOpen` のエラーを一律 `ErrNotGitRepository` に丸めるのは採らない。
権限エラーや壊れたリポジトリまでスキップに化けて、gitのコミットログが
1件も出ないことに気付けなくなる(`TestNewGitRepSuccessForGitRepository` が
その意図で置いてある)。
## 検証
CI(Ubuntu)はこの2件で **2026-08-15 の `a9b168d2` から赤いまま**だった
(最後に緑だったのは `00fd4b4b`)。Windows では再現しないので手元では気付けない。
- `TestNewGitRepReturnsErrNotGitRepositoryForNonGitPath`
- `TestGetRepositoriesSkipsNonGitEntriesInGitCommitLogGlob`
WSL で修正前の失敗を再現し、修正後に Windows(30パッケージ)と Linux の両方で
通ることを確認した。
`onlyLatestData := updateTime == nil` の直後に `onlyLatestData = query.OnlyLatestData` があり、最初の代入が使われていなかった。 **挙動は変わらない。** すぐ上の query リテラルが `OnlyLatestData: updateTime == nil` で組み立てられているので、 上書きしている値は同じもの。 問題は、なぜ `updateTime == nil` でなければならないかを説明した4行のコメントが、 **捨てられる行に付いていた**こと。「false のままだと updateTime 未指定のときに そのIDの全バージョンを無順序・無制限に読み、kyous[0] が格納順の先頭 (多くの場合いちばん古い版)を返す」という肝心の説明が、 読み手からは効いていない行の注釈に見える。 query から1回だけ読む形にして、コメントもそちらへ付け替えた。 同じ「宣言してから上書き」の形はこのパッケージの他の実装にも多いが、 そちらは初期値が `false`(ゼロ値)なので CodeQL は報告しない。 意味のある式が捨てられているのはここだけ。
2件の指摘レポート(HEAD=becea910)を12クラスタで裏取りし、 Critical 3・High 7・Medium 多数を実装。確立した不変条件は CLAUDE.md 本体へ集約した。 MCP / API 認可: - HTTPモードの1リクエスト文脈を不変 requestContext で引数伝播し、並行要求の user/session 混線を解消(C-02)。Bearer 未提示は401(C-01)、OAuth は S256 必須で 未登録 client_id を拒否 - 共有ページのファイル配信を共有クエリの結果集合でゲート(C-03) - 利用者入力URL・og:image 取得を api/safefetch 経由に統一(SSRF・無制限read・ 画像爆弾を遮断、既定 private 拒否)(H-04) - 型別 GetXxx(id,nil) が最新版を返す(H-07) - http.Server に ReadHeaderTimeout/IdleTimeout/MaxHeaderBytes、認証前ボディ上限、 全レスポンスにセキュリティヘッダ(H-03) - MCP の get_kyous_mcp が静かに握り潰していた部分欠落を partial/warnings で表面化(M-05) サーバ内部: - IDF走査停止フラグを参照カウント化し、重なるアップロードの取りこぼしを解消(M-02) - find_filter の TimeIs 絞り込みを Kyou と対称化(SQL/Go 2経路、閾値32)(M-5) - CLI サブコマンドを RunE + SilenceUsage 化し失敗で exit 1、ユーザ毎ループは errors.Join で集約・成功分は即出力(M-8)、KFTL の mi ラベルを strip_prefix へ - ログインの非存在ユーザ/パスワード誤りを同一 error_code + 文言に統一し ダミー Argon2id を実行(ユーザ列挙対策) プラグイン: - chatgpt/claudeai/claudecode を常駐ビルダ + WAL + バッチcommit へ移行し、 デッドラインkill→進捗ゼロループを解消(M-6) モバイル: - Android 同梱サーバをループバック限定(--address 127.0.0.1:9999)、回転で Activity を 保持、network_security_config で cleartext を localhost 限定、外部ストレージ権限に maxSdkVersion、起動ゲートを非ブロッキング化(S3-android-main/M-15) - Wear の TLS を trust-all から TOFU + フィンガープリント一致へ(H-05)、送信を WorkManager 化して Service 破棄を跨ぎ、KFTL 送信にサーバ側冪等キーを追加 (メッセージ毎 UUID を不変入力に載せ、成功時のみ TTL 記録)(S3-wear) CI / ドキュメント: - nightly.yml(full E2E / gradle / govulncheck / npm audit)追加、Actions を commit SHA pin 化、release に SHA256SUMS 出力(M-12/S3-ci/L-03) - documents/reverse・各 ABOUT_TEST・README・マニュアルを最新化し verify_docs を緑に APK リリース署名(item 7)とメモリ/性能 M-10/M-11(item 8)は環境待ちでスコープ外。
CLAUDE.md と各所のコメントに「なぜその形なのか」が溜まっていたが、 却下した案と実測値は書き残す場所が無く、逆方向の変更が「改善」として 何度も提案される状態だった。 - documents/adr/ に44本の ADR と索引・テンプレートを置く。採番は サブシステム別に10番刻み(検索/DAO/プラグイン/クライアント/ セキュリティ/MCP/開発規約)。番号と slug は採番後不変で、覆すときは Superseded で新しい番号を採る - 実装側には3行のアンカーコメントを置き、ADR へのパスだけを書く。 規則そのものはコードコメントの持ち分のまま(正本を二重化しない) - verify_docs に checkADR() を足し、6つの必須見出し・Status の値・ Rejected alternatives が空でないこと・Related tests のパス実在を機械検査する。 CLAUDE.md の ADR 件数もコードから突合する
APK の MainActivity は gkill_server に --address 127.0.0.1:9999 --disable_tls を渡していた。 どちらも設定 DB を書き換えない実行時上書きなので、サーバは ENABLE_THIS_DEVICE の行を読みながら 待受アドレスと TLS だけは無視し、設定画面で変えて保存しても Android では何も変わらなかった (エラーも出ない)。WebView のアドレスも常に http://localhost:9999 で、Kotlin 側にも 9999 が 直書きされていた。 - 起動引数から --address と --disable_tls を外した(--gkill_home_dir と --log だけ)。 待受・TLS はこの端末の設定行(ADDRESS / ENABLE_TLS)に従う。新規の置き場の既定は 127.0.0.1:9999 +「ローカルアクセスのみ許可」なので、既定では今までどおり LAN に出ない - 画面のアドレスは、サーバが ServerConfig から組み立てて標準出力に出す起動行 (close.go の PrintStartedMessage。デスクトップ版と同じ組み立て方)だけから取る。 Kotlin の 9999・10 秒待ち・フォールバック URL は削除した。起動行はループバックの http / https だけ受け付ける(ADDRESS をポートだけにしたときの "http://localhost9999" などは捨てる) - サーバ設定を保存すると起動行が出直すので、オリジン(スキーム・ホスト・ポート)が 変わったときだけ WebView を開き直す。同じなら開いているページを保つ - 起動行はポートを開く前に出るので、ポートが応答するまで別スレッドで待ってから開く (読み取りスレッドは stdout を吸い続ける)。起動したプロセスが終了したら待つのをやめる。 60 秒たっても起動行が出なければ通知する - 既存サーバの再利用(先行プローブ)は、前回拾った URL(SharedPreferences)のポートで行う - TLS 有効時の自己署名証明書は onReceivedSslError でループバックのホストに限って通す。 ループバックへの http をサーバ認証なしで受け入れているのと同じ強さなので、ピン留めはしない ADR-1104 を追加(却下案: --address の維持、ホストだけループバック固定、Kotlin で server_config.db を読む二重実装、URL を出すサブコマンド、証明書のピン留め)。 gkill-mobile スキルの約束と description、AGENTS.md のルーティング表・症状表、 gkill-go-backend スキル、operations-guide.md、user-guide.md の Android 節、 network_security_config.xml のコメント、テスト件数の表を追随させた。Go 側は無変更。 MainActivityUnitTest は 9999 と --address の定数を確かめる4件を外し、起動引数に 上書きフラグが無いこと・起動行の URL 取り出し・ポート・同一オリジン・ループバック判定を 足して 19 件。npm run test_android(19 件成功)と npm run verify_docs が通ることを確認済み。 実機での確認(設定変更で開き直すこと、TLS 有効時に開けること)は未実施。
…ocal を確かめ、ログのパスを %q で包む
利用者ごとのスキル(dao/skills)の追加で、go/path-injection 5件・go/zipslip 1件・
go/log-injection 1件が出ていた。実行時は NormalizeFilePath の正規表現・zip 側の ".." 拒否・
joinWithin の filepath.Rel 検査で守れていて実害は無いが、CodeQL は Rel の結果への判定を
バリアと認めず、joinWithin が返すパスを汚染されたまま書き込み先(WriteFile の一時ファイルと
rename、zip 展開の MkdirAll と Create)へ流していた。
- joinWithin: 結合の前に filepath.IsLocal を確かめる。path-injection はこの真分岐をバリアとして
認識し、zipslip も同じバリアを遡って使うので、パス5件と zipslip 1件はこの1箇所で消える。
検証を通ったパスは常に IsLocal も通るので挙動は変わらない(Rel の検査はそのまま残す)
- ".." を ReplaceAll で除く形(dao/reps/local_rep_cache_path.go)はここでは使わない。
"a..b.txt" は正しいファイル名で、黙って ab.txt に書かれてしまう
- removeQuietly: ログの path を fmt.Sprintf("%q", ...) で包む(log-injection のバリアの形)
テスト: TestJoinWithin と TestFileNameWithDoubleDotKeepsItsName を追加し、".." を含む名前が
書き込みでも zip の置き換えでも同じ名前のまま保存されることを固定する(joinWithin を
ReplaceAll 型に書き換えると落ちることを確認済み)。手元の npm run codeql -- go で
dao/skills の指摘が0件になることを確認。テスト件数 1405 / 211 / 33(Go)・
合計 5,227 / 509 を資料へ追随。
…版)を使う companion の GkillApiClient が /api/get_timeis の timeis_histories を末尾から取り、最新版として 扱っていた。サーバは update_time の新しい順で返す(time_is_repositories.go の SortFunc)ので、 末尾は最古の版になる。Web(gkill-api.ts・datas/kyou.ts)も MCP(write_handlers.go)も先頭を使っている。 - endTimeis: 最古の版に end_time を付けて update_timeis で書き戻していたため、作成後に入れた タイトル変更などがエラーも警告も出ないまま巻き戻った - getPlayingTimeis: 時計の実行中一覧に元のタイトルが出ていた どちらも histories.first() に直し、コメントと手順の説明を合わせた。 テスト: GkillApiClientTest に、新しい順で2版ある履歴の fixture で実行中一覧のタイトルと 終了の書き戻し本文を見る2本を追加(修正前に落ちることを確認済み。既存の fixture は履歴1件だけ だったので見逃していた)。テスト件数 232 / 18(Wear OS)・合計 5,229 / 509 を資料へ追随。
言語をまたぐ呼び出しを資料から追えるようにする作業の中で、図に書かれた名前がコードに無いものを直す。 - sequence-diagrams.md §4 addKmemo(session_id, kmemo) → add_kmemo(req)、 §18 browseZipContents(session_id, idf_kyou_id) → browse_zip_contents(req) - 同 §15(Wear OS): requestTemplates() → sendGetTemplatesRequest()、login(user_id, password) → loginWithError(userId, passwordSha256)、getApplicationConfig(session_id) → getKftlTemplateStructJson(sessionId)、 submitKFTL(kftl_text) → sendSubmitRequest(kftlText, force)、submitKFTLText に idempotencyKey を足す - scenario.md: add_mi_re_kyou(req) → add_mirekyou(req)、MCP の GkillReadClient / normalizeKyouArgs / callRead → GkillClient / NormalizeKyouArgs / CallContext.callApi(中で GkillClient.CallApi) - dvnf-rep-type-spec.md: GkillAPI.getApplicationConfig() → GkillAPI.get_application_config() 同じ言語の中の図の古さ(class-diagrams.md の実在しない constructor など)はこのコミットでは触らない。
画面の TS が Go のハンドラを呼ぶところは "/api/xxx" という文字列だけでつながっていて、 呼び出しグラフ系の道具(CodeGraph / Graphify)では辿れない(graphify path で「経路なし」)。 既存の資料もパスまでしか書いておらず、TS のメソッド名・Go のハンドラ名との対応は追えなかった。 こうした文字列だけのつながりを1か所に集め、手書きの表を verify_docs がコードと突き合わせる。 表を生成しないのは ADR-0709(ルート情報の生成は却下)と同じ理由。 資料(documents/reverse/cross-boundary-map.md)の14の表: - Web → Go の全97ルート(TS メソッド・他の呼び出し元・Go ハンドラ・実装ファイル・usecase か直接使う DAO・Go / TS の型)。命名規則から外れる箇所に ※ を付ける - Service Worker、/api 以外のサーバの経路と vue-router、MCP(公開37ツール・EntityTargets・HTTP の経路)、 Wear OS(時計↔スマホの Data Layer、companion → /api)、CLI、プラグインの stdio コマンドと起動フラグ、 iframe の postMessage、両言語で揃える約束(字面のあるものは全置き場所で検査)、対にならない req_res ファイル verify_docs(src/tools/verify_docs.mjs): - checkCrossBoundaryDoc: 14の表をルート表・ハンドラ・GkillAPI・serviceWorker.ts・MCP・companion・CLI・ プラグイン本体と SDK・postMessage のキーと双方向に突き合わせる。Web → Go の行が欠けたら貼ればそのまま 通る1行を出す。※ の付け忘れ・付けすぎ、並び、委譲先の字面がハンドラ本体にあるかも見る。 MCP・Wear・CLI・Service Worker が叩くパスがルート表にあるかは、これまでどこも見ていなかった - コードから読んだ件数が最小値を下回ったら落とす(正規表現の空振りで資料側を0件に直す事故を防ぐ) - checkReverseDocIndex: reverse の各資料が README(読む順・要約表・依存図)と folder-structure のツリーに載っているか - 件数検査を追加: reverse 資料の本数(3箇所)、Web クライアントの /api アドレス数とメソッド数、 スキルの古い「92 endpoints, 90 registered」を97へ - countComposedToolNames を集合版 composedToolNames の上に置き直す(MCP のツールとサーバの対応に使う) ほか: frontend-architecture.md の古い数(88 / 3件 → 93 / 91 / 4件)、gkill-api.test.ts の update_cache の コメント(CLI が叩いている)を直し、境界を足す人が気づけるよう gkill-go-backend / gkill-mcp / gkill-mobile / gkill-plugin / gkill-docs の各スキルと AGENTS.md に案内を1行ずつ足した。 テスト: verify_docs.test.mjs に23本追加(合成のソースと資料で固定。CRLF も通す)。資料をわざと 壊した5通り(行の削除・※ の外し忘れ・実在しない字面・Wear のパスの削除・契約の置き場所の誤り)で 場所と直し方の分かるエラーが出ることを確認。テスト件数 83 / 3(ツール)・合計 5,252 / 509 を資料へ追随。
…設定の TS 側の置き場所) 表の突き合わせ(checkCrossBoundaryDoc)が見ない説明文を読み直して、コードと違っていた3箇所を直す。 - service-worker の表: force_reget は「素通し」ではなく、キャッシュを見ずに取り直して入れ替える - server-prefix の表: 画面の経路が初回登録へ回すのは、admin のパスワードが未設定(初回起動直後)で 同じマシンからの画面遷移のときだけ(utils.go の ifRedirectResetAdminAccountIsNotFound) - contracts の表: サーバ設定の JSON キーの TS 側は gkill-api.ts ではなく server-config.ts
acquireCallSlot は、待ちの上限タイマーと呼び出し元 ctx の期限のうち早いほうで待つのをやめる。 callCommand は待ちの上限を呼び出し元の残り時間にそろえるので、2 本はほぼ同時に切れる。 両方が届いた select はどちらを選ぶか決まらず、負荷が高いときだけ ctx の側が選ばれて context.DeadlineExceeded が返っていた(関数コメントの約束は ErrPluginBusy)。 フルテストの中でだけ TestPluginRepository_QueueTimeoutDoesNotReapProcess が落ちた(単独では毎回通る)。 期限で待ちが終わったのはスロットが空かなかったからなので、ctx の期限切れも ErrPluginBusy にそろえる。 キャンセル(結果が要らなくなった)はこれまでどおり context.Canceled を返す。 呼び出し側は 2 つを分けて扱っておらず、変わるのはエラーの理由表示だけ。 TestAcquireCallSlot_DeadlineWhileQueuedIsBusy を足した。期限を先に切らせて、期限の側の結果を毎回確かめる。 修正前の実装では落ち、修正後は通ることを確かめた。
…デン・予算を追随 ## 変更 - gkill_add_skill の name の説明に、実装の正規表現どおり「先頭と末尾は英数字」を足す - help の skills 項目に、実装が拒否する条件と返すコードを書く。要素末尾の「.」・Windows 予約名・ 大文字小文字だけ違う既存ファイル・ファイルとフォルダの衝突(400)、SKILL.md の綴りの固定、 無いスキルへの付属ファイルの書き込み(404)、revision 指定でファイルが無い(404)、 既にあるスキルへの追加(409)、description が空(400)、gkill_status の skills_error - skill_handlers_test.go に、拡張子ごとの MIME と画像判定、画像以外のバイナリは image ブロックを出さず base64 を残すこと、空の一覧の要約、追加時に本文の先頭空白を削らないことを足す - ゴールデンを GKILL_MCP_UPDATE_GOLDEN=1 で作り直し、tool_schema_budget.json を更新(write / readwrite とも +84 バイト) - mcp/README.md・ABOUT_TEST.md・gkill-mcp スキルを現状へ(Read 13 / Write 23 ツール、help の topic に skills、 gkill_status の skills[] と skills_error、要求コーパスの件数) ## 接続中の AI クライアントへの影響 write と readwrite の schema_revision が変わる(229b98200b32 → cda4d3626426、0e5322393cdf → 174da3648e55)。 接続済みのクライアントは接続し直す必要がある。read は変わらない。
…の索引網羅と表の和の検査を足す ソースを正として、v1.1.9 以降に入った変更(スキル・検索条件ダイアログの統合・ID 前方一致の 7 文字・ 支出の複数行・日付ピッカー・並べ替えの挿入線・Android の起動と待受)を追いかけた。 足したのは「実装の該当行を消しても build も型検査も通り、エラーも出さずに間違った結果を返す」種類だけ。 ## 追加 Go - スキルの保存層: 利用者 ID の大文字小文字だけが違うとき、他人のスキルへ書き込めずに拒否されること (Windows で素通りする経路)、壊れた CRC の zip、「./」で始まる項目、最上位が 2 フォルダの zip、 読み出し上限ちょうどの大きさ、無いスキルへの revision 付き書き込み、名前の食い違い、ログのパスの %q - スキル API のエラーの写し: 9 つの番兵がエラーコード・HTTP 状態・補足に写ること、未知のエラー、 無いファイルの 404 を get / delete / write の 3 つの入口で - ワード検索の ID 前方一致が 6 文字では当たらず 7 文字から当たる境界(SQL と SDK) - スキルの置き場所が --gkill_home_dir の配下になること、Android が URL を拾う起動行の http / https とポート クライアント - 検索条件ダイアログで、実行中エディタ・タスクのショートカット・ダッシュボードのタスク条件を触ったときに 適用で渡すこと、開いた設定を書き換えないこと。設定画面から各ダイアログへの配線(ソース走査) - 支出の追加で金額が空・未入力の行を保存しないこと - カレンダー 2 種・地図・ダッシュボード・ライフログビューの日付ピッカー - 並べ替えで掴んですぐ離したとき元の行が薄いまま残らないこと、集計ビューの表の key と見出しの配線(ソース走査) Android - SSL エラーの判定・ps の行の解析・起動ゲートの判断を companion の純関数へ切り出し(挙動は同じ)、 本番の関数を呼ぶテストに。SSL 判定のホスト解析は URL の authority を切り出してから java.net.URI で行う - マニフェストの権限・requestLegacyExternalStorage と、2 つのレイアウトに findViewById の全 ID があることの走査 ## 直した・消した - 表明が自分自身との比較だけだった serverBinaryName_isGkillServer を消し、実装を写していただけの 2 本を本番の関数を呼ぶ形へ - 本番から参照されていない BuildManifest と、そのテストを消す - 支出の「title is blank」のテストが店名のエラーで通っていたので、品名のエラーを確かめる形へ - フルランで不安定だった E2E 4 本の原因を直す。並列に走る他のテストの記録に押し出されて 仮想スクロールの描画範囲から外れていた 3 本(テキストの編集、ダイアログを開いたままの画面切替、種類の混在)は、 本文で絞ってから見る。種類の混在のテストは、題のとおりタスクも一覧に出ることを確かめる。 リポストの行を右クリックしてもメニューが出なかった 1 本は、種類別のデータを読み終える前の右クリックが 捨てられていたので、メニューの項目が出るまで右クリックをやり直す補助関数を足した ## verify_docs - これまで検査していなかった件数の語句を登録(認証の種類ごとのエンドポイント数、ダイアログ数、 ダイアログのうちフローティングの数、MCP の要求コーパス件数とツール数、API の README のファイル数、src/ABOUT_TEST.md の索引行) - 検査を 2 つ追加: 全テストファイルがどれかの ABOUT_TEST.md に載っていること、 src/server/ABOUT_TEST.md の分類表の和が合計行と一致すること - 個人情報の検査で、作業ツリーから消したが索引に残っているファイルは索引の版を読む(ENOENT で検査全体が止まっていた) ## 資料 ABOUT_TEST.md と testing-guide.md の件数と一覧を実測へ(テスト宣言 5,252 → 5,322、テストファイル 509 → 515)。 載っていなかったテストファイルを全部載せた。 境界対応表の「Android が URL を拾う起動行」のテスト欄に、今回足した Go 側のテストを載せた。 E2E の落とし穴の表に読み込み中の右クリックが捨てられることを足し、リポストの行の特定手順を補助関数の実際の引数に合わせた。
対象の変更: スキル、設定の検索条件ダイアログの統合、ワード検索の ID 前方一致の 7 文字、 メモ帳のタブ名とタグ履歴、支出の複数行、カレンダーと地図の日付ピッカー、集計ビューの列の追加と削除、 並べ替えの挿入線、Android の保存先・権限・待受、Wear OS の版履歴の先頭。 ## 設計資料(documents/reverse) - API・プログラム仕様・用語集(スキルと revision の項)・画面仕様・画面遷移・フロントエンド構成・ フォルダ構成・運用ガイド・クラス図・MCP 導入手順・プラグイン・ユースケース(スキル)・ シーケンス図・シナリオ・アクティビティ図 - エラー処理とセキュリティ: スキルの保存先の独自のパス防御、ERR000419〜444、404 と 409、 Android の保存先が共有ストレージに戻ったことで何が露出するか、スキルを素のテキストで表示する理由 - 利用者ガイド: 検索条件ダイアログの 3 つのセクション、スキル、バックアップ対象に skills/、 メモ帳のタグ履歴、支出の複数行、ID の 7 文字、起動画面の選択肢と「テンプレート構造」の名前 ## README API・ハンドラ・要求と応答・DAO・クライアント・Android・Wear OS・プラグインの README を現状へ(件数は実測)。 ## ADR - ADR-1105 Android の保存先を /sdcard/gkill に戻し、権限が許可されるまで起動しない - ADR-0412 検索条件ダイアログは、適用で触ったセクションだけを渡す ## スキル・AGENTS.md gkill-plugin(7 文字、ADR-0114)、gkill-mobile(版履歴の先頭、requestLegacyExternalStorage、ADR-1105)、 gkill-client-kftl(タグ履歴、タブの最小幅)、gkill-docs(ADR の件数、用語検査の対象)、AGENTS.md の症状表。
…ログビューの API キーの場所と支出の複数行、実行中の絞り込み、メモ帳のタグ履歴(7言語) - ダッシュボード: 地図の上の日付を押すと日付ピッカーが開き、ダッシュボードの表示日ごと移る - AI連携: 連携の種類ごとにスキルでできること、埋め込み転送のサイズ上限がスキルのファイルにも効くこと、 スキルの zip の取り込み規則(名前の決まり方・剥がされるフォルダ・取り込まないファイル・名前とファイル名の規則) - サーバ設定: スマートフォン(Android)アプリでの待受アドレスの書き方と、変えたときの開き直し - ライフログビュー: Google Map の API キーを入れる場所の誤りを直す、支出を複数行で追加できること - 実行中: 設定の「検索条件」ダイアログで表示を絞れること - メモ帳: 付けたタグがタグ履歴に入ること - 困ったとき: スマートフォン(Android)アプリが権限を許可するまで起動しないこと
… とコメントの参照 過去の全コミットから実環境由来の値を取り除く書き換え(4 回目)で、全コミットのハッシュが変わった。 ファイル名やハッシュ値で旧コミットを指していた箇所を、書き換え後の値へ直す。 - リリースノート 9 本(v1.1.1〜v1.1.9。v1.1.0 以前は書き換えの起点より前なので変わらない)のファイル名の 8 桁と、一覧の表の 40 桁 - ADR 14 本にある実在のコミット参照 20 種(Sources・本文) - src/server/gkill/dvnf と main の ABOUT_TEST.md、dao/reps の Go コメント 2 か所、client のソース走査テストのコメント - リリースノート一覧の注意書きを、書き換えの回数と今回の内容に合わせて直す 以前の書き換えで既に失効していた ADR の参照(旧 SHA)は、前回までと同じくそのまま。
履歴書き換えに伴う追随で、リリースノート v1.1.1〜v1.1.9 のファイル名(末尾 8 桁)は 新しいハッシュへ改名したが、一覧の表のリンク(表示文と href)は旧ファイル名のままだった。 追随の置換が単語境界で区切っていたため、`_` に続く 8 桁がファイル名の中で一致しなかった。 verify_docs はリリースノート配下をリンク検査の対象外にしているので、機械検査でも止まらなかった。 - 一覧の表 9 行のリンクを、実在するファイル名へ直す
Bumps the npm-minor-patch group with 10 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@googlemaps/js-api-loader](https://github.com/googlemaps/js-api-loader) | `2.1.1` | `2.1.3` | | [dompurify](https://github.com/cure53/DOMPurify) | `3.4.15` | `3.4.16` | | [marked](https://github.com/markedjs/marked) | `18.0.13` | `18.0.14` | | [vuetify](https://github.com/vuetifyjs/vuetify/tree/HEAD/packages/vuetify) | `4.2.1` | `4.2.2` | | [@types/google.maps](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/google.maps) | `3.66.3` | `3.66.4` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.6.2` | `26.6.3` | | [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) | `10.11.0` | `10.11.1` | | [jsdom](https://github.com/jsdom/jsdom) | `30.1.0` | `30.1.1` | | [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.3.0` | `8.3.1` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `5.0.1` | `5.0.2` | Updates `@googlemaps/js-api-loader` from 2.1.1 to 2.1.3 - [Release notes](https://github.com/googlemaps/js-api-loader/releases) - [Changelog](https://github.com/googlemaps/js-api-loader/blob/main/CHANGELOG.md) - [Commits](googlemaps/js-api-loader@v2.1.1...v2.1.3) Updates `dompurify` from 3.4.15 to 3.4.16 - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](cure53/DOMPurify@3.4.15...3.4.16) Updates `marked` from 18.0.13 to 18.0.14 - [Release notes](https://github.com/markedjs/marked/releases) - [Commits](markedjs/marked@v18.0.13...v18.0.14) Updates `vuetify` from 4.2.1 to 4.2.2 - [Release notes](https://github.com/vuetifyjs/vuetify/releases) - [Commits](https://github.com/vuetifyjs/vuetify/commits/v4.2.2/packages/vuetify) Updates `@types/google.maps` from 3.66.3 to 3.66.4 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/google.maps) Updates `@types/node` from 26.6.2 to 26.6.3 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `eslint-plugin-vue` from 10.11.0 to 10.11.1 - [Release notes](https://github.com/vuejs/eslint-plugin-vue/releases) - [Changelog](https://github.com/vuejs/eslint-plugin-vue/blob/master/CHANGELOG.md) - [Commits](vuejs/eslint-plugin-vue@v10.11.0...v10.11.1) Updates `jsdom` from 30.1.0 to 30.1.1 - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](jsdom/jsdom@v30.1.0...v30.1.1) Updates `vite` from 8.3.0 to 8.3.1 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.3.1/packages/vite) Updates `vitest` from 5.0.1 to 5.0.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.2/packages/vitest) --- updated-dependencies: - dependency-name: "@googlemaps/js-api-loader" dependency-version: 2.1.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@types/google.maps" dependency-version: 3.66.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@types/node" dependency-version: 26.6.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: dompurify dependency-version: 3.4.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: eslint-plugin-vue dependency-version: 10.11.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: jsdom dependency-version: 30.1.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: marked dependency-version: 18.0.14 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vite dependency-version: 8.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vitest dependency-version: 5.0.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: vuetify dependency-version: 4.2.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com>
dependabot
Bot
force-pushed
the
dependabot/npm_and_yarn/npm-minor-patch-62d2cf8efc
branch
from
September 29, 2026 19:38
f7bd059 to
287e05d
Compare
mt3hr
deleted the
dependabot/npm_and_yarn/npm-minor-patch-62d2cf8efc
branch
September 30, 2026 19:35
Contributor
Author
|
This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests. To ignore these dependencies, configure ignore rules in dependabot.yml |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps the npm-minor-patch group with 10 updates in the / directory:
2.1.12.1.33.4.153.4.1618.0.1318.0.144.2.14.2.23.66.33.66.426.6.226.6.310.11.010.11.130.1.030.1.18.3.08.3.15.0.15.0.2Updates
@googlemaps/js-api-loaderfrom 2.1.1 to 2.1.3Release notes
Sourced from @googlemaps/js-api-loader's releases.
Changelog
Sourced from @googlemaps/js-api-loader's changelog.
Commits
a2ea171chore(main): release 2.1.3 (#1303)0c794c8fix: add allowScripts block to package.json (#1302)cf89cb7build(deps-dev): bump eslint from 10.9.1 to 10.10.0 (#1299)adb4400build(deps-dev): bump@babel/runtime-corejs3from 8.0.0 to 8.0.6 (#1300)3445060build(deps-dev): bump rollup-plugin-dts from 6.4.1 to 6.5.1 (#1301)27b4ecdchore(main): release 2.1.2 (#1268)ff440c2build(deps-dev): bump typescript-eslint from 8.69.0 to 8.70.0 (#1298)e46c00cbuild(deps-dev): bump@typescript-eslint/parserfrom 8.69.0 to 8.70.0 (#1297)6b2f534build(deps-dev): bump jest from 30.4.2 to 30.5.1 (#1295)939512ebuild(deps-dev): bump jest-environment-jsdom from 30.4.1 to 30.5.1 (#1294)Updates
dompurifyfrom 3.4.15 to 3.4.16Release notes
Sourced from dompurify's releases.
Commits
b9b9d80release: 3.4.16 (#1636)Updates
markedfrom 18.0.13 to 18.0.14Release notes
Sourced from marked's releases.
Commits
ef0704cchore(release): 18.0.14 [skip ci]23c82adchore: update deps (#4108)1b89557fix: keep text after empty nested blockquote (#4101)7f7a496fix: support GFM protocol autolinks (#4067)5196d98docs: add commonmark and gfm as versions in demo (#4094)de2320adocs: add marked-gitlab to known extensions (#4092)7d05530fix: allow indented lines in setext heading text (#4095)c7ee43afix: strip whitespace when normalizing link reference labels (#4091)cead8defix: decode numeric character references in text (#4076)e136da7fix: preserve internal tabs in list item content (#4086)Updates
vuetifyfrom 4.2.1 to 4.2.2Release notes
Sourced from vuetify's releases.
Commits
5b4625fchore(release): publish v4.2.2c8b9d6afix(VAutocomplete/VCombobox): prevent menu icon from toggling twice (#23200)b6c9f5cfix(VSelect): match autofill against item values (#23063)6d6513echore(VSelect/VAutocomplete/VCombobox): deprecatemenu-elevation8d1d985fix(VSelect/VAutocomplete/VCombobox): applymenu-elevationto the content d...bf5805cchore(v-touch): fix flaky test9453f06fix(VPullToRefresh): wrap styles in the components cascade layer (#23207)7cd8c57fix(VCommandPalette): render thelist.prependslot (#23204)3469724chore: use pnpm catalog to manage dependencies (#21259)3d3f418chore: bump vitest to 4.1.11 (#23188)Updates
@types/google.mapsfrom 3.66.3 to 3.66.4Commits
Updates
@types/nodefrom 26.6.2 to 26.6.3Commits
Updates
eslint-plugin-vuefrom 10.11.0 to 10.11.1Release notes
Sourced from eslint-plugin-vue's releases.
Changelog
Sourced from eslint-plugin-vue's changelog.
Commits
ec9c53aVersion Packages (#3139)50ffb7fdocs: explain how to apply the configs to a subset of files (#3122)ad239b4fix(no-unused-properties): ignore props typed asnever(#3113)24cb5bcfix(no-ref-object-reactivity-loss): improve IIFE handling (#3115)ef6f53efix(require-default-prop): don't report ondefineModel(#3138)121030cFormat changelogUpdates
jsdomfrom 30.1.0 to 30.1.1Release notes
Sourced from jsdom's releases.
Commits
0a117f430.1.1103f67dRemove unnecessary window cleanup from API testscdda00aTest HTTP/2 document and subresource loading7ab92ceUpdate@asamuzakjp/dom-selectorto v9.2.1d940c20Share jsdom settings across descendant windows6ba40cbFix and simplify option propagation3b3be70Preserve CSS priorities across declaration updates97b2758Align focusing and unfocusing with HTMLb7b460bUpdate w3c-xmlserializer to v671d562fUpdate html-encoding-sniffer to v7Updates
vitefrom 8.3.0 to 8.3.1Release notes
Sourced from vite's releases.
Changelog
Sourced from vite's changelog.
Commits
39ddf7crelease: v8.3.1 (#23573)f68c0d5fix: handleserver.ws: falsein mergeConfig (#23511)6f831f9fix(server): avoid reinitializing watcher when adding file after server close...04fc30afix(sourcemap): skip URL source roots when injecting sources content (#23519)5f89433fix(optimizer): resolve pending discovered dep processing on close before ini...63567c7chore(optimizer): add debug log when waiting for dep before init (#23566)e8990c4fix(deps): update all non-major dependencies (#23537)af7cdf6refactor: replacefindwithsome(#23554)39330f4fix(optimizer): don't skip imports whose binding starts with type (#23540)9abd99brefactor: remove duplicate configurations (#23532)Updates
vitestfrom 5.0.1 to 5.0.2Release notes
Sourced from vitest's releases.
Commits
428e2e5chore: release v5.0.2 (#11357)0b79231fix: bindprocessin case global is overwritten (#11343)597df56docs: correct stale config defaults (#11354)ea1c44fdocs:sequence.setupFilesdefault is'list'(#11351)0fd6b97fix(detect-async-leaks): ignoreprocess.stdiohandles (#11333)4e91e56fix(reporters):hanging-processto use ESM entrypoint (#11316)1a57929docs(browser): fix locators.exact default (#11338)5b95efbfix(reporter):agentto respect--silent(#11271)f58a209docs: correct benchmark.exclude and watch defaults (#11268)d1c3eccfix(jsdom): fixRequestwithBlobbody on jsdom 28+ (#11295)