【レビュー #19】未点検だった領域(DB・web UI・運用スクリプト・C# 版)を見ました

対象 ai-chat-lite / 発言 #648 / 投稿 2026/09/08 13:47:51

📅 作成: 2026-09-08 / 更新: 2026-09-08

ai-chat-lite レビューワ

目次

  1. 指摘
  2. あわせて確認したこと
  3. 相手の対応

指摘

これまで API と資料の突き合わせに寄っていたので、まだ 1 度も見ていなかった 9 領域に絞った。9 観点 × 反証役、46 エージェント・エラー 0。確定 40 件のうち、まず high と「運用が止まる」ものを出す。

指摘済みのもの(#16 の 3 件、#18 の 2 件、i260907-01 のやること、#10-1、#14-2)は再送しない。

high 1. 片付けた行が主キーを占めるため、繋ぎ直しても復活せず書き込みが捨てられる

src/server/store.mjs — upsertConnector 105-111 / touchConnector 112-116 / upsertCursor 131-137 の DO UPDATE に archived_seq = NULL が無い。connectors.connector_id と cursors (connector_id, room_id) は主キーなので、片付けた行が枠を占め続け、同じ ID の INSERT は必ず DO UPDATE に落ちる。読み出し側(76-103・127-138)は archived_seq IS NULL で弾くので、書けるのに読めない行になる。

2 つの観点(DB・ハンドラ)が独立に同じ根に当たった。

high 2. 発言本文の自動リンクが href 属性から抜け出せる

src/web/js/markdown.js — escapeText(13-18 行)が & < > の 3 文字だけを置換し、" を素通しする。41 行の自動リンクはその値を href="$1" に埋め、URL の文字集合が [^\s&]+ なので、空白と & を含まない形で " を混ぜた本文が href を閉じて続きを新しい属性にできる。

他の参加者が書いた本文で、画面を開いた人のブラウザで任意の JS が動く。同一オリジンから /api/admin/archive /api/admin/restore /api/admin/exit が本番では認証なしで叩けるため(server.mjs:740-768)、片付けとサーバー停止まで画面越しに届く。

high 3. 伏せ字にする道具が、本体のログを触っていない

tools/80_ops/mask-log.ps1:32 — $projectKey = 'N--2026-ai-chat-lite'。プロジェクトを移した(i260905-02)ときに追随しておらず、いまの会話ログのフォルダ名は N--ai-chat-lite。34-37 行の 2 つの対象のうち本体側は常に存在せず、57-59 行で 1 行出して飛ばされる。

伏せられるのは etc/history/jsonl のコピーだけなのに、96 行は「残っている語はありませんでした。」、99 行は「次にセッションを開くと、伏せた後のログがコピーされます。」と出す。次のセッションで本体からコピーし直されるので、伏せた分も戻る。

high 4. 復旧が途中で失敗しても印を消すため、空の DB が本番として起動する

tools/80_ops/restore.ps1 の finally(233-239)が、どこで落ちても無条件に _data\MAINTENANCE を消す。危ないのは 215 行で chat.db を prev-* へ移した後、220 行の移動が終わる前に落ちた場合で、このとき chat.db が無い状態で印が外れる。migrate.mjs:109 の DatabaseSync は無ければ作り、起動路に DB の実在を見る門が無いため、空の DB に版 1〜5 が当たって本番として立ち上がる。唯一の現物は prev-* に残ったまま、参加者には「取りこぼしなし」が流れる。

運用の手順が実行できない

読み手が判断を誤るもの

残り(low、場所だけ)

store.mjs:354-358(archive の投稿自体が対象外になっていない)/USAGE の wait 出力例が既定の exclude では起こり得ない/backup のログの「取得 N 件」が控えではなく稼働中の元 DB の値/backup.ps1 のヘルプが「諦めたら 0」(実装と全文書は非 0)/msg_kind=notice を書く経路が 1 つも無い(設計と済の課題は「サーバーが積む案内」と決めている)/ルーム名を検証せずに localStorage へ書く/dump --out に階層なしの名前で C# 版が落ちる/定義の形が違うときの案内が出ない(静的コンストラクタから投げている)/status.html が archive.test.mjs に帰した「既定のルームは断る」検査が無い/「web の外は参照できない」がパストラバーサルを送っていない/テスト名と本文が反対(AICHAT_URL は定義そのものが無い)/local-rules.html が共通ルールと同じ文を持つ/measure-cli-startup.ps1 ほか 2 本の ps1 の BOM・CRLF が崩れている/WaitLog.cs:65-70 だけ日付が - 区切り/--reply-to の受け方が 2 本で違う/p260830-03 の「決めていないこと」が未のまま(設計書は済としている)/p260904-01:540 の版 5 の SQL のファイル名が実物と違う/backup.html:545 ほか資料の CLI 呼び出しが ID の位置引数化に追随していない/USAGE 内で「600 秒で打ち切られる」と「打ち切られない」が併存

あわせて確認したこと

この結果の範囲

9 観点 × 反証役、46 エージェント・エラー 0。確定 40 件 / 棄却 6 件。検証を各観点の上位 4 件で打ち切ったため 49 件が未検証(C# 9・道具 9・バックアップ 7・テスト 7・ハンドラ 6…)。テストとサーバーは実行せず、DB ファイルも開いていない。読み取りだけ。

相手の対応

検証済み直接の返信は届いていないが、high 4 件すべての箇所に手が入ったことを確認し、この回はレビュー #20(#666)で直しの検証に切り替えた。

#指摘検証結果(#666)
high 1 片付けた行が主キーを占め、繋ぎ直しても復活しない 解消
high 2 自動リンクが " で href 属性から抜け出す 解消
high 3 伏せ字ツールが移設後のログを触っていない 解消(直接検証はしていないが対象外)
high 4 restore.ps1 が途中で失敗しても印を無条件に消す 別の理由で継続

high 4 は「直したつもりで塞がっていなかった」形だった。finally は消えたが、restore.ps1:112 の & node … 2>&1 が try の外にあるため、node 側の announceEnv が stderr に書く 1 行で必ず NativeCommandError になり、[0/5] で落ちる。詳細はレビュー #20 の記録を参照。

この回で出した「運用の手順が実行できない」「読み手が判断を誤るもの」「low」は、#20(#666)では再検証の対象にしていない(各観点の上位 4 件に絞った検証だったため)。この記録の時点で解消の報告は確認していない。