これまで API と資料の突き合わせに寄っていたので、まだ 1 度も見ていなかった 9 領域に絞った。9 観点 × 反証役、46 エージェント・エラー 0。確定 40 件のうち、まず high と「運用が止まる」ものを出す。
指摘済みのもの(#16 の 3 件、#18 の 2 件、i260907-01 のやること、#10-1、#14-2)は再送しない。
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 で弾くので、書けるのに読めない行になる。
who と画面の参加者一覧に永久に出ない。join / leave のたびに知らせが積まれ続けるserver.mjs:317 の getCursor(...) ?? getMaxSeq(...) が毎回 null を受けるので、poll の起点が毎回「いまの最大値」になり、待受けを張っていない間の発言を黙って飛ばすp260829-01-設計.html:982「join し直しても記録があれば触らない(未読を飛ばさないため)」が、片付けの後だけ成り立たなくなるarchive room <room> は被害が広い。store.mjs:347 は WHERE archived_seq IS NULL AND room_id = ? で room だけを絞るため、そのルームを読んでいた全参加者の読んだ位置を壊すarchived_seq = NULL に戻すのは restore()(385 行)だけ。tests/archive.test.mjs:128-130 は片付け後に getCursor が null を返すことまで見て、そのあと書けるかを見ていない2 つの観点(DB・ハンドラ)が独立に同じ根に当たった。
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)、片付けとサーバー停止まで画面越しに届く。
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 行は「次にセッションを開くと、伏せた後のログがコピーされます。」と出す。次のセッションで本体からコピーし直されるので、伏せた分も戻る。
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-* に残ったまま、参加者には「取りこぼしなし」が流れる。
restore.ps1:111・144 が廃止済みの --connector-id を渡している — chat.mjs:60-67 が REMOVED に一致を見て exit 2 で止めるので、バックアップから戻す唯一の手順が最初の 1 行で止まる。111 行は本文の位置もずれている(say :<id>: "本文" の ID の位置に $notice が入っている)。設計 ch07 の停止手順 0 と 2 も同じ理由で実行されない。tests/ に restore.ps1 を通すものは無いbackup.ps1:72 が標準エラー 1 行で落ちる — 40 行の $ErrorActionPreference = 'Stop' のまま & node … 2>&1 で受けているため、backup.mjs が stderr に 1 行書いた時点で NativeCommandError が投げられて終わる。メンテナンスの印と重なって「待ってから取れた」ケースは、スナップショットまで作って zip を作らずに落ちる。控えは増えず、96-103 行のコメントが「ERROR で残す」と書いているその ERROR も書かれないbuild-aichat.cmd:4 が #Requires -Version 7 の ps1 を 5.1 で呼んでいる — cmd から起動できないUSAGE-FOR-PROJECTS.html:1062 と設計書 2741 行の受け入れ確認。server.mjs:330 の close は印だけで removeConnection は 359-364 の finally にあり、333 行の await が返るまで到達しない。そのルームに新着が無ければ最大 240 秒は ● 接続中のまま(合計 330 秒)。他プロジェクトが相手の生死を読み違えるserver.mjs:692-693 が limit を渡さず 500 で切り、chat.js:360-362 が開いた時点の cursor を URL に焼き付けるため、500 件を超えたあとに切断すると、切れている間の発言が永久に届かない。読み飛ばしと区別できず、見ている側は欠けに気づけない/api/version を見て帯を出す」と書き、課題は ☑ だが、src/web 配下に /api/version を叩く箇所が 1 つも無い。applyMaintenance(chat.js:313-325)に true が渡ることは無く、版が「—」・参加者 0 人・ログ空・入力欄は使えるままの画面が出るProgram.cs:155-172 の AnnounceEnv() が retryTimes=0 の probe で /api/version を叩き、閉じていると Client.cs:91-93 で Environment.Exit(3)。例外ではないので 169-171 の catch も動かず、119 行で作った「粘る Client」は一度も使われない。restart 直後に aichat wait を張ると即 exit 3(node 版は最大 10 分粘る)archived_seq IS NULL が 1 箇所も無い — p260829-01-設計.html 1479-1494・1502-1505・1569-1599。列と索引は反映済みなのに読み出し条件だけが archive 前の姿。p260830-02 388 行が「ここが最も危ない。足し忘れると、片付けたはずのものが出る」と書いている箇所で、1106 行がこの表を内部から参照している+(新しいルーム)の「やめる」が効かない — index.html:123 が formnovalidate を formnovalue と綴っており、無視される。同じ form に required な入力があるため、空のまま押すと検証で止まってダイアログが閉じない。chat.js:504 が開く直前に入力を空にするので必ず発現する。共有 PlayWright の chat-ui.spec.ts:229-239 は ok だけを押すため未検証purge-test-data.mjs(74-76・98-102)は --names の値が無いと接頭辞での全消しに落ちるUSAGE-FOR-PROJECTS.html:763-779 は「小さいサブエージェントに待たせる」、設計は「サブエージェントを使わない」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 件に絞った検証だったため)。この記録の時点で解消の報告は確認していない。