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
10 changes: 8 additions & 2 deletions docs/specifications/ndf-production-release-record.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,20 @@ python3 release-steps.py record --version <版> --prs <PR番号>... [--plugin <
### まとめのプランの記録の PR と `release-verify`

まとめのプラン(`supervise_lib/sprint.py` の `close_plan`)は、記録の PR の参照を経路から決め(`supervise_lib/sprint_routes.py` の
`record_pr_ref`)、記録の PR が `{queue_pr:…}` で決まる経路ではマージの後・`close` の前に work ステップ `release-verify`(`/ndf:release-verification`)を置く。
`record_pr_ref`)、記録の PR の参照が `0` でない経路ではマージの後・`close` の前に work ステップ `release-verify`(`/ndf:release-verification`)を置く。

| 経路 | `close` の `--record-pr` | `release-verify` |
| --- | --- | --- |
| 雛形(`release.form`) | `{queue_pr:release-prod}` | 置く |
| 昇格(`route_waves` が昇格のプランを置き、開発版のチャネルが手で届ける本番でないとき) | `{queue_pr:promote}` | 置く |
| 経路がすべて届けない経路(none) | `0`(本番の記録なし。条件を見ずに閉じる) | 置かない |
| それ以外(merge・manual・検証の環境だけ・手動反映の本番系の昇格) | `unknown`(記録の置き場が分からない。課題を理由つきの `kept_open` で開いたまま残し、ボードも書かない) | 置かない |
| それ以外(merge・manual・検証の環境だけ・手動反映の本番系の昇格) | `{queue_record}`(まとめを流し始める時点に queue が GitHub の参照から記録の PR を探して埋める。#2230) | 置く |
| 開発ループのまとめ(`new close --pace auto`)で、経路がすべて届けない経路でないとき | 経路にかかわらず `{queue_record}`(承認ゲート 2 の後のまとめは本番のプランと別の queue にあり、`{queue_pr:…}` を解けない) | 置く |

`{queue_record}` は、まとめの課題を閉じる PR とそれを参照する PR のリリース記録のうち、段階が本番か配布なしで `スプリント:` が
その閉じる PR を含む記録を置いた PR の番号で埋まる(`sprint_close_lib/record_find.py`)。見つからない・2 つ以上のスプリントにある・
GitHub を読めなければ、まとめを流さずに止まる(queue の結果は `stopped`、開発ループの周回は失敗で締まる)。まとめのプランは
`sprint-close.py --record-pr unknown` を組まず、`unknown` を渡すのは手で打つ入口と #2230 より前に組んだプランだけである。

`release-verify` は、記録の PR にリリース後テストの記録をコメントで置き、課題は閉じない。実行時に番号が `0` になったとき
(最終の検査で変更が無く、まとめの queue の本番が飛ばされたとき)は何もせずに終える。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

スプリントの機械の判定が、記録の無い状態や「確かめる中身が無い」行を取り違えないようにする決まりを 2 つ置く。

- **記録の置き場が分からないまとめの `close` は、課題を閉じない。** リリースの経路が雛形(`release.form`)でも昇格(promote)でも
なく、届ける経路を 1 つでも含むとき、まとめのプランは `sprint-close.py --record-pr unknown` を打つ(`new close --record-pr <番号>`
で組んだときはその番号を打つ。#2089)。`sprint-close.py` は
配布の記録を読まず、どの課題も閉じず、ボードも書かずに、`--issues` の課題を理由つきの `kept_open` で返す(終了コード 0)
- **記録の置き場が分からない `close` は、課題を閉じない。** `sprint-close.py --record-pr unknown` は
配布の記録を読まず、どの課題も閉じず、ボードも書かずに、`--issues` の課題を理由つきの `kept_open` で返す(終了コード 0)。
#2230 から、まとめのプランは `unknown` を組まない。リリースの経路が雛形(`release.form`)でも昇格(promote)でもなく、届ける経路を
1 つでも含むとき(と開発ループのまとめ)は `--record-pr {queue_record}` を組み、まとめを流し始める時点に queue が記録の PR を探して埋める
([ndf-production-release-record.md](ndf-production-release-record.md) の「まとめのプランの記録の PR と `release-verify`」)。
`unknown` を渡すのは手で打つ入口と、#2230 より前に組んだまとめのプランだけである
- **「手動確認は無い」と書いた行は、手動確認の行として数えない。** 要求の「検証手段」の表で 2 列目が「無し」の形の行は、
PR 本文の `## 手動確認` の節に載らず、merge-gate も承認ゲート(終了コード 10)で止まらない

Expand Down Expand Up @@ -51,7 +53,7 @@
| # | 条件 | 破れたときの扱い |
| --- | --- | --- |
| I1 | まとめのプランの記録の参照が `0`(`RECORD_NONE`)になるのは、リリースの経路がすべて届けない経路(`STAGE_NONE`)のときだけである | テストが落とす |
| I2 | 記録の参照が `{queue_pr:…}` でない(`has_record` が偽)とき、プランに `release-verify` を置かず、merge の次は `retro`(その次が `close`。#2228)になる | テストが落とす |
| I2 | 記録の参照が `0` のとき(`has_record` が偽。#2230 からは `0` のときだけ偽)、プランに `release-verify` を置かず、merge の次は `retro`(その次が `close`。#2228)になる | テストが落とす |
| I3 | `--record-pr unknown` の実行は、どの課題も閉じず、ボードも書かず、課題の本文も読まない(gh へ書き込まない) | テストが落とす |
| I4 | `--record-pr 0` の意味(記録を読まず、閉じる条件 1・2 を見ずに `--issues` を閉じる(条件 3 の振り返りの記録は見る)。`--issues` が無ければ終了コード 2)は変わらない | 既存のテストが落とす |
| I5 | 要求の 2 列目が「無し」の形の行は `ManualRow` にならない。それ以外の空でない 2 列目は手動確認の行になる | テストが落とす |
Expand All @@ -66,10 +68,11 @@
| --- | --- |
| 雛形の経路がある | `{queue_pr:release-prod}` |
| 昇格の経路があり、開発版のチャネルが手動反映の本番系(`delivery.MANUAL_PRODUCTION`)でない | `{queue_pr:promote}` |
| 経路がすべて `STAGE_NONE`(`delivery` が `[]` を含む) | `0`(`RECORD_NONE`) |
| それ以外(merge・手で届ける・検証の環境だけ・手動反映の本番系の昇格) | `unknown`(`RECORD_UNKNOWN`) |
| それ以外(merge・手で届ける・検証の環境だけ・手動反映の本番系の昇格) | `{queue_record}`(`RECORD_FOUND`。#2230) |

語 `0` と `unknown` と `has_record` は `supervise_lib/sprint_routes.py` に置き、`close_plan` はそれを呼ぶだけにする。
#2230 から、最初に経路がすべて `STAGE_NONE`(`delivery` が `[]` を含む)かを見て `0`(`RECORD_NONE`)を返し、次に開発ループのまとめ
(`--pace auto`)なら `{queue_record}` を返し、その後に上の表を上から見る。`unknown`(`RECORD_UNKNOWN`)は `sprint_routes.py` から消えた。
語 `0` と `{queue_record}` と `has_record` は `supervise_lib/sprint_routes.py` に置き、`close_plan` はそれを呼ぶだけにする。

#### `sprint-close.py --record-pr`

Expand Down Expand Up @@ -105,17 +108,19 @@

```mermaid
flowchart TD
A["record_pr_ref"] --> B{"雛形の経路がある"}
A["record_pr_ref"] --> D{"経路がすべて STAGE_NONE"}
D -- はい --> Z["0"]
D -- いいえ --> L{"開発ループのまとめ(--pace auto)"}
L -- はい --> U["{queue_record}"]
L -- いいえ --> B{"雛形の経路がある"}
B -- はい --> T["{queue_pr:release-prod}"]
B -- いいえ --> C{"昇格の経路があり、手動反映の本番系でない"}
C -- はい --> P["{queue_pr:promote}"]
C -- いいえ --> D{"経路がすべて STAGE_NONE"}
D -- はい --> Z["0"]
D -- いいえ --> U["unknown"]
C -- いいえ --> U
T --> V["merge → release-verify → retro → close"]
P --> V
U --> V
Z --> W["merge → retro → close(release-verify なし)"]
U --> W
```

`sprint-close.py` の中では、`cmd_close` が `--issues` の有無を確かめ、`_read_sprint_record` が `0` と `unknown` で記録を読まずに
Expand All @@ -130,7 +135,7 @@ PR の一覧を空で返す。`_closing_blocker` は `unknown` のとき全課
| 決定 | 理由 | 採らなかった案 |
| --- | --- | --- |
| `--record-pr` に語 `unknown` を足し、`0` の意味は変えない | 語ならプランの `cmd` と結果を読む人がそのまま意味を取れる。`0` を手で打つ既存の手順の意味が黙って変わらない | 負の数(`-1`)で表す。`0` を「置き場を知らない」に変え、配布なしに別の値を足す |
| 検証の環境だけ(本番の行の無い)経路・手動反映の本番系の昇格も `unknown` にする | 開いたまま残った課題は人が 1 回の操作で閉じられるが、条件を見ずに閉じた課題は確かめていないことが結果から読めない | 検証の環境だけの経路を配布なしとして `0` で閉じる |
| 検証の環境だけ(本番の行の無い)経路・手動反映の本番系の昇格も `unknown` にする(#2230 で `{queue_record}` に置き換わった。閉じる条件を見ずに閉じない方針は変わらない) | 開いたまま残った課題は人が 1 回の操作で閉じられるが、条件を見ずに閉じた課題は確かめていないことが結果から読めない | 検証の環境だけの経路を配布なしとして `0` で閉じる |
| 「無し」の判定を `rows_of` の 1 か所に置き、語の直後を括弧・句読点・空白・文末に限る | PR 本文の節も merge-gate の数え方も `rows_of` の出力から作られる。後続を限れば「無しの場合は〜」のような確認の文を落とさない | merge-gate で「無し」の行を数えない(PR 本文に未チェックの行が残り続ける)。要求の雛形の文を変える(雛形に「無ければ行を消す」が既にある) |

## データ・設定
Expand All @@ -157,7 +162,7 @@ PR の一覧を空で返す。`_closing_blocker` は `unknown` のとき全課

| 観点 | テスト |
| --- | --- |
| merge・手で届ける・検証の環境だけの経路で、`close` の `cmd` が `--record-pr unknown` になり `release-verify` が無いこと(I1・I2) | `test_supervise_pace_verify.py` の `test_close_without_a_known_record_keeps_the_issues_open` |
| merge・手で届ける・検証の環境だけの経路で、`close` の `cmd` が `--record-pr {queue_record}` になり `unknown` を持たず、`release-verify` が同じ参照を持つこと(I1・I2。#2230) | `test_supervise_pace_verify.py` の `test_close_without_a_plan_record_resolves_it_when_run` |
| `delivery: []` で `--record-pr 0` のまま変わらないこと(I1) | 同じファイルの `test_close_of_no_delivery_keeps_record_pr_zero` |
| `--record-pr unknown --issues …` で全課題が `kept_open`・理由つき・終了コード 0、gh の書き込みが 0 回で、`summary` が先頭の文を持つこと(I3) | `test_sprint_close_issues.py` の `test_record_unknown_keeps_the_given_issues_open_with_a_reason` |
| `unknown` に `--issues` が無ければ終了コード 2、それ以外の値・負の数は終了コード 3 | 同じファイルの `test_record_unknown_alone_returns_two`・`test_record_pr_rejects_other_values` |
Expand All @@ -170,15 +175,13 @@ PR の一覧を空で返す。`_closing_blocker` は `unknown` のとき全課

| 項目 | 内容 |
| --- | --- |
| 記録の PR を `close` へ渡す手段が無い | merge・手で届ける・検証の環境だけの経路の課題は、`unknown` で開いたまま残り、人が手で閉じる。受け渡しの手段は課題 #2044 が扱う |
| 手動反映の本番系の昇格はテストで縛っていない | 見本のリポジトリ(`make_repo`)は起点 develop・本番 main で、起点と本番が同じ形を組めない。`record_pr_ref` の分岐(`manual_prod`)は昇格を飛ばして `unknown` へ落ちる形で入っている |
| 語 `unknown` が 2 か所にある | `sprint-close.py` は `supervise_lib` を import しない独立のスクリプトで、`RECORD_UNKNOWN` を `sprint_routes.py` と別に持つ(コメントで指し合う) |
| 手動反映の本番系の昇格はテストで縛っていない | 見本のリポジトリ(`make_repo`)は起点 develop・本番 main で、起点と本番が同じ形を組めない。`record_pr_ref` の分岐(`manual_prod`)は昇格を飛ばして `{queue_record}` へ落ちる形で入っている |
| 既に閉じた課題も `kept_open` で載る | `unknown` は課題の状態を読まずに返すため、closing keywords で GitHub が先に閉じた課題も `kept_open` に並ぶ |
| 流し直さない PR 本文 | 既に作られた PR 本文の「無し」の未チェック行は、pr ステップを流し直さない限り残る |

## 関連リンク

- 課題: #1875(記録の置き場が分からない close)・#1675(「無し」の手動確認の行)。実装は PR #2051
- 課題: #1875(記録の置き場が分からない close)・#1675(「無し」の手動確認の行)。実装は PR #2051。まとめのプランが `unknown` の代わりに `{queue_record}` を組む変更は #2230
- [ndf-production-release-record.md](ndf-production-release-record.md): 経路ごとの記録の PR と `release-verify`
- [ndf-sprint-close-acceptance-criteria.md](ndf-sprint-close-acceptance-criteria.md): 閉じる条件 2 と受け入れ条件の印(`unknown` で本文を読まない条件 I8)
- [ndf-sprint-close-referenced-issues.md](ndf-sprint-close-referenced-issues.md): 参照だけの課題(`unknown` ではスプリントの PR を読まない)
Expand Down
8 changes: 4 additions & 4 deletions docs/specifications/ndf-workflow-development-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ MVV のレッドラインで人へ戻すという要求がそれを決める。
| --- | --- | --- |
| `--pace auto` | まとめのステージだけを組む(上の表) | 今の形(`fast` のスプリントの終わり)。出力は変わらない |
| `--carry N...` | 棚卸しのステップの指示へ前の周回の持ち越しを `--add` で渡す | 指示は今のまま |
| `--record-pr N` | 課題を閉じるステップ(`sprint-close.py --record-pr`)へ本番の記録の Pull Request を渡す | 配布の経路から導く印(`{queue_pr:release-prod}` など)を残し、queue が前のステージの本番のプランの Pull Request で埋める |
| `--record-pr N` | 課題を閉じるステップ(`sprint-close.py --record-pr`)へ本番の記録の Pull Request を渡す | 経路がすべて届けない経路なら `0`、それ以外は経路にかかわらず `{queue_record}` を残し、queue がまとめを流し始める時点に GitHub の参照からリリース記録の PR を探して埋める(#2230) |

周回の中では `--record-pr` を渡さない。渡すのは承認ゲート 2 の承認の後にまとめを組み直すとき(`stop.values.pr`)だけである。
ループは `--record-pr` を渡さない。承認ゲート 2 の承認の後にまとめを組み直すときも渡さない(`stop.values.pr` は検査のスプリント PR で、記録の PR ではない。#2230)。

### 承認ゲートで止まったとき(`gate`、`lap --done`)

Expand Down Expand Up @@ -240,7 +240,7 @@ MVV のレッドラインで人へ戻すという要求がそれを決める。
失敗の鍵は、スプリント状態の計画の行のうち結果が `まだ`・`流さなかった`・`完了`・`関門` でない最初の行の
`{issues, kind, step}` である。理由の文は含めない。`loop lap --failed` で締めて該当の行が無ければ
`{issues: 選んだ課題, kind: 周回, step: conductor}` にする。周回は、`--failed`・done に完了でも関門でも流さなかったでもない
結果がある・失敗の鍵がある、のどれかで `失敗`、ほかは `完了` で締まる。
結果がある・done に差し込みを埋められずに流さなかった計画(`unfilled`。記録の PR が見つからないまとめなど。#2230)がある・失敗の鍵がある、のどれかで `失敗`、ほかは `完了` で締まる。

`loop start` の再開は止まった理由ごとに次のとおりである。

Expand All @@ -249,7 +249,7 @@ MVV のレッドラインで人へ戻すという要求がそれを決める。
| `user_stop` | ファイルを消して解ける |
| 予算 | 再開の引数で上書きした予算で判定し直す。まだ予算以上なら 3 |
| `same_failure` | 再開の起動そのものを解けた印とし、失敗の数を数え直す |
| `gate2_returned` | 答えが無ければ 3。差し戻しなら周回を `人へ戻した` で締める。承認なら `next` に、止まった計画を経路に合うステップ(雛形の本番は `--from bump`、昇格は `--from promote-approved`、マージで止まった計画は `--from merge-approved`)から `supervise.py run` で続け → 同じ queue の残りのステージ → `--record-pr <stop.values.pr>` で組み直したまとめ → `wait` → `loop lap` の 1 行を載せる。続けるステップが無い計画は、手で行う本番を先に示す |
| `gate2_returned` | 答えが無ければ 3。差し戻しなら周回を `人へ戻した` で締める。承認なら `next` に、止まった計画を経路に合うステップ(雛形の本番は `--from bump`、昇格は `--from promote-approved`、マージで止まった計画は `--from merge-approved`)から `supervise.py run` で続け → 同じ queue の残りのステージ → `--record-pr` なしで組み直したまとめ(`{queue_record}` を持つ)→ `wait` → `loop lap` の 1 行を載せる。続けるステップが無い計画は、手で行う本番を先に示す |
| `refused`(続きの queue) | 人の判断待ちへ移した課題を戻さず、残した課題で続きを組み直す。組めなければ 3 |
| `refused`(ほか) | `next` に同じ周回での `loop sprint` のやり直しを載せる(モードと版は conductor が決め直す) |
| `mvv_changed` | 解けない。新しい名前でループを始め直すよう示す(開始時の値を今の値へ置き換えない) |
Expand Down
8 changes: 7 additions & 1 deletion plugins/ndf/scripts/lib/dist_record.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""リリース記録(`## 配布の記録`)の形を 1 か所に持つ(#1273 の決定 3)。

形の正本は `skills/progress-tracking/SKILL.md` の「配布の記録」の表である。書く側(`release-steps.py record`)は
`format_record` で組み、読む側(`sprint-close.py`)は `parse_record` で読む。見出しと行の名前をほかのモジュールに写さない。
`format_record` で組み、読む側(`sprint-close.py`・`sprint_close_lib/record_find.py`)は `parse_record` で読む。見出しと行の名前をほかのモジュールに写さない。

使う側は `deps.require("md")` を先に呼ぶ。
"""
Expand Down Expand Up @@ -38,6 +38,12 @@ def format_record(prev: str | None, new: str, prs, *, stage_note: str, version_n
)


def released(stage) -> bool:
"""段階が本番か配布なしか(課題を閉じてよい段階。`sprint-close.py` と `sprint_close_lib/record_find.py` が使う)。"""
stage = stage or ""
return stage.startswith("本番") or stage.startswith("配布なし")


def _strip_note(text):
"""版の文字列から全角の括弧の注記を落とす。"""
return re.sub(r"\s*(.*$", "", text).strip()
Expand Down
Loading
Loading