Skip to content

feat(PLAN66): 名前の形に合わないプロジェクトを、作られた時点で知らせる (#203) - #233

Merged
takemi-ohama merged 7 commits into
release/v3.7.0from
feature/v3.7.0-project-name-warn
Sep 22, 2026
Merged

takemi-ohama merged 7 commits into
release/v3.7.0from
feature/v3.7.0-project-name-warn

Conversation

@takemi-ohama

@takemi-ohama takemi-ohama commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Pull Request

概要

名前の形(bin/devbase が受け付ける形)に合わない名前が projects/ に載る時点で、警告を 1 行出して知らせる。
弾かずに警告に留める(設計の決定 1)。plugin install / update / sync と env import の終了コードと、作られる symlink・ディレクトリは変えない。

設計文書 issues/PLAN66_project-name-validation-design.md の「実装の分け方」の 1 本目(知らせ。F1・F2)である。
2 本目(スナップショットの名前の検証を utils/names の述語へ寄せる。F3・決定 5・6)はこの Pull Request のマージ後に別に出す。
計画は issues/PLAN66_project-name-validation-impl1.md。

関連 Issue

変更点

  1. docs(PLAN66): 実装 1 本目の計画を置いた

  2. feat(PLAN66)(同期・F1): utils/names.NAME_FORM_HINT(名前の形の説明文。ログは出さない。決定 7)と
    syncer._warn_unusable_name(name, source, base=None) を足した。呼ぶのは 3 か所だけ(決定 2)

    • sync_projects: real_projects を採取した直後に sorted(real_projects) の名前ごと / winner の symlink を張る直前(実ディレクトリのスキップより後)
    • _link_loser_projects: 別名の symlink を張る直前(元のプロジェクト名を base に渡す)
    • 案内は出所で 4 つに分かれる(プラグイン / 別名で元の名前の側が原因 / 別名で <owner> の側が原因 / 実ディレクトリ)。verbose に依存させない
    • discover_projects(. 始まりの除外を含む。決定 8)・_collect_project_candidates・戻り値は変えていない
  3. feat(PLAN66)(import・F2): _import_merge.project_name_of(arcname) を足し、import_bundle が _build_plans の直後・--dry-run の判定より前に
    plans を回して知らせる。平文の projects/<name>/.env(plan.ref is None かつ plan.target がそのパス)なら「この import が projects/<name>/ を作る」と改名の案内、
    それ以外(age・サーバ backend)は保存先を名指しして projects/ には何も作られないことを書き、改名の案内は出さない(決定 4)。
    _PROJECT_ENV_RE・env/bundle.py・env/secret_store.py は触っていない

  4. docs(PLAN66): 確定仕様 docs/specifications/cli-argument-resolution.md の「運用」の 1 つ目の箇条書きだけを書き換え(2 つ目は 2 本目)、CHANGELOG.md の [Unreleased] に Added を足した(Changed は 2 本目)

  5. Test(構造改善のテスト追加ラウンド): cross-refactoring が現状固定のテストを 3 ファイルへ足した(570a2fe。プロジェクト名の取り出し・サーバ backend の import・同期の別名。追加のみ)。コミットメッセージが英語なのはボットの既定のためで、履歴は書き換えていない

  6. fix(PLAN66)(実装レビュー round 1 の指摘): sync_projects の実ディレクトリの知らせが projects/.vscode など . 始まりのディレクトリにも出ていた。決定 8 のとおり . 始まりは知らせの対象から外した(real_projects の集合と「実ディレクトリならスキップ」の判定は変えていない)。回帰テスト test_dot_real_directories_are_not_warned を追加(7687bfb)

下流の検証(bin/devbase・cli.py・commands/container.py)は変えていない(決定 3)。受け付ける名前を狭める変更は含まない。

補足: 設計の「実装の分け方」はテストのファイルを 3 つ(tests/plugin/test_repos_core.py・tests/env/test_io_import.py・tests/cli/test_env_bundle_backend.py)挙げており、そのとおりに 3 つへ足した。既存のテストは 1 行も変えていない(差分は 3 ファイルとも追加のみ。構造改善と実装レビューで足した分も追加のみ)。

テスト駆動の証跡: 新しいテストを先に書き、変更前の実装で期待どおりの理由で落ちることを確かめてから実装した
(同期: TestSyncProjectsNameForm 6 件のうち警告を期待する 4 件が assert 0 == 1 / assert 0 == 2(警告が 0 件)。条件 2・5 の 2 件は「警告が出ない」ことの固定のため変更前から緑。
import: 条件 6・7・9 の 3 件が assert 0 == 1、条件 8 は変更前から緑)。

構造改善(打ち切り)

構造改善(/ndf:cross-refactoring)は 利用者の判断で途中で打ち切った(2026-09-23)。テスト追加のラウンド(570a2fe)までで終え、提案ラウンド 2 の途中で止めた。構造の変更は入れていない。 570a2fe の時点の全体テストは 2921 passed、exit=0 で確かめた。

実装レビュー

/ndf:cross-review 233 で 2 ラウンド、approved で収束した。

round レビュー 修正
1 agy=APPROVE (0) / kiro=REQUEST_CHANGES (1: . 始まりの実ディレクトリにも知らせが出る) 7687bfb(1 件修正)
2 codex=APPROVE (0) / kiro=APPROVE (0) —

最終スイープ: 未解決の指摘 0 件(GitHub 側で確認)。deferred / rejected 0 件。

Test plan

release/v3.7.0 を base にした Pull Request では CI が動かない(#216)。以下はすべて手元(作業ツリー、macOS)で実行した。
実環境のプラグイン・projects/ に対して plugin install / update / sync と env import は実行していない。

  • 変更前の全件: uv run --locked pytest tests/ -q(ff48e8e + 空コミット)→ 2900 passed、exit=0
  • 受け入れ条件 1・2・3・3-2・4・5: uv run --locked pytest tests/plugin/test_repos_core.py -q → 60 passed(新設 TestSyncProjectsNameForm 6 件。既存の TestSyncProjects 7 件は無変更で通過=条件 15)
  • 受け入れ条件 6・7・8・9: uv run --locked pytest tests/env/ tests/cli/test_env_bundle_backend.py -q → 661 passed(新設 4 件。既存の test_io_import.py・test_import_merge.py・test_store_roundtrip.py・test_env_bundle_backend.py は無変更で通過=条件 16)
  • 実装の後の全件: uv run --locked pytest tests/ -q(788d727)→ 2910 passed、exit=0(新設 10 件。失敗 0)— 条件 17
  • 隔離した root(scratchpad の DEVBASE_ROOT と HOME)で python -m devbase.cli env import <_foo を含む書庫> --no-global → 標準エラーに Warning: プロジェクト名として使えない形の名前を取り込みます: '_foo'(出所: 書庫)。この import が projects/_foo/ を作ります。… が 1 行、projects/_foo/.env が作られ exit=0
  • 構造改善のテスト追加の後の全件: uv run --locked pytest tests/ -q(570a2fe)→ 2921 passed、exit=0
  • 完了判定(7687bfb、2026-09-23 00:43): uv run --locked pytest tests/plugin/test_repos_core.py tests/env/ tests/cli/test_env_bundle_backend.py -q → 733 passed、exit=0
  • 完了判定の全件(7687bfb、2026-09-23 00:43〜00:46): uv run --locked pytest tests/ -q → 2922 passed、exit=0
  • CI が行う検査を手元で: uv run --locked python -m compileall -q lib → exit=0 / uvx ruff check --select=E9,F63,F7,F82 lib → All checks passed!、exit=0
  • 隔離した root(7687bfb)で env import <_foo と ok-name を含む書庫> --no-global → _foo だけに警告 1 行、projects/_foo/.env・projects/ok-name/.env が作られ exit=0
  • 隔離した root(7687bfb)で projects/.vscode と projects/_bar を置いて plugin sync → _bar(と前項の _foo)の実ディレクトリの警告だけが出て .vscode には出ない、exit=0
  • 確定仕様(条件 13 の 1 つ目)と CHANGELOG(条件 14 の Added): 実装レビュー(agy / kiro / codex)で差分を見た。指摘なし

🤖 Generated with Claude Code

takemi-ohama and others added 6 commits September 22, 2026 23:48
Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
symlink は今と同じく張り、戻り値も変えない(決定 1)。検査は winner の symlink の直前・
別名の symlink の直前・実ディレクトリの採取の直後の 3 か所に置き、discover_projects と
_collect_project_candidates には置かない(決定 2)。別名の案内は元の名前と <owner> の
どちらが原因かで分ける。名前の形の説明文は utils/names.NAME_FORM_HINT に置く(決定 7)。

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
import は今と同じく通し、書庫の名前の規則(_PROJECT_ENV_RE)も変えない(決定 4)。
知らせは _build_plans の直後、--dry-run の判定より前に出す。平文の projects/<name>/.env
では作ることと改名の案内を、age・サーバ backend では保存先を名指しして projects/ に
何も作らないことを書く。env/secret_store.py は触らない。

Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Refs #203

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…liases

Add characterization coverage for R1-001, R1-002, and R1-003 without changing production code.

Item-Id: R1-001
Round: 1
Impl-Runtime: codex
Impl-Model: default
@takemi-ohama

Copy link
Copy Markdown
Contributor Author

改修計画 — devbasex/devbase #233

/ndf:cross-refactoring が提案し、適用した改善項目の記録である。
理由と手順は提案の時点でしか残らないため、公開の直前に書き出している。

  • 対象範囲: lib/devbase/env/_import_merge.py, lib/devbase/env/io_import.py, lib/devbase/plugin/syncer.py, lib/devbase/utils/names.py, tests/cli/test_env_bundle_backend.py, tests/env/test_io_import.py, tests/plugin/test_repos_core.py
  • 着手前のテスト: env -u DEVBASE_ROOT uv run --locked pytest tests/plugin tests/env tests/cli -q

ラウンド 1(実装 codex / レビュー agy / kiro)

R1-001 — lib/devbase/env/_import_merge.py#project_name_of

兆候・経路 手法・階層 重要度 提案元 状態 コミット
branch unit — agy 検証中 1

なぜ: PR #233 で追加された公開関数 project_name_of はバンドル内メンバー名からプロジェクト名を抽出するが、プロジェクト名に合致するメンバーと、それ以外のメンバー(グローバル設定、メタデータ、不正なパス)で None を返す分岐の単体テストが存在しない。

手順: 1. 'env/projects/web/.env' や 'env/projects/_foo/.env' を渡し、プロジェクト名文字列 ('web', '_foo') が正しく抽出されることを確認する
2. 'env/global.env' や 'env/sources.yml' などの全体設定メンバー名を渡し、None が返されることを確認する
3. パス階層の異なる形式外パスを渡し、例外を送出せず None が返されることを確認する

R1-002 — lib/devbase/env/io_import.py#import_bundle

兆候・経路 手法・階層 重要度 提案元 状態 コミット
branch integration — agy 検証中 1

なぜ: _warn_unusable_project_names の保存先別案内において、ファイル backend 平文(projects/ 作成)と age backend(secrets/projects/ 作成)は固定されているが、サーバ backend(OpenBao)への import で形に合わないプロジェクト名を取り込む経路(plan.ref is not None)の警告文(サーバの...)および取り込み完了の振る舞いが未固定である。

手順: 1. OpenBao の fixture (openbao_root, openbao, bundle_keys) を用いて、形に合わないプロジェクト名 ('env/projects/_foo/.env') を含む暗号化バンドルを作成する
2. import_bundle を実行し、戻り値が 0 であることを確認する
3. projects/_foo ディレクトリが作成されず、サーバ (OpenBao) 側に機密が正常に保存されていることを確認する
4. caplog に形に合わないプロジェクト名に対する警告が 1 行記録され、保存先としてサーバのラベルが含まれ、'projects/ には何も作られません' が案内されていることを確認する

R1-003 — lib/devbase/plugin/syncer.py#sync_projects

兆候・経路 手法・階層 重要度 提案元 状態 コミット
normal unit — agy 検証中 1

なぜ: TestSyncProjectsNameForm では別名の owner または base が不正で警告が出るケースは固定されているが、プラグイン競合による別名 symlink 生成において、base と owner の双方が名前の形に合致する場合に警告が出ずに正常にリンクが作成される正常系経路が固定されていない。

手順: 1. 優先度の異なる 2 つのプラグインで同一プロジェクト名を定義し、双方のプロジェクト名および loser 側の owner 名が名前の形に合致するよう設定する
2. sync_projects(registry, verbose=False) を実行し、戻り値が 2 であることを確認する
3. winner の symlink と loser の別名 symlink が正常に作成されていることを確認する
4. caplog に名前の形に関する警告が 1 行も出力されていないことを確認する

見送った項目

(なし)

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | kiro | REQUEST_CHANGES

syncer.py:202 の real_projects 経路が . 始まりの実ディレクトリを除外しないため、projects/.vscode などの隠しディレクトリで毎回の同期に不要な警告が出ます。仕様の決定8(. 始まりは同期対象外・知らせも出さない)と CHANGELOG/spec の記述に反するので、実ディレクトリ列挙にも dot 除外を入れてください。詳細はインラインを参照。

Comment thread lib/devbase/plugin/syncer.py

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 1 | agy | APPROVE

PLAN66 実装1本目の要件(同期・import時の名前警告、弾かずに通知、出所に応じた案内)および確定仕様・CHANGELOGとの整合性が確認され、修正アクションを要する問題はありません。

sync_projects の実ディレクトリの知らせが .vscode などにも出ていた。
決定 8 のとおり . 始まりはプロジェクトとして扱わず、知らせも出さない。
回帰テスト test_dot_real_directories_are_not_warned を追加。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@takemi-ohama

takemi-ohama commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

/ndf:fix サマリ (round 1)

対応件数: critical=0 / major=1 / minor=0 (合計 1 件)
deferred: 0 件 / rejected: 0 件
commit: 7687bfb
CI: release base のため check-runs なし。手元で全体テスト 2922 passed、ruff (E9,F63,F7,F82) / compileall OK

詳細

  • [major] lib/devbase/plugin/syncer.py:202 — projects/ 直下の . 始まりの実ディレクトリ(.vscode など)に名前の形の警告が出ていた。決定 8 に合わせて知らせのループで . 始まりを飛ばす。回帰テスト test_dot_real_directories_are_not_warned を追加

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | codex | APPROVE

新たな修正指摘はありません(関連テスト 107 件成功)。

@takemi-ohama takemi-ohama left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 cross-review | round 2 | kiro | APPROVE

PLAN66 の「知らせだけ出し弾かない」方針に沿った追加変更で、sync_projects(実ディレクトリ / winner / 別名)と import_bundle(平文・age・サーバ backend)の各経路が保存先ごとに正しく文面を分岐している。終了コード・生成される symlink / ディレクトリは不変で、. 始まりの除外も維持されている。別名の owner 抽出 (name[len(base)+1:]) と保存先判定 (plan.ref is None かつ plan.target == projects/<name>/.env) の分岐も、age が plan.ref is None かつ plan.target が .age パスになる点と整合しており正しい。ラウンド1で提案された 3 件(project_name_of の単体、OpenBao 取り込み、正常系別名リンク)はいずれも本 PR のテストで固定済み。tests/plugin tests/env tests/cli 全 1681 件がグリーン。修正を要する点は見当たらない。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant