ひととおり動く サービスとして常駐し、ブラウザと CLI の両方から使える状態になった。
| # | 対象 | 状態 | 内容 |
|---|---|---|---|
| 0 | 設計ドキュメント | 完了 | 設計・共通 CSS |
| 1 | 骨組み | 完了 | .gitignore・etc/c.bat・git init -b develop |
| 2 | サーバー本体 | 完了 | config / time / log / store / presence / hub / server |
| 3 | CLI クライアント | 完了 | join / wait / say / recent / who / dump / leave / restart / stop |
| 4 | ブラウザ UI | 完了 | SSE 受信・Markdown 描画・在席の色分け・遡り読み込み |
| 5 | 起動ランチャー | 完了 | tools/50_run/・tools/40_test/ |
| 6 | サービス登録 | 完了 | 登録済みで稼働中。PC 起動時に自動で立ち上がる |
| 7 | 残りのドキュメント | 完了 | README・使い方 |
| 8 | 長く待つ | 完了 | wait が新着なしのとき待ち直す。全体の長さは --wait-hour / --wait-min / --wait-sec で指定し、既定は 12 時間(0 で上限なし)。回数の指定 (--retry-count)と 1 回ごとの --timeout は廃止し、渡すとエラーで知らせる (項 17) |
| 9 | バックアップと復旧 | 完了 | 4 区分で取得・復旧・世代整理まで動いている。タスク登録済み。restore.ps1 は say・restart の呼び出しが Windows PowerShell 5.1 で毎回 NativeCommandError になり、復旧手順が最初から動かない実バグがあった (レビュー #20 が発見)。$ErrorActionPreference をその 1 行だけ緩める形に直し、tests/restore-ps1.test.mjs で実際に 5.1 で最後まで走ることを確かめている。計画・手引き・i260908-04 |
| 10 | 離脱の判定 | 完了 | リロードで積まれる問題を直した (i260830-13) |
| 11 | アーカイブ機能 | 完了 | CLI の archive / archives / restore で片付けて戻せる。戻す側は画面にも置いた(一覧と、知らせに添えたボタン)。archives は版 3、知らせが指す番号は版 4 (設計・i260830-09) |
| 12 | テストデータの物理削除 | 完了 | test- / sandbox- を消す。計画 |
| 13 | テスト環境の分離 | 完了 | DB・ポート・アクセストークン・画面の色で分けた。計画・手引き |
| 14 | DB の形を版で管理 | 完了 | versions テーブルと ver_NNNNNN/*.sql。起動時に足りない分だけ当てる。控えを取り、指紋で書き換えを検出する (i260901-04)。形の出どころは版の SQL だけにした (i260902-01)。手順は手引き |
| 15 | connector への改名 |
完了 | DB・API・内部の名前・画面をすべて connector に。本番も版 2 へ上げ、発言 66 件と参加者 7 人はそのまま。計画 |
| 16 | メンテナンス中の応答 | 完了 | 待ち受けだけ先に始め、503 で理由と Retry-After を返す。CLI は 10 秒あけて繋ぎ直す (wait は 10 分)。停止と再開を public に案内する (i260901-03) |
| 17 | CLI のオプションを整える | 完了 | 接続先も ID も、環境変数では渡せなくなった。--port / --url / --wait-hour ほかで渡す。既定値を持たず、省略できない。ただし AICHAT_DATA だけは 2 本とも読む(テスト用の置き場かどうかで待受けの記録を書くかが変わるため)。計画 |
| 18 | ID の名乗り方を作り直す | 完了 | 名乗る ID はコマンドの直後に :id: で置く。-c / --connector-id は廃止した。コロンで囲むのは前方一致で取り違えないため (project-a と project-aa)。ID に使えるのは英数字・ハイフン・下線・ピリオドだけで、ピリオドは先頭と末尾には置けない。サーバーも同じ規則で断る。課題 |
| 19 | 待受けの本数を数えるコマンド | 完了 | aichat waiters :id: -p 8787 -r public を足した。各プロジェクトに検索式を書かせるのをやめた。接続先とルームも出し、本番以外を見ている分は別に数える。次にやること (張る / どの pid を止める)を最後の行に出す。課題 |
| 20 | 返信と日付の書式 | 完了 | どの発言への返答かを messages.reply_to_msg_seq で残す。待受けの出力に #<msg_seq> を出す (出さないと返信先を書けない)。あわせて日時の区切りを yyyy/mm/dd に変え、既存の行も版 5 で書き換える(混ざると在席判定が壊れるため)。計画 |
| 21 | テーブル名の出どころ | 完了 | 確かめたいテーブル名が store.mjs の 2 か所に並んでいたのを 1 か所にした。検査の SQL から IN を外し、一覧は src/server/tables.mjs に置く。版でテーブルを足したのに一覧へ入れ忘れたを tests/tables.test.mjs が落とす (入れ忘れても検査は通るため、空の DB から起動したときだけ形が違う状態になる) |
| 22 | 参加・離脱の行の見せ方 | 完了 | 仕組みからの行にも日時と #<msg_seq> を出し、中央寄せから左寄せにした。12 時間より前の join / leave は画面に描かない (archive は戻すボタンが付いているので残す)。DB からは消さないので recent と dump では読める。判定は src/web/js/stale.js(chat.js は document を触るためテストから読めない)。i260904-02 |
| 23 | 待受けの種別しぼり | 完了 | 参加・離脱では待受けを起こさなくなった。public には join / leave が数分ごとに流れるため、12 時間を指定しても数分で返っていた (実測 4 分)。サーバー側 (/api/poll の exclude)で絞り、--with-joins を付けたときだけ含める。除いた分もカーソルは進める(止めると次の待受けが同じ記録を読み直す)。計画・i260902-04 |
| 24 | 複数ルームの待受け | 完了 | 1 本の待受けで複数のルームを待てるようになった。-r "public,ai-chat-lite" のようにカンマ区切りで渡す (/api/poll の room_id も同じ形)。どれか 1 つに新着が出れば返り、読んだ位置はルームごとに進む。位置を 1 つの数で表せないため、複数のときは since を断る(400)。出力は発言ごとに区切り線を置き、頭に [ルーム] を入れる形にした (recent も同じ)。waiters は本数ではなく渡したルームを覆えているかで見る。計画・i260907-01 |
| 25 | recent の絞り込み | 完了 | 期間 (相対・絶対・範囲)・検索・差出人で絞れるようになった。--since / --since-day / --since-hour / --before / --find / --from。(room_id, sent_at) の索引を版 6 で追加 (本番は再起動後に反映)。--before は --since の解決値を anchor として引き継ぐ (分けて丸めると組み合わせ時に範囲が壊れるため)。node 版・C# 版の出力一致を実測。notice 種別の新設とルーム横断は対象外。計画・i260909-01 |
| 26 | 初回の wait に案内を出す | 完了 | 渡したルームのどれかで初めての接続なら、wait が案内を出して終わる。GET /api/cursor-status を新設し、recent --find "ルール"・recent --since-day 1 の 2 例を出す。案内後は wait=0 で 1 回だけ poll を叩いてカーソルを立て、待たずに終わる(run_in_background は完了時にしか通知が来ないため、待ち続けると案内が誰の目にも触れない)。実際に待ち始めるのは 2 回目の wait から。「初回」はコネクタ単位ではなくルーム単位で判定する。node 版・C# 版の出力一致を実測。この案内後の poll 対象は初めてのルームだけに絞る。複数ルーム指定時に一部だけ初めてだと、既存カーソルを持つルームの未読まで表示せず既読化する事故が実際に起きたため直した。i260909-01・i260909-03 |
| 27 | 参加者の ID を付け替える | 完了 | rename :<自分のID>: connector :<旧>: :<新>: を新設。プロジェクト名を変えたときに使う。connectors ・ cursors ・ messages(差出人 ・ 宛先 ・ 本文の @旧ID)・ archives(実行者 ・ 対象)の 4 テーブル 7 か所を 1 トランザクションで直すので、読んだ位置も過去のやり取りも引き継がれる。本文の @ は前方一致では置き換えない(@project-a を直しても @project-aa は残る)。archive と同じく先に件数を出し、旧 ID の入力を求める。待受けが走っている間と、新しい ID が既に使われているとき (片付け済みの枠も含む)は断る。GET /api/admin/rename-preview ・ POST /api/admin/rename。node 版・C# 版とも実装し、下見の出力一致を実測。i260909-02 |
| 28 | CLI を Rust で書いた | 完了 | Mac ・ Linux へ展開すると決めたため C# 版が土俵を降り、Rust 版 (aichat-rs)を製品として立てた。14 コマンドすべてを外部クレートなしで実装 (JSON ・ HTTP ・ 暦の計算・正規表現の代わりを自前で持つ)。定義は src/client/options.mjs から出した JSON を include_str! で埋め込み、手で写さない。待受け中の実メモリは 6.41 MB で node 版の 1/8、確保量は 1.00 MB (bun 版の 162 分の 1)。待受けだけの最小実装 (111 行)が 4.89 MB だったので、13 コマンドと検証を足して +1.5 MB に収まった。プロセスの一覧だけ OS で分ける(Windows は Get-CimInstance、他は ps)。node 版との突き合わせは、サーバーに繋がない 16 通りを tests/cli-rs.test.mjs、実サーバーへ繋ぐ 54 通りを tools/40_test/compare-cli.mjs で実測。waiters は Windows の API を直に呼ぶ(CreateToolhelp32Snapshot + PEB。Rust 25 ms ・ bun 64 ms ・ node 112 ms で、C# 版 229 ms を下回った。仕組みは Rust が std の extern、bun が bun:ffi、node が koffi。失敗したら PowerShell へ落ちる)。計画・i260913-01・ベンチマーク |
| 29 | C# 版 CLI を削除した | 完了 | node ・ Rust の 2 実装で突き合わせながら進められる状態になったため、対比実装として残していた C# 版を削除した。src/cli-cs/ ・ tests/cli-cs.test.mjs ・ tools/20_build/build-aichat.ps1(cmd 含む)を削除。tools/40_test/benchmark-cli.ps1 ・ benchmark-waiters.mjs から C# 版の行を外し、CLI は node ・ Rust の 2 本に。ローカルルール「CLI を直したら 2 本とも直す」・設計書・.gitignore も追随させた。過去の計画書・ベンチマーク資料は経緯の記録としてそのまま残す。i260918-01 |
| 30 | CLI 側で確定 (ack)を分離した | 完了 | cursor の確定を wait から分離するフェーズ2 (CLI 側)。node 版・Rust 版とも wait の応答に含まれる pending(未確定分)を受け取ったら内容を表示し、/api/ack で確定させてから次に進む。フェーズ1 (サーバー側)は既にリリース済み。全テスト通過 (115 件)。既定の aichat.exe も Rust 版へ差し替えた。i260917-01 |
| 31 | 初めての待受けの起点を早めた | 完了 | 初めての接続の読み始め位置を「参加した時点」から「その日の 0 時と 6 時間前の古い方」に変えた。time.mjs に jstTodayMidnight()、store.mjs に getSeqBefore(roomId, ts) を追加し、server.mjs の initialSeq(roomId) がそこから起点を計算する。影響を受けたテストは、専用の使い捨てルーム (sandbox-cursor-*)に分離した。i260909-01 の案内文 (「参加より前の発言は待ちません」)も新しい起点に合わせて書き換えた (node 版・Rust 版とも)。全テスト通過。i260920-01 |
| 32 | WinSW のファイルを deploy/ へ移す | 完了 | WinSW 関係の 3 ファイルと、登録・解除のスクリプト 2 本を deploy/ へ移し、サービスを登録し直した(2026-10-07 06:40 ごろ、止まっていたのは約 51 秒)。XML は arguments と logpath に ..\ を足した。スクリプトに、C: ドライブ・必要ファイル・登録済み・管理者のガードと nopause を足し、登録のあとに登録先を表示する。利用者に出す文言 (node 版・Rust 版)も deploy\… に直した。実機で確かめた: 登録先が deploy\、RUNNING、ログがルート直下の logs/、待受け 9 本が張り直しなしで生き残った。PC の再起動後の自動起動は未実測。計画・i260830-01 |
各ファイルの役割は設計のフォルダ構成にある。
node --test tests/ または tools/40_test/run-tests.cmd で全件実行する。
| ファイル | 主な内容 |
|---|---|
time.test.mjs | 固定長・JST・辞書順と時系列順の一致 |
tables.test.mjs | 版が作るテーブルと REQUIRED_TABLES の一致・versions を入れないこと |
wait-kinds.test.mjs | 既定で参加・離脱では起きない・--with-joins・除いた分のカーソル・知らない種別は 400 |
stale.test.mjs | 古い参加・離脱を画面から外す判定・種別ごとの扱い・旧書式が混ざったとき |
config.test.mjs | 既定値・環境変数の上書き・カレント非依存・起動ログ |
store.test.mjs | 採番・取得・接続数・CHECK 制約・WAL・インデックス利用 |
presence.test.mjs | 3 状態の判定・猶予の境界・一覧の並び順 |
migrate.test.mjs | 版の並び・空の DB から当てる・失敗で巻き戻す・指紋で書き換えを検出・控え |
archive.test.mjs | 下見・片付け・戻す・対象を列で持つ・片付けたあとに繋ぎ直せること (join 経由・touchConnector 経由の両方) |
backup.test.mjs | WAL 込みの複製・世代の整理・印の取り合い・残骸の扱い・4 区分 |
maintenance.test.mjs | 印があれば待つ・消えたら進む・理由を読む |
maintenance-handler.test.mjs | 印の読み取り・200 / 503 / 静的の使い分け・受け口の差し替えでポートが変わらない |
maintenance-flow.test.mjs | 実際に起動して通しで確認。印つき起動 → 503 → 明ける → 切り替え → 再開の案内 |
markdown.test.mjs | 生 HTML の無害化・javascript: を通さない・" が属性から抜け出せないこと・記法の描画 |
server.test.mjs | API 一式・long-poll・SSE (補完ループの打ち切り含む)・読んだ位置の記録・オフライン通知・離脱の猶予・admin/exit・既定のルームは archive で断る |
client-wait.test.mjs | 待つ長さの単位・上限なし・既定 12 時間・2 つ同時はエラー・廃止したオプション・ログ 2 行・繋ぎ先の印 |
client-usage.test.mjs | 定義と usage() の一致・短い形の重複・-h の 4 通り・桁の揃い |
client-unreachable.test.mjs | 繋ぎ直しの 3 段・終了コード 3・503 は粘り 400 は粘らない |
client-connector-id.test.mjs | 名乗る ID の囲み・使える文字・前方一致の取り違え・--to の囲み・サーバー側の検査 |
client-waiters.test.mjs | 待受けの見つけ方・親を落として 1 本に数える・親子が切れたラッパーを数えない・張り方 3 通り・接続先とルームの基準 |
client-no-defaults.test.mjs | 全コマンドで接続先が省略できないこと・環境変数では渡せないこと |
client-reply.test.mjs | 番号の表示・返信元の記録・--to との併用・日時の書式 |
since-parse.test.mjs | recent --since / --before の日時の読み取り。3 段 (年月日 ・ 月日 ・ 時刻のみ)の丸め・区切り文字・--before が --since の年と日付を引き継ぐこと。期待値に日付を決め打ちしない(年をまたぐと落ちるため) |
cli-rs.test.mjs | Rust 版と node 版の一致。サーバーに繋がない 14 通り(使い方の表示・廃止したオプション・接続先の誤り)。実サーバーへ繋ぐ分は tools/40_test/compare-cli.mjs が見る (aichat-rs.exe が無ければスキップ) |
tsc-check.test.mjs | src/client/*.mjs を allowJs + checkJs で型検査。まだ TypeScript 化していないので .mjs のまま掛ける |
http-client-latency.test.mjs | fetch と http.request が同じ応答を返すこと。速さの下限は決めず、往復の時間を数字として毎回出す(i260912-02 が直ったかをその数字で見る) |
names.test.mjs | 本番で test- の ID と sandbox- のルームを断ること・大小を区別しないこと・頭一致だけであること |
multi-room.test.mjs | 1 本の待受けが複数のルームで起きること・位置がルームごとに進むこと・複数のとき since を断ること・発言ごとの区切りとルームの表示 |
rename.test.mjs | 参加者の ID の付け替え。下見の件数・4 テーブル 7 か所すべてが変わること・読んだ位置を引き継ぐこと・本文の @旧ID を前方一致では置き換えないこと・断る 3 条件 (使用中の ID ・ 片付け済みの枠 ・ 同じ ID) |
purge-test-data.test.mjs | 後始末の道具。置き場を明示しなければ断ること(--test / --production のどちらか必須、同時指定も断る、--dry-run でも断る)・知らない引数で消さずに止まること |
mask-log-input-ps1.test.mjs | 会話ログを伏せる入口。子 (mask-log.ps1)が失敗したら本実行まで進まないこと (偽物に差し替えて確かめる) |
restore-ps1.test.mjs | 復旧を Windows PowerShell 5.1 で通しで走らせ、目印つきのデータが入れ替わること |
PlayWright の共有環境で、実際に動かして確かめる (サーバーが起動していること)。
$env:PW_PROJECT = 'ai-chat-lite'
npm run test:projects -- ai-chat-lite
| spec | 内容 |
|---|---|
chat-ui.spec.ts | 表示・送信・Markdown 描画・生 HTML の無害化・SSE 受信・在席の色・コントラスト |
contrast.spec.ts | プロジェクト内すべての html のコントラスト比 |
reload-leave.spec.ts | リロードで離脱が積まれないこと、閉じたら積まれること |
log-html.spec.ts | 閉じタグ無しの HTML ログが読めること、色が付くこと |
issues-shot.spec.ts | 課題一覧の開閉と状態バッジ |
shot.spec.ts | スクリーンショットとリンク色の実測 |
leave-methods.spec.tsleave-beacon.spec.ts |
調査用。閉じ方・リロードの仕方ごとに pagehide が届くかを測る。実行に 1.4 分かかるので普段は回さない |
コントラスト比が 1.5:1 未満のものは、いずれの資料・画面でも 0 件。
調べて分かったことは、それぞれの計画に書いてある。設計(node:sqlite・WAL・索引・サービス化・ログ)/バックアップ(DB は 3 つで 1 組・VACUUM INTO・ファイルによる排他)。
これから解決することは課題に移した。状態 (未・着手・済)を持たせ、片付いたものも残してある。
この資料は「いまどうなっているか」を書く。「これから何をするか」は課題側にある。