Skip to content

fix(db): CM_ROOT_DIR 由来の幽霊リポジトリ行を掃除する (#1339)#1374

Merged
Kewton merged 2 commits into
developfrom
fix/1339-ghost-env-repo-rows
Jul 17, 2026
Merged

fix(db): CM_ROOT_DIR 由来の幽霊リポジトリ行を掃除する (#1339)#1374
Kewton merged 2 commits into
developfrom
fix/1339-ghost-env-repo-rows

Conversation

@Kewton

@Kewton Kewton commented Jul 17, 2026

Copy link
Copy Markdown
Owner

概要

Closes #1339

#1328 以前の getRepositoryPaths()CM_ROOT_DIR を単一のリポジトリパスとして返し、ensureEnvRepositoriesRegistered() がそれを is_env_managed=1 の行として登録していた。CM_ROOT_DIR はリポジトリを格納するコンテナであってリポジトリではないため git worktree list は 0 件を返し、worktree を1つも持たない幽霊行だけが残る。#1328 は自動発見を削除したが既存行は残置していた(本 PR がその後始末)。

マイグレーション v43

スコープ: path が CM_ROOT_DIR と完全一致する is_env_managed=1 行のみ。

誤爆させないための3重ガード(すべて「残す側」に倒れる)

正当な env 管理行を消すのは無害ではない。ensureEnvRepositoriesRegistered() は行が無いと enabled: true で再作成するdb-repository.ts:469)ため、誤削除は利用者が無効化したリポジトリを黙って再有効化し、visible / display_name も失わせる。

# ガード 内容
1 CM_ROOT_DIR 未設定なら何もしない
2 CM_ROOT_DIR が WORKTREE_REPOS にも入っている場合は残す その行は正当(env がまだ要求している)
3 NOT EXISTS (worktrees WHERE repository_path = ?) worktree を持つ行は env が何と言おうと幽霊ではない。この行を誰も参照していないことが保証され、削除がロスレスであることの根拠になる

★実装時に発見した罠(Issue 未記載)

getEnv() を使ってはいけない。 src/lib/env.ts:218

const rootDir = getEnvByKey('CM_ROOT_DIR') || process.cwd();

CM_ROOT_DIR 未設定時に process.cwd() へフォールバックする。これを使うと DELETE がサーバーの起動ディレクトリ(dev 環境では実在のリポジトリ)を狙うことになる。process.env を直接読み、未設定は「スキップ」であって「cwd を対象」ではないことを保証している。あわせて MCBD_ROOT_DIR#76 以前の名称・現在も ENV_MAPPING でサポート)も見る。

後方互換

幽霊行が無い DB(#1328 以前を動かしたことがない利用者=通常ケース)は何にもマッチせず no-op。down は no-op(削除した行は利用者データを持たず、復元すると本 PR が直した欠陥そのものを戻すため。v35/v40 に倣う)。

★CURRENT_SCHEMA_VERSION の更新(必須)

runner.ts:2742 → 43 に更新した。これを忘れると #1353 で入れた将来版ガードが自分自身の DB を「将来版」と誤検知して起動不能になる。版数をハードコードしていた既存テスト(db-migrations.test.ts)も更新済み。なお future-schema-guard.test.ts#1353)は定数を import しており影響なし。

テスト

tests/unit/db/migration-v43-cm-root-dir-ghost-repository.test.ts を新規追加(幽霊行の削除 / 3ガードそれぞれの非削除 / no-op ケース / 冪等性)。

品質チェック(exit code 実測)

項目 EXIT 結果
npm run lint 0 Pass
npx tsc --noEmit 0 Pass
CI=true npm run test:unit 0 Pass(587 files / 9960 tests・Errors なし)
npm run build 0 Pass

関連

🤖 Generated with Claude Code

#1328 以前の getRepositoryPaths() は CM_ROOT_DIR を単一のリポジトリパスとして
返しており、ensureEnvRepositoriesRegistered() がそれを is_env_managed=1 の行と
して registered していた。CM_ROOT_DIR はリポジトリを格納するコンテナであって
リポジトリではないため git worktree list は 0 件を返し、worktree 行が作られない
まま リポジトリ行だけが残る。#1328 は自動発見自体は削除したが既存行は残す判断を
したため、既存利用者の DB に worktreeCount:0 の幽霊行が残置されている。
マイグレーション v43 で削除する。

削除条件は次のすべてを満たす行のみとし、判定はいずれも「残す」側へ倒す:
  1. CM_ROOT_DIR (legacy MCBD_ROOT_DIR) が明示的に設定されている
  2. 解決済みパスが WORKTREE_REPOS のエントリに含まれない
  3. その path を持つ worktrees 行が 1 件も無い
  4. is_env_managed = 1

実機同等の再現で検証済み: v42 DB に実際の ensureEnvRepositoriesRegistered() で
幽霊を作り、getAllRepositoriesWithWorktreeCount()(GET /api/repositories の実装)
が Issue 記載どおり name:"repos"/worktreeCount:0 を返すことを確認したうえで、
v43 適用後に幽霊のみが消え、実リポジトリと利用者が無効化した行が enabled=false の
まま残ることを確認した。各ガードは個別に破壊して対応テストが落ちることも確認済み。

--- Issue 本文の記載に対する補足(本文は orchestrator 管理のため未編集)---

Issue の案A(「is_env_managed=1 かつ worktree 行を持たない行を削除」)は採用して
いない。誤爆が無害ではないため:
ensureEnvRepositoriesRegistered() は行が無ければ enabled:true で再作成するので
(db-repository.ts:469)、利用者が意図的に無効化した WORKTREE_REPOS リポジトリを
消すと無効化が解除されて復活し、visible / display_name も失われる。案A は
「一時的に worktree が 0 件のリポジトリ」でこれを踏む。Issue 本文が併記していた
安全側の案(CM_ROOT_DIR 完全一致に限定)を採った。

環境変数を getEnv() 経由で読まないのも同じ理由による。getEnv() は CM_ROOT_DIR
未設定時に process.cwd() へフォールバックする (env.ts:218) ため、DELETE の狙いが
サーバーの起動ディレクトリ(実在のリポジトリでありうる)に向いてしまう。未設定は
「対象なし」として skip する。この退行はテストで固定した。

--- 委任時の事前調査に対する補足 ---

「マイグレーション追加時に更新が必要な 3 箇所」に加えて、4 箇所目があった:
tests/unit/lib/db-migrations.test.ts:37 が CURRENT_SCHEMA_VERSION を 42 と
ハードコードしており、43 へ上げると落ちる(実際に full suite で 1 件失敗を確認)。
併せて更新した。事前調査で安全と確認されていた tests/unit/db/future-schema-guard.test.ts
は import して使っているため指摘どおり無変更で通る。

また CHANGELOG の #1353 エントリ内 "CURRENT_SCHEMA_VERSION(現在 42)" が本変更で
不正確になるため 43 に更新した(同一 Unreleased 節のため未リリース)。

なお disableRepository() が作る is_env_managed=0 の幽霊行は別個体であり本修正の
対象外(#1346)。

品質ゲート(exit code で判定): lint=0 / tsc=0 / build=0 /
CI=true test:unit=0(587 files, 9960 tests passed, Errors 行なし)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Kewton Kewton added the bug Something isn't working label Jul 17, 2026
@Kewton
Kewton merged commit 32e7cb7 into develop Jul 17, 2026
9 checks passed
@Kewton
Kewton deleted the fix/1339-ghost-env-repo-rows branch July 17, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant