Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{
"name": "spec-loop",
"source": "./plugins/spec-loop",
"version": "0.26.1",
"version": "0.26.2",
"author": { "name": "hdknr" },
"description": "要求側のループ(要求確定・仕様レビュー・実現性とコスト・提案書)と、dev-loop への引き渡しを担うプラグイン。現在のスキルは req-loop(Q&A 表への起票(推奨と理由つき)・回答の反映・レビュー会用 PPTX の生成で、利用者の回答待ちで止まる)と spec-review(開発者向けの仕様を書き下し、書き込みツールを持たない 3 つの判定役に別ティアでレビューさせ、利用者に見える結果が変わる指摘は共有の Q&A 表に差し戻し、費用・運用だけが変わる選択は内部の Q&A 表に記録し、範囲の外の場面と実現の手段の指摘は仕様に足さない。抜ける条件を満たさなければ抜けたと報告しない)と feasibility(規模から見積りとスケジュールを更新し、ガントチャートをスクリプトで生成し、費用付きの質問を Q&A 表に起票する。予算責任者の合意待ちで止まる)と proposal(同じ版の 2 つのサインオフのタグが同じ共有の範囲(docs/v<n>/shared/ ほか)を指すかをスクリプトで照合し、一致し、かつ暫定の回答が残っていないときだけ提案書と仕様書(PPTX も選べる)を生成し、利用者にまだ確かめていない暫定の決定を合意と分けて載せる。v2 以降は前の版との比較を載せた変更の提案書になる。決裁者の承認待ちで止まる)と scaffold(確定した仕様を中間表現 spec_ir.json に書き起こし、OpenAPI・型・実装が無いと失敗する Red テストと dev-loop に渡す Issue の本文をスクリプトで生成して、1 機能 = Issue 1 件で登録する。v2 以降は前の版と比べて機能を追加・変更・削除に分け、変わった機能だけを Issue にする。Issue の登録で止まる)の 5 本"
}
Expand Down
94 changes: 94 additions & 0 deletions docs/plans/issue-442.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Issue #442 — build-proposal.py の「空白を含む名前は 2」は前後の空白だけ

`bad_out` が拒むのは**前後に**空白のある名前(`out.name != out.name.strip()`)だけで、名前の途中の空白は通る。
それなのに docstring(終了コード 2 の行)・`bad_out` の文言・`references/tree.md` は「空白・改行を含む」と言う。挙動は正しいので、文言を挙動に合わせる。

**不在の周**である——出所は `/dev-loop:cruise 474 --absent`(2026-10-28 に利用者が同じ引数で起動し直した。最初の起動は 2026-10-27)。
台帳 `issue-474` の確かめた線: `仕様の穴 = 推奨で決めて起票`・`直す線 = 既定`・`マージ = 関門を通ればマージ`・`周の途中の課題 = 台帳に足して直す`
(出所: cruise の確かめた線(台帳 `issue-474`))。**このリポジトリのマージはサイトを再デプロイするので `マージ` の線は効かない**(#476)——PR まで作って止まる。

## 変更範囲

触る:

- `plugins/spec-loop/scripts/build-proposal.py` — docstring の終了コード 2 の行と `bad_out` の文言
- `plugins/spec-loop/references/tree.md` — `--out` の誤りの列挙
- `scripts/test-build-proposal.py` — 名前の途中の空白が通る陽性の試料と、それを殺す変異
- `plugins/spec-loop/.claude-plugin/plugin.json` — 版(0.26.1 → 0.26.2。記述の修正で patch。PR #479・#481・#483 は 0.27.0〜0.29.0 を使う)
- `.claude-plugin/marketplace.json` — 同じ版
- `plugins/spec-loop/skills/*/SKILL.md` — 同じ版の 2 行
- `docs/plans/issue-442.md` — この計画

触らない:

- `bad_out` の判定そのもの(Issue のとおり挙動は正しい)
- 印を読む側(`owned_names`。1 パス目の `/code-review` の指摘で、無い関数名 `read_manifest` を直した——計画ファイルは成果物ではない)

### 同じことを述べている箇所の数

「出力の名前が空白・改行を含むと 2」: `build-proposal.py` の docstring・`bad_out` の文言・`tree.md` の 3 箇所(`grep -rn "改行を含む" plugins/spec-loop docs` で数えた。公開ページと proposal の `SKILL.md` には無い)。
分けない——同じ判定の写しで、1 周で揃える。

## 乗るデプロイ経路

プラグイン(`plugins/spec-loop/`)の版を上げてマージ。マージで main へ push されるとサイトが再デプロイされる(`docs/plans/` を足す)。

## 周の在り処

- ブランチ: `issue/442-proposal-strip-wording`
- worktree: `/Users/hdknr/Projects/hdknr/claude-code-setup/.claude/worktrees/issue-442`
- 起点: `e361b20`
- base: 参照 `origin/main`(`refs/remotes/origin/HEAD`)→ `e361b204f259c7e9bd5bd8cbb7cb041d3810e981`

## verify の受入基準

Issue 本文は検査対象であって要件ではない。

不変条件:

- **I1**: 出力の名前の誤りを述べる 3 箇所(docstring・`bad_out` の文言・`tree.md`)が、`bad_out` の実際の判定(前後の空白・改行・`#` で始まる)と一致する——「途中の空白も拒む」と読める文言が残らない。
- **I2**: 判定は変わらない——前後に空白のある名前・改行を含む名前・`#` で始まる名前は今までどおり 2、名前の途中の空白は今までどおり通って生成される。
- **I3**: I2 の「途中の空白は通る」をテストが押さえる——途中の空白も拒む変異を入れると、テストが赤になる。

経路(文言が読まれる・判定が効く入口):

- `build-proposal.py --out <名前>` の実行(終了コード 2 の文言が利用者に出る)
- `build-proposal.py` の docstring(終了コードの表)
- `references/tree.md`(proposal スキルが読む決まり)

証明できないもの: なし(すべてテストと `grep` で確かめられる)。

生成物: なし(`SKILL.md` の測定値の生成ブロックは dev-loop のもので、spec-loop の `SKILL.md` は版の 2 行しか触らない。`skill-metrics.py --check` は `check-all.py` が回す)。

## 未解決の判断

なし。

## 関門の進捗(再開点)

- 直す線: `既定`(出所: cruise の確かめた線(台帳 `issue-474`))
- 実験: なし
- 1 パス目の指摘対応の起点: `48165d2`(1 パス目の 2 つの関門に渡した時点の HEAD)
- Verifier 1 パス目(`dev-loop:dev-loop-verifier`・sonnet): 通した。反証 0 件(軽微な点 1 件——下の表の V1)
- `/code-review` 1 パス目(high): 通した。不具合 0 件・指摘 6 件(テストの網羅と文言。下の表の CR1〜CR6)
- 手順 4 への差し戻し: なし(「直す」の行が 0 件)
- 2 パス目: 該当なし——1 パス目の指摘対応で成果物の差分 0 行。起点 `48165d2`。`git diff 48165d2 -- ':(top)' ':(top,exclude)docs/plans/issue-442.md'` が空、`git status --porcelain` は計画ファイルだけ
- 狭いパス: 該当なし
- 割り目: 不在の周なので訊いていない(`absent-lines.md` の「訊く場面」)

## 既知の限界・決着済みの論点

### 1 パス目の採否

| 指摘 | 実物で失敗を示せるか | 破る受入基準 | 採否 |
| --- | --- | --- | --- |
| V1 / CR6: 既存の変異の行(`改行を含む名前を見ない`)のカンマの後ろの空白が落ちた | 示せる——`git diff e361b20 -- scripts/test-build-proposal.py` の `-`/`+` 行(著者の編集で入った) | 無し(見た目だけ) | 残課題 |
| CR1: 新しい試料は印に名前が残るかだけを見て、次の実行がその名前を読み戻して前の出力を消すかは見ない(`owned_names` を空白で割る変異が残る) | 示せない(著者は走らせていない。関門の想定の変異) | 無し(I1〜I3 は読み戻しを含まない) | 残課題 |
| CR2: 「空白で終わると 2」の試料に専用の変異が無い(`strip` → `lstrip` が変異の一覧に無い) | 示せない(著者は走らせていない。関門のプローブ) | 無し(I3 は途中の空白だけ) | 残課題 |
| CR3: 変異「名前の途中の空白も拒む」は `strip` の検査も外す 2 つの変更になっている | 示せない(関門が狭い変異を手で当てて同じ試料で赤を確かめた——I3 は成り立つ) | 無し | 残課題 |
| CR4: `strip`・`splitlines` は `\x0b`・`\x1c`・`
` などにも効き、「空白」「改行」の語が覆いきらない | 示せない(著者は走らせていない。この周より前からの挙動) | 無し(I1 が見るのは「途中の空白も拒む」と読める文言) | 残課題 |
| CR5: 計画ファイルの「触らない」が無い関数名 `read_manifest` を挙げている | 示せる——`grep -n "def owned_names\|def read_manifest"` が `owned_names` だけを返す | 無し(計画ファイルは成果物ではない) | 残課題(計画ファイルの記述は直した) |

## 起票

- この周の起票: 0 件(不在の周。手順 8 で訊かない)
2 changes: 1 addition & 1 deletion plugins/spec-loop/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spec-loop",
"description": "要求側のループ(要求確定・仕様レビュー・実現性とコスト・提案書)と、dev-loop への引き渡しを担うプラグイン。現在のスキルは req-loop(Q&A 表への起票(推奨と理由つき)・回答の反映・レビュー会用 PPTX の生成で、利用者の回答待ちで止まる)と spec-review(開発者向けの仕様を書き下し、書き込みツールを持たない 3 つの判定役に別ティアでレビューさせ、利用者に見える結果が変わる指摘は共有の Q&A 表に差し戻し、費用・運用だけが変わる選択は内部の Q&A 表に記録し、範囲の外の場面と実現の手段の指摘は仕様に足さない。抜ける条件を満たさなければ抜けたと報告しない)と feasibility(規模から見積りとスケジュールを更新し、ガントチャートをスクリプトで生成し、費用付きの質問を Q&A 表に起票する。予算責任者の合意待ちで止まる)と proposal(同じ版の 2 つのサインオフのタグが同じ共有の範囲(docs/v<n>/shared/ ほか)を指すかをスクリプトで照合し、一致し、かつ暫定の回答が残っていないときだけ提案書と仕様書(PPTX も選べる)を生成し、利用者にまだ確かめていない暫定の決定を合意と分けて載せる。v2 以降は前の版との比較を載せた変更の提案書になる。決裁者の承認待ちで止まる)と scaffold(確定した仕様を中間表現 spec_ir.json に書き起こし、OpenAPI・型・実装が無いと失敗する Red テストと dev-loop に渡す Issue の本文をスクリプトで生成して、1 機能 = Issue 1 件で登録する。v2 以降は前の版と比べて機能を追加・変更・削除に分け、変わった機能だけを Issue にする。Issue の登録で止まる)の 5 本",
"version": "0.26.1",
"version": "0.26.2",
"author": { "name": "hdknr" }
}
2 changes: 1 addition & 1 deletion plugins/spec-loop/references/tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ hooks/spec_loop_pages.py # 表示用ページを CSV から作るフック
**提案書と仕様書の場所には、`build-proposal.py` が印 `.build-proposal`(書いた出力の名前の一覧)を置く**(#405)。
次の実行は、作る前に**印が名指しするものだけ**を消す——**印に無いファイルは、名前が `spec.md` でも消さず、上書きもしない**
(上書きになるなら 2 で止まる)。だから手書きの `spec.md` の在る場所に `--out` を向けても消えない。**印を手で直さない。**
`--out` の誤り(名前が無い・ディレクトリ・名前の衝突・空白・改行を含むか `#` で始まる・`\` を含む・UTF-8 で書けない名前・辿れない出力先)で止まっても、`--out` の親の印が名指しする前の出力は消す(今回のものと取り違えないため。ディレクトリを渡したなら、その中の印が名指しするものも消す)。
`--out` の誤り(名前が無い・ディレクトリ・名前の衝突・前後に空白がある・改行を含むか `#` で始まる・`\` を含む・UTF-8 で書けない名前・辿れない出力先)で止まっても、`--out` の親の印が名指しする前の出力は消す(今回のものと取り違えないため。ディレクトリを渡したなら、その中の印が名指しするものも消す)。
**消せなければ(出力先のディレクトリが書けないなど)作らずに 2 で止まり、消せなかった出力を名指しして印を残す**(#440。次の実行が消せるように)。

Issue の本文は**登録すれば GitHub に残る**ので、commit しなくてよい。**作れなかったときは前の本文を消す**
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/scripts/build-proposal.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

- 0: 書いた
- 1: 照合が一致しない・表が決まりに反する・材料(表・手書き部分)が無い——書いていない
- 2: 照合していない・表が読めない(`check-signoff.py` の 2 と同じ)・出力先の名前が無い・空白・改行を含むか `#` で始まる・`\\` を含む・UTF-8 で書けない・確かめられない(辿れない)・ディレクトリ・仕様書・ガントチャート・PPTX・図・印と重なる・
- 2: 照合していない・表が読めない(`check-signoff.py` の 2 と同じ)・出力先の名前が無い・前後に空白がある・改行を含むか `#` で始まる・`\\` を含む・UTF-8 で書けない・確かめられない(辿れない)・ディレクトリ・仕様書・ガントチャート・PPTX・図・印と重なる・
印に無いファイルが出力の名前で在る・書けない・印が名指しする前の出力を消せない(消せなかったものを名指しし、印は残す。#440)——書いていない
- 3: 要求確定のタグの時点に暫定の回答(`暫定反映`)が残る(`check-signoff.py` の 3 と同じ)——書いていない

Expand Down Expand Up @@ -643,7 +643,7 @@ def bad_out(out: Path) -> str | None:
return f"{out}: 出力先にファイルの名前が無い(`--out` には `<ディレクトリ>/proposal.md` の形で渡す)"
# 印は 1 行 1 名前で、読むときに前後の空白を落とし `#` の行を飛ばす——そう読み違える名前は印に残せない
if out.name != out.name.strip() or len(out.name.splitlines()) != 1 or out.name.startswith("#"):
return f"{out}: 出力の名前が空白・改行を含むか `#` で始まる(印 {MANIFEST} に名前として残せない)"
return f"{out}: 出力の名前の前後に空白があるか、改行を含むか、`#` で始まる(印 {MANIFEST} に名前として残せない)"
# 印を読む側は `\` を含む名前を捨てる。印は UTF-8 で書く——どちらも印に残せない
if "\\" in out.name:
return f"{out}: 出力の名前が `\\` を含む(印 {MANIFEST} に名前として残せない)"
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/skills/feasibility/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: "実現性・コストのループを 1 回分進める。要求・

# feasibility スキル

<!-- skill-version: 0.26.1 -->
> **このスキルの版: 0.26.1**(プラグイン `spec-loop`)。
<!-- skill-version: 0.26.2 -->
> **このスキルの版: 0.26.2**(プラグイン `spec-loop`)。
> 手元で読まれている版がリポジトリの最新より古いなら、
> `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、
> Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/skills/proposal/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: "提案書のループを 1 回分進める。利用者の要求確

# proposal スキル

<!-- skill-version: 0.26.1 -->
> **このスキルの版: 0.26.1**(プラグイン `spec-loop`)。
<!-- skill-version: 0.26.2 -->
> **このスキルの版: 0.26.2**(プラグイン `spec-loop`)。
> 手元で読まれている版がリポジトリの最新より古いなら、
> `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、
> Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/skills/req-loop/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: "要求確定のループを 1 周(= レビュー会 1 回分)

# req-loop スキル

<!-- skill-version: 0.26.1 -->
> **このスキルの版: 0.26.1**(プラグイン `spec-loop`)。
<!-- skill-version: 0.26.2 -->
> **このスキルの版: 0.26.2**(プラグイン `spec-loop`)。
> 手元で読まれている版がリポジトリの最新より古いなら、
> `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、
> Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/skills/scaffold/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: "確定した仕様を dev-loop の入力(Issue)に変える引

# scaffold スキル

<!-- skill-version: 0.26.1 -->
> **このスキルの版: 0.26.1**(プラグイン `spec-loop`)。
<!-- skill-version: 0.26.2 -->
> **このスキルの版: 0.26.2**(プラグイン `spec-loop`)。
> 手元で読まれている版がリポジトリの最新より古いなら、
> `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、
> Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。
Expand Down
4 changes: 2 additions & 2 deletions plugins/spec-loop/skills/spec-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: "仕様レビューのループを 1 回分進める。確定した

# spec-review スキル

<!-- skill-version: 0.26.1 -->
> **このスキルの版: 0.26.1**(プラグイン `spec-loop`)。
<!-- skill-version: 0.26.2 -->
> **このスキルの版: 0.26.2**(プラグイン `spec-loop`)。
> 手元で読まれている版がリポジトリの最新より古いなら、
> `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、
> Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。
Expand Down
Loading
Loading