From c67289fa6f34c86a696dc8001a5be99e416870a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=88=E8=89=AF=20=E8=8B=B1=E6=A8=B9?= Date: Tue, 27 Oct 2026 21:02:31 +0900 Subject: [PATCH 1/6] =?UTF-8?q?scaffold.py:=20=E4=B8=AD=E9=96=93=E8=A1=A8?= =?UTF-8?q?=E7=8F=BE=E3=81=AE=E3=82=B1=E3=83=BC=E3=82=B9=E3=81=AE=20ref?= =?UTF-8?q?=EF=BC=88=E4=BB=95=E6=A7=98=E3=81=AE=E4=B8=AD=E3=81=AE=E7=95=AA?= =?UTF-8?q?=E5=8F=B7=EF=BC=89=E3=81=8C=E5=8E=9F=E6=96=87=E3=81=AB=E5=9C=A8?= =?UTF-8?q?=E3=82=8B=E3=81=8B=E3=82=92=E7=94=9F=E6=88=90=E3=81=A8=20--chec?= =?UTF-8?q?k=20=E3=81=A7=E8=A6=8B=E3=82=8B=EF=BC=88#465=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 値は突き合わせない(仕様の穴として推奨で決めた。確認は #482)。 Fixes #465 Co-Authored-By: Claude Opus 5.5 --- .claude-plugin/marketplace.json | 2 +- docs/plans/issue-465.md | 95 +++++++++++++++++++ plugins/spec-loop/.claude-plugin/plugin.json | 2 +- plugins/spec-loop/references/spec-ir.md | 1 + plugins/spec-loop/scripts/scaffold.py | 29 +++++- plugins/spec-loop/skills/feasibility/SKILL.md | 4 +- plugins/spec-loop/skills/proposal/SKILL.md | 4 +- plugins/spec-loop/skills/req-loop/SKILL.md | 4 +- plugins/spec-loop/skills/scaffold/SKILL.md | 6 +- plugins/spec-loop/skills/spec-review/SKILL.md | 4 +- scripts/test-scaffold.py | 20 ++++ 11 files changed, 157 insertions(+), 14 deletions(-) create mode 100644 docs/plans/issue-465.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 448012d5..08b6c138 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -41,7 +41,7 @@ { "name": "spec-loop", "source": "./plugins/spec-loop", - "version": "0.26.0", + "version": "0.29.0", "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/shared/ ほか)を指すかをスクリプトで照合し、一致し、かつ暫定の回答が残っていないときだけ提案書と仕様書(PPTX も選べる)を生成し、利用者にまだ確かめていない暫定の決定を合意と分けて載せる。v2 以降は前の版との比較を載せた変更の提案書になる。決裁者の承認待ちで止まる)と scaffold(確定した仕様を中間表現 spec_ir.json に書き起こし、OpenAPI・型・実装が無いと失敗する Red テストと dev-loop に渡す Issue の本文をスクリプトで生成して、1 機能 = Issue 1 件で登録する。v2 以降は前の版と比べて機能を追加・変更・削除に分け、変わった機能だけを Issue にする。Issue の登録で止まる)の 5 本" } diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md new file mode 100644 index 00000000..1227a043 --- /dev/null +++ b/docs/plans/issue-465.md @@ -0,0 +1,95 @@ +# Issue #465 — scaffold.py --check が rules.md(決定表)と spec_ir.json の一致を見ない + +`scaffold.py --check` が見るのは `spec_ir.json` ↔ `scaffold/` の 1 本だけで、仕様(決定表)↔ `spec_ir.json` の一致は機械で確かめていない。 +中間表現のケースに**仕様の中の番号(`ref`)**を持たせ、生成と `--check` がその番号が仕様の原文に在るかを確かめる。 + +**不在の周**である——出所は `/dev-loop:cruise 474 --absent`(2026-10-27、利用者が会話で「-absent でまわします」と指示)。 +台帳 `issue-474` の確かめた線: `仕様の穴 = 推奨で決めて起票`・`直す線 = 既定`・`マージ = 関門を通ればマージ`・`周の途中の課題 = 台帳に足して直す` +(出所: cruise の確かめた線(台帳 `issue-474`))。**このリポジトリのマージはサイトを再デプロイするので `マージ` の線は効かない**(#476)——PR まで作って止まる。 + +## 変更範囲 + +触る: + +- `plugins/spec-loop/scripts/scaffold.py` — ケースの `ref` を許し、`check_ref` で機能の `source` の原文に番号が在るかを見る・docstring の「守らないもの」 +- `plugins/spec-loop/references/spec-ir.md` — ケースの `ref` の行 +- `plugins/spec-loop/skills/scaffold/SKILL.md` — 手順 2 に `ref` を書く指示・版の 2 行 +- `scripts/test-scaffold.py` — 試料と変異 +- `plugins/spec-loop/.claude-plugin/plugin.json` — 版(0.26.0 → 0.29.0。機能の追加で minor。#477・#479・#481 の版と重ならない値) +- `.claude-plugin/marketplace.json` — 同じ版 +- `plugins/spec-loop/skills/*/SKILL.md` — 同じ版の 2 行 +- `docs/plans/issue-465.md` — この計画 + +触らない: + +- 決定表の値(入力・期待)と中間表現のケースの値の突き合わせ(下の「仕様の穴」で見送った) +- `check-spec-exit.py` + +### 同じことを述べている箇所の数 + +「`ref`」: `spec-ir.md` の表・`scaffold.py` の docstring(守らないもの)・scaffold の `SKILL.md` 手順 2 の 3 箇所。分けない——同じ決定の写し。 + +## 仕様の穴(不在の線で推奨により決めた) + +Issue の案は「決定表の行と `spec_ir.json` のケースを突き合わせ、過不足と値の食い違いで赤」と、 +「書式が機械で読めないなら、少なくともケースの出所(R-xx / ケース ID)が仕様に実在するか」の 2 つ。**線は `仕様の穴 = 推奨で決めて起票`**。 + +- 選択肢: (a) ケースに任意の `ref` を足し、その番号が `source` の原文に在るかだけを見る / (b) 仕様の決定表の書式を spec-loop で決め、行と値を突き合わせる / (c) `ref` を必須にする +- **決めた値: (a)** +- 理由: 仕様の決定表・テストケースの書式は spec-loop の決まりに無い(`spec-exit.md` は「番号を振っていれば番号の数、振っていなければ表のデータの行の数」と両方を許す)。(b) は書式を決める大きな変更で、既存の正本リポジトリの仕様を書き直させる。(c) は番号を振らない仕様を書き起こせなくなる。 + (a) は Issue の 2 つ目の案そのもので、#465 の実データ(`R-F10` の値を変えた仕様と古い中間表現)は**番号を残したまま値だけ変えた**ので拾えない——**値のずれは拾わない**ことを、確認の Issue に書く。 + +## 乗るデプロイ経路 + +プラグイン(`plugins/spec-loop/`)の版を上げてマージ。マージで main へ push されるとサイトが再デプロイされる(`docs/plans/` を足す)。 + +## 周の在り処 + +- ブランチ: `issue/465-scaffold-rules-check` +- worktree: `/Users/hdknr/Projects/hdknr/claude-code-setup/.claude/worktrees/issue-465` +- 起点: `eab5e13` +- base: 参照 `origin/main`(`refs/remotes/origin/HEAD`)→ `eab5e1387a3fa7587aed615754fcb7bc35cd75e0` + +## verify の受入基準 + +Issue 本文は検査対象であって要件ではない。 + +不変条件: + +- **I1**: ケースの `ref` が機能の `source` の原文のどれにも無ければ、生成も `--check` も断る(1)。別の番号の一部(`R-F100`・`R-F10a`)は在ることにしない。 +- **I2(陽性対照)**: `ref` が原文に在れば通る。`ref` を書かないケースは今までどおり。 +- **I3**: `ref` を探すのは機能の `source` の原文(`spec/` の中)だけ——`requirements/` などほかのファイルや、全体の根の外は読まない。 +- **I4**: 空・複数行・前後に空白のある `ref` は断る。 +- **I5**: 既存の試料と変異が緑。 + +経路: + +| 経路 | 守り方 | 確かめ方 | +| --- | --- | --- | +| 生成(`scaffold.py`)と `--check`・`--dry-run` が通る `check_ir` | ケースの検査で `check_ref` を呼ぶ | 試料: 在る(0)・無い(1)・別の番号の一部(1)・空(1)・`requirements/` にだけ在る(1)・`--check` でも無いと 1 | +| `check_ref` の原文の選び方 | `source` のうち `spec/` の中のファイルだけ | 試料: `requirements/r.md` にだけ番号がある | + +各経路の守りを外す変異で赤になる。 + +生成物: `skill-metrics.py` の生成ブロックは dev-loop の `SKILL.md` だけ・図の書き出しも無い——**生成物なし**。 + +未証明: なし。 + +## 未解決の判断 + +上の「仕様の穴」を確認の Issue #482 で利用者に渡す(台帳の `decisions` に記録)。 + +## 関門の進捗(再開点) + +- 直す線: `既定`(出所: cruise の確かめた線(台帳 `issue-474`)) +- 割り目(手順 4 の完了時): 不在のため訊かず続けた +- 実験: `test-scaffold.py`(試料 200 件・変異 144 件) + +## 起票 + +- この周の起票: 1 件(仕様の穴の確認の Issue。起票の承認は不在のため訊いていない) + +## 既知の限界・決着済みの論点 + +- 値(入力・期待)の突き合わせはしない——番号を残したまま値だけ変えた仕様は拾えない(仕様の穴として推奨で決めた。確認の Issue)。 +- `ref` は任意——番号を振らない仕様の機能には書けない。 diff --git a/plugins/spec-loop/.claude-plugin/plugin.json b/plugins/spec-loop/.claude-plugin/plugin.json index cc8d7cf6..994f7e1c 100644 --- a/plugins/spec-loop/.claude-plugin/plugin.json +++ b/plugins/spec-loop/.claude-plugin/plugin.json @@ -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/shared/ ほか)を指すかをスクリプトで照合し、一致し、かつ暫定の回答が残っていないときだけ提案書と仕様書(PPTX も選べる)を生成し、利用者にまだ確かめていない暫定の決定を合意と分けて載せる。v2 以降は前の版との比較を載せた変更の提案書になる。決裁者の承認待ちで止まる)と scaffold(確定した仕様を中間表現 spec_ir.json に書き起こし、OpenAPI・型・実装が無いと失敗する Red テストと dev-loop に渡す Issue の本文をスクリプトで生成して、1 機能 = Issue 1 件で登録する。v2 以降は前の版と比べて機能を追加・変更・削除に分け、変わった機能だけを Issue にする。Issue の登録で止まる)の 5 本", - "version": "0.26.0", + "version": "0.29.0", "author": { "name": "hdknr" } } diff --git a/plugins/spec-loop/references/spec-ir.md b/plugins/spec-loop/references/spec-ir.md index 514a593d..1da33376 100644 --- a/plugins/spec-loop/references/spec-ir.md +++ b/plugins/spec-loop/references/spec-ir.md @@ -126,6 +126,7 @@ python3 /scripts/scaffold.py --repo <正 | `expected` | 正常時に返すもの。**`operation.output` の項目をちょうど全部**、その型(と `enum`)で | | `error` | 失敗するケースなら、`expected` の代わりに `operation.errors` のどれか | | `qa` | このケースの根拠にした Q&A の `No` の配列(省いてよい)。機能の `qa` と同じ決まり | +| `ref` | このケースの元になった、仕様の中の行の番号(決定表の `R-F10`・テストケースの `F1-5b` など。省いてよい)。**仕様が番号を振っていれば書く**——生成と `--check` が、機能の `source` の原文にその番号が在るかを確かめる(#465。値が一致するかまでは見ない) | **`expected` と `error` は、ちょうど片方だけ書く。** **決まりに無いキーは書かない**——書いても生成物に現れないので、検査が落とす。 diff --git a/plugins/spec-loop/scripts/scaffold.py b/plugins/spec-loop/scripts/scaffold.py index e4392e25..b522a8da 100644 --- a/plugins/spec-loop/scripts/scaffold.py +++ b/plugins/spec-loop/scripts/scaffold.py @@ -87,7 +87,7 @@ | 守らないもの | なぜ | | --- | --- | -| **中間表現が仕様と意味で一致するか** | 書き起こしは判断(`scaffold` の仕事)。出所(`source` の実在・Q&A が `反映済み`)までを見る。`暫定反映` の行が表に残れば、指していなくても止める | +| **中間表現が仕様と意味で一致するか** | 書き起こしは判断(`scaffold` の仕事)。出所(`source` の実在・Q&A が `反映済み`・ケースの `ref` の番号が原文に在ること。#465)までを見る。`暫定反映` の行が表に残れば、指していなくても止める | | **Red テストが仕様のケースを漏れなく持つか** | 中間表現に書いたケースだけが生成される。漏れは書き起こしの側で見る | | **Python 以外の言語の型・テスト** | OpenAPI から対象リポジトリの道具で作る | | **Issue を登録したか・登録した本文が同じか** | 登録はスクリプトの外(`gh issue create --body-file` に、生成した本文をそのまま渡す) | @@ -343,6 +343,29 @@ def check_source(where: str, sources, whole: Path) -> list[str]: return problems +def check_ref(where: str, ref, sources, whole: Path) -> list[str]: + """ケースの `ref`——仕様の中でそのケースの元になった行の番号(決定表の `R-F10`・テストケースの `F1-5b` など。#465)。 + 機能の `source` の原文のどれかに、前後に英数字・`_`・`-` が続かない形で現れなければ断る(別の番号の一部は数えない)。 + **値(入力・期待)が仕様と一致するかは見ない**——仕様の表の書式は spec-loop の決まりに無い。""" + if not isinstance(ref, str) or not one_line(ref) or ref != ref.strip(): + return [f"{where}: 仕様の中の番号(1 行・前後に空白なし)でない: {ref!r}"] + pattern = re.compile(rf"(? list[str]: return PATH_VAR.findall(path) @@ -463,7 +486,7 @@ def check_ir(ir, whole: Path, answered: dict[str, dict[str, str]], path_rules: b continue for cindex, case in enumerate(cases or []): at = f"{where}.cases[{cindex}]" - found = keys_problem(at, case, {"id", "title", "input"}, {"expected", "error", "qa"}) + found = keys_problem(at, case, {"id", "title", "input"}, {"expected", "error", "qa", "ref"}) if found: problems += found if not isinstance(case, dict): @@ -488,6 +511,8 @@ def check_ir(ir, whole: Path, answered: dict[str, dict[str, str]], path_rules: b problems.append(f"{at}.error: operation.errors に無い: {case['error']!r}") if "qa" in case: problems += check_qa_refs(f"{at}.qa", case["qa"], answered) + if "ref" in case: + problems += check_ref(f"{at}.ref", case["ref"], feature.get("source"), whole) return problems diff --git a/plugins/spec-loop/skills/feasibility/SKILL.md b/plugins/spec-loop/skills/feasibility/SKILL.md index 0b40556a..520730f7 100644 --- a/plugins/spec-loop/skills/feasibility/SKILL.md +++ b/plugins/spec-loop/skills/feasibility/SKILL.md @@ -5,8 +5,8 @@ description: "実現性・コストのループを 1 回分進める。要求・ # feasibility スキル - -> **このスキルの版: 0.26.0**(プラグイン `spec-loop`)。 + +> **このスキルの版: 0.29.0**(プラグイン `spec-loop`)。 > 手元で読まれている版がリポジトリの最新より古いなら、 > `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、 > Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。 diff --git a/plugins/spec-loop/skills/proposal/SKILL.md b/plugins/spec-loop/skills/proposal/SKILL.md index b44b6709..1b695339 100644 --- a/plugins/spec-loop/skills/proposal/SKILL.md +++ b/plugins/spec-loop/skills/proposal/SKILL.md @@ -5,8 +5,8 @@ description: "提案書のループを 1 回分進める。利用者の要求確 # proposal スキル - -> **このスキルの版: 0.26.0**(プラグイン `spec-loop`)。 + +> **このスキルの版: 0.29.0**(プラグイン `spec-loop`)。 > 手元で読まれている版がリポジトリの最新より古いなら、 > `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、 > Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。 diff --git a/plugins/spec-loop/skills/req-loop/SKILL.md b/plugins/spec-loop/skills/req-loop/SKILL.md index 8aacf123..706082bb 100644 --- a/plugins/spec-loop/skills/req-loop/SKILL.md +++ b/plugins/spec-loop/skills/req-loop/SKILL.md @@ -5,8 +5,8 @@ description: "要求確定のループを 1 周(= レビュー会 1 回分) # req-loop スキル - -> **このスキルの版: 0.26.0**(プラグイン `spec-loop`)。 + +> **このスキルの版: 0.29.0**(プラグイン `spec-loop`)。 > 手元で読まれている版がリポジトリの最新より古いなら、 > `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、 > Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。 diff --git a/plugins/spec-loop/skills/scaffold/SKILL.md b/plugins/spec-loop/skills/scaffold/SKILL.md index 32e29739..bda31660 100644 --- a/plugins/spec-loop/skills/scaffold/SKILL.md +++ b/plugins/spec-loop/skills/scaffold/SKILL.md @@ -5,8 +5,8 @@ description: "確定した仕様を dev-loop の入力(Issue)に変える引 # scaffold スキル - -> **このスキルの版: 0.26.0**(プラグイン `spec-loop`)。 + +> **このスキルの版: 0.29.0**(プラグイン `spec-loop`)。 > 手元で読まれている版がリポジトリの最新より古いなら、 > `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、 > Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。 @@ -84,6 +84,8 @@ python3 <このスキルの base ディレクトリ>/../../scripts/check-spec-ex - **1 機能 = Issue 1 件**になるので、機能の切り方は仕様が書き分けている単位(画面の操作・API・バッチ)に合わせる。 - 各機能の `source` に、その機能を書いた仕様のファイルを**重ね合わせた全体の根からのパス**(`spec/order.md`)で、 `qa` に決定の根拠にした Q&A の No を書く。 +- **仕様が決定表の行やテストケースに番号を振っていれば、各ケースの `ref` にその番号を書く**(`R-F10` など)—— + 生成と `--check` が、その番号が `source` の原文に在るかを確かめる(書き起こしの誤り・仕様の後からの修正とのずれを拾う。#465)。 - **既にあるなら、仕様と食い違うところだけを直す。** 機能の `id` とケースの `id` を振り直さない—— 登録済みの Issue と Red テストの名前がずれる。 diff --git a/plugins/spec-loop/skills/spec-review/SKILL.md b/plugins/spec-loop/skills/spec-review/SKILL.md index 4246fd1d..490dccd1 100644 --- a/plugins/spec-loop/skills/spec-review/SKILL.md +++ b/plugins/spec-loop/skills/spec-review/SKILL.md @@ -5,8 +5,8 @@ description: "仕様レビューのループを 1 回分進める。確定した # spec-review スキル - -> **このスキルの版: 0.26.0**(プラグイン `spec-loop`)。 + +> **このスキルの版: 0.29.0**(プラグイン `spec-loop`)。 > 手元で読まれている版がリポジトリの最新より古いなら、 > `/plugin marketplace update` → `/plugin update spec-loop@claude-code-setup` の順に実行し、 > Claude Code を再起動する([#63](https://github.com/hdknr/claude-code-setup/issues/63))。 diff --git a/scripts/test-scaffold.py b/scripts/test-scaffold.py index 3c17ad01..74d09871 100644 --- a/scripts/test-scaffold.py +++ b/scripts/test-scaffold.py @@ -1133,6 +1133,18 @@ def remedy(repo: Path) -> None: Case("Q&A が表に無い", 1, "Q-099 は Q&A 表に無い", ir=edit(lambda ir: f1(ir).update(qa=["Q-099"]))), Case("ケースの Q&A が表に無い", 1, "Q-098 は Q&A 表に無い", ir=edit(lambda ir: f1(ir)["cases"][0].update(qa=["Q-098"]))), Case("Q&A の重複", 1, "Q&A の No が重複している", ir=edit(lambda ir: f1(ir).update(qa=["Q-001", "Q-001"]))), + # ケースの ref——仕様の原文にその番号が在るか(#465)。在れば通る(陽性対照)・無い/別の番号の一部/空なら断る + Case("ケースの ref が仕様に在る", 0, ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), + spec={"order.md": SPEC + "| R-F10 | silver | 9999 | 0 |\n"}), + Case("ケースの ref が仕様に無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), + Case("ケースの ref が別の番号の一部にしか無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), spec={"order.md": SPEC + "| R-F100 | x |\n| R-F10a | y |\n"}), + Case("--check もケースの ref を見る", 1, "R-F10 が仕様の原文(source)のどこにも無い", args=("--check",), + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), + Case("ケースの ref が空", 1,"仕様の中の番号(1 行・前後に空白なし)でない", ir=edit(lambda ir: f1(ir)["cases"][0].update(ref=""))), + Case("ケースの ref を仕様の外のファイルで探さない", 1, "R-F10 が仕様の原文(source)のどこにも無い", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), extra={"docs/v1/requirements/r.md": "R-F10\n"}), Case("仕様のファイルが無い", 1, "spec/missing.md が無い", ir=edit(lambda ir: f1(ir).update(source=["spec/missing.md"]))), Case("仕様の外のファイル", 1, "の中に無い", ir=edit(lambda ir: f1(ir).update(source=["shared/qa.csv"]))), # 版のディレクトリのパスは指さない(重ね合わせた全体の根からのパス) @@ -1465,6 +1477,14 @@ def remedy(repo: Path) -> None: # (名前, 壊す前, 壊した後, 殺すはずの試料の名前) MUTATIONS: list[tuple[str, str, str, str]] = [ + ("ケースの ref を見ない", ' if "ref" in case:\n problems += check_ref', + ' if False:\n problems += check_ref', "ケースの ref が仕様に無い"), + ("ref の部分一致を許す", 'pattern = re.compile(rf"(? Date: Tue, 27 Oct 2026 21:03:18 +0900 Subject: [PATCH 2/6] =?UTF-8?q?issue-465:=20=E5=86=8D=E9=96=8B=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/plans/issue-465.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md index 1227a043..7f21da21 100644 --- a/docs/plans/issue-465.md +++ b/docs/plans/issue-465.md @@ -84,6 +84,9 @@ Issue 本文は検査対象であって要件ではない。 - 直す線: `既定`(出所: cruise の確かめた線(台帳 `issue-474`)) - 割り目(手順 4 の完了時): 不在のため訊かず続けた - 実験: `test-scaffold.py`(試料 200 件・変異 144 件) +- 1 パス目の起点: `c67289f`(この後のコミットは計画ファイルだけ) +- Verifier 1 パス目: 起動(sonnet) +- `/code-review` 1 パス目: 起動(high) ## 起票 From 923fb4176de85072c37d643559904f18cc048654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=88=E8=89=AF=20=E8=8B=B1=E6=A8=B9?= Date: Tue, 27 Oct 2026 21:08:37 +0900 Subject: [PATCH 3/6] =?UTF-8?q?scaffold.py:=20ref=20=E3=81=AE=E5=B0=8F?= =?UTF-8?q?=E7=95=AA=E5=8F=B7=E3=82=92=E5=88=A5=E3=81=AE=E7=95=AA=E5=8F=B7?= =?UTF-8?q?=E3=81=A8=E3=81=BF=E3=81=AA=E3=81=99=E3=83=BBI3/I4=20=E3=81=AE?= =?UTF-8?q?=E8=A9=A6=E6=96=99=E3=81=A8=E5=A4=89=E7=95=B0=EF=BC=88#465=20?= =?UTF-8?q?=E3=81=AE=201=20=E3=83=91=E3=82=B9=E7=9B=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/plans/issue-465.md | 21 +++++++++++++++++++-- plugins/spec-loop/scripts/scaffold.py | 3 ++- scripts/test-scaffold.py | 26 ++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md index 7f21da21..b6ce908b 100644 --- a/docs/plans/issue-465.md +++ b/docs/plans/issue-465.md @@ -85,8 +85,10 @@ Issue 本文は検査対象であって要件ではない。 - 割り目(手順 4 の完了時): 不在のため訊かず続けた - 実験: `test-scaffold.py`(試料 200 件・変異 144 件) - 1 パス目の起点: `c67289f`(この後のコミットは計画ファイルだけ) -- Verifier 1 パス目: 起動(sonnet) -- `/code-review` 1 パス目: 起動(high) +- Verifier 1 パス目: 通した——反証 2 件(V1・V2) +- `/code-review` 1 パス目: 通した——指摘 7 件(CR1〜CR7) +- 1 パス目の指摘対応: CR1・V1/CR3・V2/CR2・CR4 を直した。差分は 0 行でない → 2 パス目を回す +- 割り目(2 パス目の前): 不在のため訊かず続けた ## 起票 @@ -96,3 +98,18 @@ Issue 本文は検査対象であって要件ではない。 - 値(入力・期待)の突き合わせはしない——番号を残したまま値だけ変えた仕様は拾えない(仕様の穴として推奨で決めた。確認の Issue)。 - `ref` は任意——番号を振らない仕様の機能には書けない。 +- 版 0.29.0 は、並行する PR(#477 が 0.26.1・#479 が 0.27.0・#481 が 0.28.0)と重ならないための値(CR7 は決着済み)。 + +### 1 パス目の指摘の採否 + +Verifier(sonnet): 反証 2 件。`/code-review`(high): 7 件。どちらも `git status --porcelain` は前後とも空。 + +| # | 指摘 | 実物で失敗を示せるか | 破る受入基準 | 採否 | +| --- | --- | --- | --- | --- | +| CR1 | `R-F10.1`・`R-F10/2` しか無い原文で `ref` = `R-F10` を在ることにする | 示せる(`/code-review` の試料で exit 0) | I1 | 直す(後ろに `.`・`/`・`:` と英数字が続く形を別の番号とみなす。文末の `R-F10.` は在る) | +| V1・CR3 | 前後に空白のある・複数行の `ref` の試料と変異が無い(空の試料だけ) | 示せる(Verifier の変異で素通り) | I4 | 直す(試料 2 件・変異 2 件) | +| V2・CR2 | 「仕様の外のファイルで探さない」の試料が `requirements/r.md` を `source` に入れておらず、守りを外しても緑 | 示せる(Verifier の変異で緑) | I3 | 直す(`source` に入れた試料と、守りを外す変異) | +| CR4 | 計画の「各経路の守りを外す変異で赤」が I3 では偽 | 示せる(V2 と同じ) | — (計画ファイル) | 直す(V2 の対応で真にした) | +| CR5 | `check_ref` の原文の選び方が `check_source` の写しで、`spec/spec_ir.json` を読みうる | 示せない(今は `check_source` が 1 にする) | 無し | 残課題 | +| CR6 | 読めない原文を黙って飛ばし「書き起こしの誤り」と言う | 示せない(走らせていない) | 無し(終了コードは 1 で正しい) | 残課題 | +| CR7 | 版が 0.26.0 → 0.29.0 と飛ぶ | 示せる | 無し | 残課題(並行する PR と重ならない値。上の決着)| diff --git a/plugins/spec-loop/scripts/scaffold.py b/plugins/spec-loop/scripts/scaffold.py index b522a8da..29a23658 100644 --- a/plugins/spec-loop/scripts/scaffold.py +++ b/plugins/spec-loop/scripts/scaffold.py @@ -346,10 +346,11 @@ def check_source(where: str, sources, whole: Path) -> list[str]: def check_ref(where: str, ref, sources, whole: Path) -> list[str]: """ケースの `ref`——仕様の中でそのケースの元になった行の番号(決定表の `R-F10`・テストケースの `F1-5b` など。#465)。 機能の `source` の原文のどれかに、前後に英数字・`_`・`-` が続かない形で現れなければ断る(別の番号の一部は数えない)。 + 後ろに `.`・`/`・`:` と英数字が続く形(`R-F10.1`・`R-F10/2`)も別の番号とみなす——文末の `R-F10.` は在ることにする。 **値(入力・期待)が仕様と一致するかは見ない**——仕様の表の書式は spec-loop の決まりに無い。""" if not isinstance(ref, str) or not one_line(ref) or ref != ref.strip(): return [f"{where}: 仕様の中の番号(1 行・前後に空白なし)でない: {ref!r}"] - pattern = re.compile(rf"(? None: Case("ケースの ref が仕様に無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), Case("ケースの ref が別の番号の一部にしか無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", - ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), spec={"order.md": SPEC + "| R-F100 | x |\n| R-F10a | y |\n"}), + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), + spec={"order.md": SPEC + "| R-F100 | x |\n| R-F10a | y |\n| R-F10.1 | z |\n| R-F10/2 | w |\n"}), + Case("文末の ref は在ることにする", 0, ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), + spec={"order.md": SPEC + "割引は R-F10.\n"}), Case("--check もケースの ref を見る", 1, "R-F10 が仕様の原文(source)のどこにも無い", args=("--check",), ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), - Case("ケースの ref が空", 1,"仕様の中の番号(1 行・前後に空白なし)でない", ir=edit(lambda ir: f1(ir)["cases"][0].update(ref=""))), + Case("ケースの ref が空", 1, "仕様の中の番号(1 行・前後に空白なし)でない", ir=edit(lambda ir: f1(ir)["cases"][0].update(ref=""))), + # 原文に「R-F10 |」と在っても、前後に空白のある ref・複数行の ref は断る(#465 の 1 パス目) + Case("ケースの ref の後ろに空白", 1, "仕様の中の番号(1 行・前後に空白なし)でない", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10 ")), spec={"order.md": SPEC + "| R-F10 | x |\n"}), + Case("ケースの ref が複数行", 1, "仕様の中の番号(1 行・前後に空白なし)でない", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10\nR-F11")), spec={"order.md": SPEC + "| R-F10 | x |\n| R-F11 | y |\n"}), + # source に spec/ の外のファイルを書いても(check_source が断る)、ref はそこで探さない(#465 の 1 パス目) Case("ケースの ref を仕様の外のファイルで探さない", 1, "R-F10 が仕様の原文(source)のどこにも無い", - ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), extra={"docs/v1/requirements/r.md": "R-F10\n"}), + ir=edit(lambda ir: (f1(ir).update(source=["spec/order.md", "requirements/r.md"]), + f1(ir)["cases"][0].update(ref="R-F10"))), + extra={"docs/v1/requirements/r.md": "R-F10\n"}), Case("仕様のファイルが無い", 1, "spec/missing.md が無い", ir=edit(lambda ir: f1(ir).update(source=["spec/missing.md"]))), Case("仕様の外のファイル", 1, "の中に無い", ir=edit(lambda ir: f1(ir).update(source=["shared/qa.csv"]))), # 版のディレクトリのパスは指さない(重ね合わせた全体の根からのパス) @@ -1479,10 +1490,17 @@ def remedy(repo: Path) -> None: MUTATIONS: list[tuple[str, str, str, str]] = [ ("ケースの ref を見ない", ' if "ref" in case:\n problems += check_ref', ' if False:\n problems += check_ref', "ケースの ref が仕様に無い"), - ("ref の部分一致を許す", 'pattern = re.compile(rf"(? Date: Tue, 27 Oct 2026 21:12:37 +0900 Subject: [PATCH 4/6] =?UTF-8?q?issue-465:=202=20=E3=83=91=E3=82=B9?= =?UTF-8?q?=E7=9B=AE=E3=81=AE=E5=86=8D=E9=96=8B=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/plans/issue-465.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md index b6ce908b..50fad2d4 100644 --- a/docs/plans/issue-465.md +++ b/docs/plans/issue-465.md @@ -89,6 +89,9 @@ Issue 本文は検査対象であって要件ではない。 - `/code-review` 1 パス目: 通した——指摘 7 件(CR1〜CR7) - 1 パス目の指摘対応: CR1・V1/CR3・V2/CR2・CR4 を直した。差分は 0 行でない → 2 パス目を回す - 割り目(2 パス目の前): 不在のため訊かず続けた +- 2 パス目の起点: `923fb41`(この後のコミットは計画ファイルだけ) +- Verifier 2 パス目: 起動(sonnet) +- `/code-review` 2 パス目: 起動(high) ## 起票 From 883cdd68aab6460fd62cc496a3cc2b15b8a26a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=88=E8=89=AF=20=E8=8B=B1=E6=A8=B9?= Date: Tue, 27 Oct 2026 21:17:23 +0900 Subject: [PATCH 5/6] =?UTF-8?q?scaffold.py:=20ref=20=E3=81=AE=E5=A2=83?= =?UTF-8?q?=E7=95=8C=E3=82=92=E5=89=8D=E5=BE=8C=E3=81=A7=E6=8F=83=E3=81=88?= =?UTF-8?q?=E3=83=BB=E5=85=A8=E8=A7=92=E3=81=AE=E8=8B=B1=E6=95=B0=E5=AD=97?= =?UTF-8?q?=E3=82=92=E5=90=AB=E3=82=81=E3=83=BB=E5=8C=BA=E5=88=87=E3=82=8A?= =?UTF-8?q?=E3=81=AE=E5=BE=8C=E3=82=8D=E3=81=AF=E6=95=B0=E5=AD=97=E3=81=A0?= =?UTF-8?q?=E3=81=91=E5=88=A5=E3=81=AE=E7=95=AA=E5=8F=B7=E3=81=A8=E3=81=BF?= =?UTF-8?q?=E3=81=AA=E3=81=99=EF=BC=88#465=20=E3=81=AE=202=20=E3=83=91?= =?UTF-8?q?=E3=82=B9=E7=9B=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/plans/issue-465.md | 23 ++++++++++++++++++++--- plugins/spec-loop/scripts/scaffold.py | 7 +++++-- scripts/test-scaffold.py | 26 +++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md index 50fad2d4..1063a137 100644 --- a/docs/plans/issue-465.md +++ b/docs/plans/issue-465.md @@ -83,15 +83,17 @@ Issue 本文は検査対象であって要件ではない。 - 直す線: `既定`(出所: cruise の確かめた線(台帳 `issue-474`)) - 割り目(手順 4 の完了時): 不在のため訊かず続けた -- 実験: `test-scaffold.py`(試料 200 件・変異 144 件) +- 実験: `test-scaffold.py`(最初 試料 200 件・変異 144 件 → 2 パス目の対応の後 208 件・153 件) - 1 パス目の起点: `c67289f`(この後のコミットは計画ファイルだけ) - Verifier 1 パス目: 通した——反証 2 件(V1・V2) - `/code-review` 1 パス目: 通した——指摘 7 件(CR1〜CR7) - 1 パス目の指摘対応: CR1・V1/CR3・V2/CR2・CR4 を直した。差分は 0 行でない → 2 パス目を回す - 割り目(2 パス目の前): 不在のため訊かず続けた - 2 パス目の起点: `923fb41`(この後のコミットは計画ファイルだけ) -- Verifier 2 パス目: 起動(sonnet) -- `/code-review` 2 パス目: 起動(high) +- Verifier 2 パス目: 通した——反証 1 件(W1) +- `/code-review` 2 パス目: 通した——指摘 8 件(P1〜P8) +- 2 パス目の指摘対応: P2・P3・W1・P5・P7・P8 を直した。終点は下の狭いパスに渡すコミット +- 狭いパス: 起動(sonnet) ## 起票 @@ -116,3 +118,18 @@ Verifier(sonnet): 反証 2 件。`/code-review`(high): 7 件。どちら | CR5 | `check_ref` の原文の選び方が `check_source` の写しで、`spec/spec_ir.json` を読みうる | 示せない(今は `check_source` が 1 にする) | 無し | 残課題 | | CR6 | 読めない原文を黙って飛ばし「書き起こしの誤り」と言う | 示せない(走らせていない) | 無し(終了コードは 1 で正しい) | 残課題 | | CR7 | 版が 0.26.0 → 0.29.0 と飛ぶ | 示せる | 無し | 残課題(並行する PR と重ならない値。上の決着)| + +### 2 パス目の指摘の採否 + +Verifier(sonnet): 反証 1 件(W1)。`/code-review`(high): 8 件。どちらも `git status --porcelain` は前後とも空。 + +| # | 指摘 | 実物で失敗を示せるか | 破る受入基準 | 採否 | +| --- | --- | --- | --- | --- | +| P1 | **v2 で既存のケースに `ref` を足すと、機能の比較(`compare_maps`)と指紋(`fingerprint`)が機能を「変更」とみなす**——Red テストは変わらないのに変更の Issue の本文が出て、登録済みの Issue の指紋も古くなる | 示せない(読解。走らせていない) | 無し(受入基準は `ref` を書かないケースと書いたケースの検査だけ) | **残課題(マージの前に人間が判断)** | +| P2 | 1 パス目の対応で `R-F10/R-F11`・`R-F10.md` の `R-F10` を「無い」と言うようになった | 示せる(`/code-review` の試料) | I2 | 直す(区切りの後ろは数字だけを別の番号とみなす) | +| P3・W1 | 前の境界が非対称——`XR-F10`・`R-F10.1` の `1` を在ることにし、前に付く形の試料・変異が無い | 示せる(Verifier の変異・`/code-review` の試料) | I1 | 直す(前の境界を揃え、数字で始まる `ref` は前の小番号の区切りも見る。試料と変異) | +| P4 | `SKILL.md` の「仕様の後からの修正とのずれを拾う」が言い過ぎ(値は見ない・取り消し線やコメントの番号も在る) | 示せる(文言と試料) | 無し | 残課題 | +| P5 | 境界が ASCII だけ——`R-F10a`(全角)を別の番号とみなさない | 示せる(`/code-review` の試料) | I1 | 直す(全角の英数字も境界に入れる) | +| P6 | ケースごとに原文を読み直す(N×M) | 示せない(性能) | 無し | 残課題 | +| P7 | 計画の件数が古い | 示せる | — (計画ファイル) | 直す | +| P8 | `--dry-run` の試料が無い(v2 の試料も無い) | 示せる(試料の一覧) | I1(経路の表の `--dry-run`) | 直す(`--dry-run` の試料。v2 は P1 と一緒に残課題) | diff --git a/plugins/spec-loop/scripts/scaffold.py b/plugins/spec-loop/scripts/scaffold.py index 29a23658..e4f3c2f0 100644 --- a/plugins/spec-loop/scripts/scaffold.py +++ b/plugins/spec-loop/scripts/scaffold.py @@ -346,11 +346,14 @@ def check_source(where: str, sources, whole: Path) -> list[str]: def check_ref(where: str, ref, sources, whole: Path) -> list[str]: """ケースの `ref`——仕様の中でそのケースの元になった行の番号(決定表の `R-F10`・テストケースの `F1-5b` など。#465)。 機能の `source` の原文のどれかに、前後に英数字・`_`・`-` が続かない形で現れなければ断る(別の番号の一部は数えない)。 - 後ろに `.`・`/`・`:` と英数字が続く形(`R-F10.1`・`R-F10/2`)も別の番号とみなす——文末の `R-F10.` は在ることにする。 + 英数字には全角の英数字も含める(`R-F10a` は別の番号)。後ろに `.`・`/`・`:` と数字が続く形(`R-F10.1`・`R-F10/2`)も別の番号とみなし、 + 数字で始まる `ref` は前に英数字と `.`・`/`・`:` が付く形(`R-F10.1` の `1`)を別の番号の一部とみなす—— + `R-F10.`(文末)・`R-F10.md`・`R-F10/R-F11` の `R-F11` は在ることにする。 **値(入力・期待)が仕様と一致するかは見ない**——仕様の表の書式は spec-loop の決まりに無い。""" if not isinstance(ref, str) or not one_line(ref) or ref != ref.strip(): return [f"{where}: 仕様の中の番号(1 行・前後に空白なし)でない: {ref!r}"] - pattern = re.compile(rf"(? None: ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), Case("ケースの ref が別の番号の一部にしか無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), - spec={"order.md": SPEC + "| R-F100 | x |\n| R-F10a | y |\n| R-F10.1 | z |\n| R-F10/2 | w |\n"}), + spec={"order.md": SPEC + "| R-F100 | x |\n| R-F10a | y |\n| R-F10.1 | z |\n| R-F10/2 | w |\n| R-F10a | v |\n"}), + # 前に付く形も別の番号の一部(#465 の 2 パス目) + Case("ケースの ref が別の番号の後ろの一部にしか無い", 1, "R-F10 が仕様の原文(source)のどこにも無い", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), spec={"order.md": SPEC + "| XR-F10 | x |\n| XR-F10 | y |\n"}), + Case("数字の ref が小番号にしか無い", 1, "1 が仕様の原文(source)のどこにも無い", + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="1")), spec={"order.md": SPEC + "| R-F10.1 | x |\n"}), + # 区切りの後ろが数字でなければ在ることにする(2 パス目の P2) + Case("拡張子の付いた ref は在ることにする", 0, ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), + spec={"order.md": SPEC + "R-F10.md を見る。\n"}), + Case("区切りの後ろの ref は在ることにする", 0, ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F11")), + spec={"order.md": SPEC + "R-F10/R-F11 を参照。\n"}), + Case("--dry-run もケースの ref を見る", 1, "R-F10 が仕様の原文(source)のどこにも無い", args=("--dry-run",), + ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10"))), Case("文末の ref は在ることにする", 0, ir=edit(lambda ir: f1(ir)["cases"][0].update(ref="R-F10")), spec={"order.md": SPEC + "割引は R-F10.\n"}), Case("--check もケースの ref を見る", 1, "R-F10 が仕様の原文(source)のどこにも無い", args=("--check",), @@ -1490,8 +1502,16 @@ def remedy(repo: Path) -> None: MUTATIONS: list[tuple[str, str, str, str]] = [ ("ケースの ref を見ない", ' if "ref" in case:\n problems += check_ref', ' if False:\n problems += check_ref', "ケースの ref が仕様に無い"), - ("ref の部分一致を許す", 'pattern = re.compile(rf"(? None: "ケースの ref が複数行"), ("ref を仕様の外でも探す", " if not path.is_relative_to(spec_root):\n continue\n", "", "ケースの ref を仕様の外のファイルで探さない"), - ("ref の後ろの小番号を別の番号とみなさない", "(?![A-Za-z0-9_-]|[./:][A-Za-z0-9])", "(?![A-Za-z0-9_-])", + ("ref の後ろの小番号を別の番号とみなさない", "A-Za-z0-9]|[./:][0-9])", "A-Za-z0-9])", "ケースの ref が別の番号の一部にしか無い"), ("ref を在れば通す", " return []\n except (OSError, UnicodeDecodeError, ValueError):", " pass\n except (OSError, UnicodeDecodeError, ValueError):", "ケースの ref が仕様に在る"), From 4a81ea0b9c99b7e5e51989472c930d78cb6b9b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=88=E8=89=AF=20=E8=8B=B1=E6=A8=B9?= Date: Tue, 27 Oct 2026 21:21:39 +0900 Subject: [PATCH 6/6] =?UTF-8?q?issue-465:=20=E7=8B=AD=E3=81=84=E3=83=91?= =?UTF-8?q?=E3=82=B9=E3=81=AE=E7=B5=90=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/plans/issue-465.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/plans/issue-465.md b/docs/plans/issue-465.md index 1063a137..c12aa51f 100644 --- a/docs/plans/issue-465.md +++ b/docs/plans/issue-465.md @@ -92,8 +92,9 @@ Issue 本文は検査対象であって要件ではない。 - 2 パス目の起点: `923fb41`(この後のコミットは計画ファイルだけ) - Verifier 2 パス目: 通した——反証 1 件(W1) - `/code-review` 2 パス目: 通した——指摘 8 件(P1〜P8) -- 2 パス目の指摘対応: P2・P3・W1・P5・P7・P8 を直した。終点は下の狭いパスに渡すコミット -- 狭いパス: 起動(sonnet) +- 2 パス目の指摘対応: P2・P3・W1・P5・P7・P8 を直した。起点 `923fb41` → 終点 `883cdd6` +- 狭いパス: 通した(sonnet)——指摘 2 件(人間が決める): (1) 全角の区切り・全角の数字(`R-F10.1`・`R-F10.1`)を別の番号とみなさない (2) 境界の文字クラスの要素(`_`・`-`・全角の数字・`:` など)12 件を 1 つずつ欠く変異が ref の試料 14 件では素通りする +- PR: 作る(マージは止まる。#476) ## 起票