目的(なぜ)
Li+ の language-definition.md は、変更を「要求仕様 / ターゲットプログラム / CI テスト」の 3点1単位 と定義する。CI テストは「変更が要求どおりか継続観測する」脚。本リポジトリはこの脚を実質的に欠いている:
要求仕様 ✅ — docs/0-requirements.md(約 23KB、Architecture / Retrieval Model / MCP Tools を定義)
プログラム ✅ — src/ + mcp-server/(約 9,700 行)
CI テスト ❌ — 挙動テストはゼロ。CI は tsc --noEmit(型)/ wrangler deploy --dry-run(ビルド)/ check-schema-drift.mjs(search パラメータ名の集合一致 1 個)/ proxy の node --check(構文)のみ
→ 仕様書が「何が正しいか」を定義しているのに、それを照合する観測が無い。型・ビルドは形式の層 しか保証せず、論理の正しさ は死角。実例: #135 (diff 行の FTS5 upsert 失敗)、v0.9.0 の graph_expand 取りこぼし——どちらも静的チェックが緑のまま、論理がソースで壊れていた。
方針
ゼロから網羅を作らない。既存の scripts/check-schema-drift.mjs(Li+ 的に唯一機能している CI テスト脚)を種 として伸ばす。カバレッジ率は追わず、高精度・低 recall——「壊れたら静かに効く」surface から最小の脚を生やす。
優先順位(最初の一枚)
subtraction-safeguard 域(セキュリティ / データ整合性 = 明示性が load-bearing な領域)を先に:
データ整合性 — src/store.ts の D1/FTS5 upsert、src/pipeline/vector-id.ts のハッシュ導出(ID の決定性・衝突回避)。bug(fts): D1 FTS5 upsert failures observed for diff rows across all repos #135 が実際に噛んだ場所。
セキュリティ境界 — src/oauth.ts / proxy の OAuth フロー(PKCE code_challenge、動的クライアント登録、トークン更新、401 再認証)、src/webhook.ts の署名検証。as unknown as が 7 箇所(うち oauth.ts に 5 箇所)= 型保証すら局所的に切れている領域。
後回し(later): RRF fusion / rerank scoring / embed チャンク分割、poller.ts のオーケストレーション。
前提・制約
Cloudflare Workers + D1 / Vectorize / Workers AI バインディングはテストが高摩擦。harness は @cloudflare/vitest-pool-workers(実機寄り)か miniflare + バインディングのモックを比較検討。外部 AI(BGE-M3 / reranker)はモック化前提。この harness 選定が着手時の最初の判断点。
純ロジック(vector-id ハッシュ、ingest-filter、fusion 計算)はバインディング非依存。harness 決定を待たず先行して unit 化できる → 最初のサブ issue 候補。
複数 surface にまたがるため、本 issue は親 として最終的にサブ issue へ分割する見込み。
対象ファイル(テスト対象。実装ファイルは着手時に確定)
src/store.ts / src/pipeline/vector-id.ts / src/pipeline/ingest-filter.ts
src/oauth.ts / src/webhook.ts / mcp-server/server/index.js
scripts/check-schema-drift.mjs(型・enum まで広げる余地)
リリース観点
挙動変更なし=テスト追加自体は patch 相当。ただし harness 導入で CI 構成が変わる場合は別途 minor 判断。
目的(なぜ)
Li+ の language-definition.md は、変更を「要求仕様 / ターゲットプログラム / CI テスト」の 3点1単位 と定義する。CI テストは「変更が要求どおりか継続観測する」脚。本リポジトリはこの脚を実質的に欠いている:
docs/0-requirements.md(約 23KB、Architecture / Retrieval Model / MCP Tools を定義)src/+mcp-server/(約 9,700 行)tsc --noEmit(型)/wrangler deploy --dry-run(ビルド)/check-schema-drift.mjs(search パラメータ名の集合一致 1 個)/ proxy のnode --check(構文)のみ→ 仕様書が「何が正しいか」を定義しているのに、それを照合する観測が無い。型・ビルドは形式の層しか保証せず、論理の正しさは死角。実例: #135(diff 行の FTS5 upsert 失敗)、v0.9.0 の
graph_expand取りこぼし——どちらも静的チェックが緑のまま、論理がソースで壊れていた。方針
ゼロから網羅を作らない。既存の
scripts/check-schema-drift.mjs(Li+ 的に唯一機能している CI テスト脚)を種として伸ばす。カバレッジ率は追わず、高精度・低 recall——「壊れたら静かに効く」surface から最小の脚を生やす。優先順位(最初の一枚)
subtraction-safeguard 域(セキュリティ / データ整合性 = 明示性が load-bearing な領域)を先に:
src/store.tsの D1/FTS5 upsert、src/pipeline/vector-id.tsのハッシュ導出(ID の決定性・衝突回避)。bug(fts): D1 FTS5 upsert failures observed for diff rows across all repos #135 が実際に噛んだ場所。src/oauth.ts/ proxy の OAuth フロー(PKCE code_challenge、動的クライアント登録、トークン更新、401 再認証)、src/webhook.tsの署名検証。as unknown asが 7 箇所(うちoauth.tsに 5 箇所)= 型保証すら局所的に切れている領域。後回し(later): RRF fusion / rerank scoring / embed チャンク分割、
poller.tsのオーケストレーション。前提・制約
@cloudflare/vitest-pool-workers(実機寄り)か miniflare + バインディングのモックを比較検討。外部 AI(BGE-M3 / reranker)はモック化前提。この harness 選定が着手時の最初の判断点。ingest-filter、fusion 計算)はバインディング非依存。harness 決定を待たず先行して unit 化できる → 最初のサブ issue 候補。対象ファイル(テスト対象。実装ファイルは着手時に確定)
src/store.ts/src/pipeline/vector-id.ts/src/pipeline/ingest-filter.tssrc/oauth.ts/src/webhook.ts/mcp-server/server/index.jsscripts/check-schema-drift.mjs(型・enum まで広げる余地)リリース観点
挙動変更なし=テスト追加自体は patch 相当。ただし harness 導入で CI 構成が変わる場合は別途 minor 判断。