設計(PLAN66): 名前の形に合わないプロジェクトを、作られた時点で知らせる (#203) - #230
Conversation
- プラグインの同期と env import で名前の形を検査し、弾かずに警告に留める - スナップショットの名前の形を utils/names の述語へ寄せる - 実装は含まない(設計だけの Pull Request) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
設計・要求文書 2 件をコードベースに突き合わせて検証した。参照する関数・シンボル(_collect_project_candidates / _link_loser_projects / sync_projects / _extract_owner / discover_projects / maybe_cd_project / _named_lifecycle_project / _build_single_image / _PROJECT_ENV_RE)はすべて実在し、行参照(syncer.py:155-157 の symlink 全削除ループ、snapshot の _VALID_NAME_RE)も一致した。末尾改行の食い違い(_VALID_NAME_RE.match("abc\n") が True・is_single_segment_name は False)、決定 5 が引く SnapshotError 文言、TestSyncProjects が 7 件であること、空文字が述語で弾かれ not name ガードを外せることも実測で確認した。docs/specifications/cli-argument-resolution.md の「運用」の書き換え対象の箇条書きも引用どおり存在する。
実装を含まない設計 PR として、誤ったパス・存在しないシンボル・文書間の矛盾・実装との齟齬・読者を誤らせる記述は見つからなかった。修正アクションのある指摘は無いため APPROVE とする。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | agy | REQUEST_CHANGES
プラグイン同期時の警告ロジックおよび env import 時のログ文言に関して、以下の設計・仕様の修正を提案します。
-
プラグイン同期における重複警告と誤報の防止(設計):
_collect_project_candidates内で警告を出力すると、複数プラグイン間で同名プロジェクトが衝突した場合や実ディレクトリ(real_projects)が存在する場合に重複して警告が出力され、さらにスキップされた候補に対しても「projects/ に載りました」と事実と異なる警告が出てしまいます。警告出力は候補収集時ではなく、実際にprojects/にシンボリックリンクを作成する処理(実ディレクトリのスキップ後)で行う設計に見直してください。 -
env importにおける--dry-run時の文言整合性(正確性):
--dry-run時や実際のファイル書き込み前に警告を出す設計に対し、文言が完了形の「projects/_foo/ を作りました」と固定されているため、書き込みが行われない dry-run 実行時や書き込みエラー時に実態と矛盾します。作成前や dry-run でも矛盾しない表現への修正が必要です。 -
要求仕様書におけるテスト対象ファイルの表記是正(正確性):
受け入れ条件の検証欄で、既存ファイル(test_repos_core.py,test_io_import.py)が「(新設)」と記載されている箇所をテストケース追加の実態に合わせて修正してください。
- 検査の位置を候補の集約から symlink を張る直前へ移す(同じ名前で 2 行出る・載らない名前にも出る) - 知らせの文を完了形にせず、dry-run や書き込み失敗と矛盾しない形にする - 決定 7 の共通化の範囲(ヒント文だけ)を明記する - 既存のテストファイルへの追加であることを検証欄に書く Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
round 1 レビュー指摘の対応(4 件)コミット
内訳
CI は base を 🤖 Generated with Claude Code |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | codex | REQUEST_CHANGES
import の保存先ごとの挙動に合わせて、警告の契約と検証条件を修正してください。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | COMMENT
設計・要求の事実主張(改行の食い違い、syncer 以外の入口としての env import、別名合成、行番号参照)はコードと突き合わせて確認でき、正確でした。指摘は 1 件のみ(インライン: 2 文書間で同一 parametrize テストの拒否件数が 7 と 8 で食い違う)。それ以外にブロッキングな修正提案はありません。
- env import の知らせを保存先ごとの文にする(age・サーバ backend は projects/ に作らない) - 受け入れ条件へ age の保存先の条件を足す(番号を 1 つ繰り下げ) - 受け入れ条件 11 の拒否リストへ末尾の改行を足し、設計の 8 件と揃える Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cross-review round 2 対応サマリround 2 のレビュー指摘 2 件へ対応しました。反映コミットは 内訳
重要度の内訳: critical 0 / major 1 / minor 1 / nit 0 対応した指摘
Resolve 状況
CICI は未実行です。この PR は base が |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | codex | APPROVE
要求仕様・設計と現行実装を照合し、修正を求める指摘はありません。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 3 | agy | REQUEST_CHANGES
ラウンド 2 での指摘対応(age/サーバ backend 保存時の警告分岐、末尾改行を含むスナップショット名拒否パターンの統一、受け入れ条件の追加)が適切に反映されていることを確認しました。
本ラウンドでは、テスト設計における fixture の前提条件の不一致(major 1 件)および文書・設計の整合性・明確化(minor 4 件)についてインラインコメントで指摘しています。
- age の保存先の受け入れ条件を backend を明示する流儀へ(平文へ落ちると条件を確かめられない) - 同期の知らせの案内を出所ごとに分ける(別名と実ディレクトリでは改名先が違う) - F2 と用語の定義を保存先の違いに合わせる - real_projects を sorted で走査する旨を明記する - 前提の番号の順序を昇順へ直す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
round 3 のレビュー指摘への対応(5 件すべて反映)コミット: 内訳
重要度: critical 0 / major 1 / minor 4 / nit 0 対応した指摘
thread の状態
CI未実行です(#216)。この PR は base が |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 4 | kiro | APPROVE
設計・要求ともコード(syncer.py / io_import.py / _import_merge.py / secret_store.py / snapshot/manager.py / utils/names.py / ci.yml)と照合し、参照シンボル・行番号・正規表現の挙動・NAME_FORM_HINT の文言一致・保存先分岐(plan.target+plan.ref で平文/age/サーバの 3 経路を過不足なく判別できること)まで確認した。修正を要する不整合は見つからなかった。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 5 | codex | REQUEST_CHANGES
別名の改名案内について、修正を求める指摘が 1 件あります。
- 別名の案内を、名前の側と owner の側で分ける(_foo.valid-owner は改名で直る) - 分かれ目を is_single_segment_name(<名前>) と明記し、_warn_unusable_name へ base を渡す - 受け入れ条件 3 を 2 つの分岐で確かめる形にする(3 と 3-2) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cross-review round 5 対応サマリround 5 のレビュー指摘 1 件へ対応しました。反映コミットは 内訳
重要度: critical 0 / major 0 / minor 1 / nit 0 対応した指摘
Resolve と残り
CICI は未実行です。base が |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 6 | kiro | APPROVE
設計・要求のみの PR。コードは含まない。差分の技術的な主張(syncer.py:155-157 の unlink→張り直し、env/runtime.py:119 の相対パス解決、secret_store.py:294-299 の age 保存先、io_import.py:220 の store.path(ref)、is_single_segment_name の fullmatch と _VALID_NAME_RE の match+$ の差、_PROJECT_ENV_RE の構築、規則 6 か所と _GROUP_NAME_RE の存在、行数指標 設計 429 / 要求 326)を実コードと照合し、いずれも一致した。2 文書間の前提・決定・受け入れ条件・実装分割(PR1/PR2)の対応にも矛盾は無く、範囲外項目は #226〜#229 として起票済み。実装者を誤らせる誤記・不整合・矛盾する指示は見つからなかったため、修正アクションの指摘は無い。
Summary
名前の形に合わないプロジェクト(
_fooなど)を、projects/に載った時点で知らせる設計。弾くか警告に留めるか、
SINGLE_SEGMENT_NAME_PATTERNと_VALID_NAME_REを寄せるかを決めた。実装は含まない。
issues/PLAN66_project-name-validation.mdissues/PLAN66_project-name-validation-design.md参照: #203 / release Pull Request #212 / 範囲外として起票した #226 #227 #228 #229
この設計で変わること
devbase plugin install/update/syncとdevbase env importに警告が 1 行増える。作られるものと終了コードは変わらない。 名前の形に合わないプロジェクトを持つ利用者に
移行の作業を求めない(弾かないため、どの操作も今と同じく通る)。
変わるものが 1 つある。スナップショットの名前が末尾の改行を受け付けなくなる
(
devbase snapshot create "abc\n"がSnapshotError)。今は通る。実測(この作業ツリー /
release/v3.7.0の先頭 688efde)issue #203 の本文の 2 つの記述が事実と違う。
syncerがprojects/に名前を載せる唯一の入口」は誤り。 隔離した root でenv/projects/_foo/.envを含む書庫を import すると、projects/_foo/が実ディレクトリとして作られ、終了コード 0 で警告が 1 行も出ない。同期だけを直しても、名前の指定から
操作できないプロジェクトは生まれる
「名前を検証する規則は 4 か所」は過少。 プロジェクト名そのものを見る規則は 6 か所
(本文の 3 つ +
env/_import_merge.pyの_PROJECT_ENV_RE+bin/devbaseの_SINGLE_SEGMENT_NAME_RE+syncer.discover_projectsの.始まりの除外)。同じ文字集合の正規表現は他に
volume/manager.pyの_GROUP_NAME_REがある「文字集合が同じ」だが振る舞いは違う。
_VALID_NAME_REはre.match+$のため末尾の改行を通す。
本文の「今のところ実在しない」は正しい。 登録済み 3 リポジトリ・22 プラグインの
projects/直下 133 件すべてが名前の形に合う(.始まり 0 件・先頭_0 件・ASCII 外 0 件)。読み取りだけで数え、実環境に対して
plugin install/update/syncは実行していない
devbase 自身が名前の形に合わない名前を作れる。 衝突に敗れた側へ張る別名
<名前>.<owner>のownerは、--linkのプラグインでは元パスの basename そのままである。既存の利用者に何が起きるか
projects/<名前>へ cd して名前なしに打つ)_fooを含む書庫を import するSnapshotErrorになる(該当する利用者がいるとは考えにくいが、受け付ける名前を狭める唯一の変更)弾く形を採らなかった理由は設計の決定 1 にある。要点は、symlink を張らないと
env/runtime.pyがプロジェクトをprojects/からの相対パスで決めるため、プラグインのクローンへ cd してもプロジェクトとして扱われなくなることである。同期の全体を失敗させる形は、
1 件の名前でそのプラグインの他のプロジェクトも
projects/から消す(同期は既存の symlink を全部消してから張り直す)。
実装の分け方
syncerの 3 か所とenv import・確定仕様の「運用」の 1 つ目・CHANGELOG)utils/namesへ寄せる(確定仕様の「運用」の 2 つ目)他の束との重なり
docs/specifications/cli-argument-resolution.mdは PR docs: [name] / --context を取るサブコマンドの列挙を揃え、profiles に requires.devbase の手順を足す (#208, #195) #213(未マージ)が触っていない。docs: [name] と --context を取るサブコマンドの列挙が 8 か所の文書で古く、rebuild / open が抜けている #208 の調査で「他のショートカット」の節は直す対象でないと確認済み。この束が触るのは
「運用」の節である
lib/devbase/commands/container.pyは触らない。 G5(container.py: cmd_scale の長いメソッドと compose config 読み取りの重複を整理する #192)の束が同じファイルを触るため、文言の定数への寄せは 名前の形を説明する文言を utils/names.py の定数へ寄せる(container.py のインラインの文言) #229 として範囲外に出した
lib/devbase/env/secret_store.pyは触らない。 G4(env backend test / env list の見出しが読み替え前のグループ名だけを出す(グループ default) #188)の束が触るためDEVBASE_ROOTの隔離は PR test: pytest のセッション全体で DEVBASE_ROOT を隔離する (#209) #217(未マージ)が入れる。 この設計のテストはPluginRegistry(tmp_path)とimport_bundle(tmp_path, ...)だけを使い、DEVBASE_ROOTに依存しない
範囲外として起票したもの
plugin infoが.始まりを除外せず、discover_projectsと食い違うowner--repo、実装はホスト名を含む)utils/names.pyの定数へ寄せる(container.pyの重複)決めたこと
issues/PLAN66_project-name-validation-design.mdprojects/に名前を載せる直前に置き、列挙と集約には置かないenv importの知らせは保存先ごとに文を変え、書庫の名前の規則は変えないutils/namesの述語を共有するutils/names.pyに置き、ログはそこから出さないdiscover_projectsの.始まりの黙った除外は変えないcross-review
6 ラウンド回し、指摘 12 件(major 4 / minor 8)をすべて受け入れて設計を変えた(deferred 0 /
rejected 0 / 未解決 0)。
round 4 で agy が 2 回とも
result.jsonを残さなかったため、担当を 1 者へ絞って round 5・6 で埋めた。最終の内容(b6ad9b9)は kiro が指摘なしで承認している。
Test plan
設計の段階で確かめたことを載せる。実装はこの Pull Request に含まれないため、
pytestは実装の Pull Request で回す。
release/v3.7.0を base にした Pull Request では CI が 1 件も動かない(ci: リリースブランチ宛の Pull Request で検査ジョブが 1 件も動かない(on.pull_request.branches が main だけ) #216)。.github/workflows/ci.ymlのon.pull_request.branchesがmainだけであるimport_bundleを実行し、projects/_foo/が実ディレクトリとして作られ、
_resolve_project_name('_foo')が False になることを確かめた(上の実測 1)。実環境の
DEVBASE_ROOTには触っていない_link_loser_projectsを隔離した root で呼び、carmo.my pluginの symlink が張られることを確かめた(上の実測 5)
plugins.ymlの 22 プラグインを辿り、projects/直下 133 件の名前をre.fullmatchで判定した(読み取りのみ。実測 4)。コミット済みの名前も
git ls-treeで数え、未コミットの手元のディレクトリ 3 件を特定した
is_single_segment_nameと_VALID_NAME_REの差を入力 12 件で測り、末尾の改行だけが食い違うことを確かめた(実測 3)
_VALID_NAME_REの使用箇所が_validate_name1 か所だけで、長さ制限と予約語が無いことを確かめた(
grep -n "len(name)\|RESERVED\|maxlen" lib/devbase/snapshot/manager.py→ 0 件)
TestSyncProjectsが 7 件で、test_real_directory_skippedを含むことを確かめた(受け入れ条件 4・14 の土台)
io_import._build_plansがstore.path(ref)で書き出し先を決め、age の backend のpath()がsecrets/projects/<名前>.env.ageを返すことを実装で確かめた(
lib/devbase/env/io_import.py:220とlib/devbase/env/secret_store.py:294-299)。round 2 の codex の指摘のとおり、age 保存では
projects/<名前>/を作らないtests/env/test_store_roundtrip.pyのrootfixture がbackend_configを書かず、tests/cli/test_env_bundle_backend.py:300のbc.save(root, bc.BackendConfig(backend='age'))が backend を明示する流儀であることを確かめた(round 3 の agy の指摘。受け入れ条件 9 の
検証先をこちらへ移した)
ドキュメント再構成の前後
「後」の値は round 1(e207cc7)・round 2(08414c1)・round 3(5233da4 / b90dc0a)・
round 5(bed1fea / b6ad9b9)のレビュー指摘への対応を含む。
目安を超えた項目:
## 依頼(原文)の引用の中の 1 文で、issue プロジェクト名の検証の規則が env の export / import・機密の保存先・名前の指定で食い違う #203 の本文そのままである。採らなかった直し方: 引用を分ける(
requirements-designが「原文の引用を省かない・要約しない」と定めている)
採らなかった案を持つ。採らなかった直し方: 決定を章へ分ける(設計文書の雛形が
「決定の記録」を 1 節と定めており、
pr-body-decisions.shもこの見出しの下を読む)処理の流れのうち 2 つ)と、図に現れない要素の説明が入る。採らなかった直し方: 図を 1 つずつ
章にする(図の対応が読めなくなる)
行数の増え方: 要求仕様 +7 行(受け入れ条件 12 を 3 つの箇条書きへ、章の分割 3 件)、
設計 +16 行(「変えないもの」の文を 6 行の表へ、「検査を置く 3 か所」の文を 3 行の表へ、
章の分割 1 件)。round 1 の対応でさらに要求仕様 +1 行・設計 +11 行(決定 2 の理由の追加、
「警告の文」の箇条書きの追加)。round 2 の対応で要求仕様 +10 行・設計 +19 行(受け入れ条件
9 の追加、決定 4 の理由と採らなかった案の追加、保存先ごとの文の表)。round 3 の対応で
要求仕様 +2 行・設計 +6 行(出所ごとの案内の表、章の分割 1 件)。round 5 の対応で要求仕様
+6 行・設計 +7 行(受け入れ条件 3-2 の追加、別名の案内の分岐)。
測れなかった指標: なし
再構成の中で別の作業として足したもの: なし