From e53440a9007387acc6317e53e27f70336bab61e4 Mon Sep 17 00:00:00 2001 From: Lien Chen Date: Wed, 26 Aug 2026 23:46:10 +0900 Subject: [PATCH 1/2] fix(ship): give the permanent-test admission record a PR body template slot Second reading of CC-554's admission-recording rule (effective since pr:#530): across a 12-PR evidence window, both qualifying instances found (pr:#539's 7 new regression cases, pr:#541's 2 new test functions) added a permanent test as a gate-finding remedy but recorded zero admission-criteria citations in the PR body. The rule text lives in Step 2.5, several screens before the PR body actually gets composed in Step 4 -- a free-floating prose reminder read once during remediation is not reliably recalled by the time the PR body template gets filled in. Add an explicit `Permanent test admissions:` field to that template so its omission is conspicuous (fill it in, or write `none`) instead of silent, and add a regression assertion that the template carries the field. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0177ds9nxEMtsh3bwpBxNHYx --- BACKLOG.md | 23 +++++++++++++++++++++++ commands/ship.md | 8 ++++++++ tests/shell/test-commands.sh | 1 + 3 files changed, 32 insertions(+) diff --git a/BACKLOG.md b/BACKLOG.md index ba84a717..197f1ac8 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -441,6 +441,29 @@ alternative 數」三欄,缺記錄本身即為協定失敗而非歧義。參 reviewer-side duty 已要求提出者載明符合哪些條件,author side 先前沒有對稱義務, 該對稱化屬該 repo 的獨立變更,不在本票 scope。 +**Update 2026-08-26(第二次讀數;票維持 active)**:對稱記錄規則自 pr:#530 +(2026-08-25 生效)起的證據窗已累積 12 個 merged PR,遠超「觀察 2-3 個」的門檻。 +逐一比對後找到 2 個合格實例——都是同一位執行者(本 agent)自己交付的 PR:pr:#539 +因 gate finding 新增 7 個永久 regression case、pr:#541 因 gate finding 新增 2 個 +永久測試函式,兩張 PR body **皆完全沒有**依規則寫「符合哪些准入條件」這一行。 + +讀數:合格實例 2 個,admit 數(附准入條件記錄)= 0,alternative 數 = 0,**缺記錄 +數 = 2**。 + +**判定**:這次不是「B 恆為 0 的三種情形分不清楚」(上次讀數已排除這個病灶),而是 +第三種、更根本的情形——**規則存在且無歧義,但執行者在動筆寫 PR body 的當下沒有 +意識到要查它**。純文字提醒(寫在 Step 2.5,PR body 是在後面的 Step 4 才組裝)在 +兩次連續合格實例上都沒有被觸發,證明「靠執行者記得回頭查一段前面讀過的規則」這個 +機制本身不可靠,不是這次剛好疏忽。 + +**處置**:把 Step 4 的 PR body 樣板本身加一個 `Permanent test admissions:` 欄位 +(原樣板只有 `Refactor/reuse audit`/`Final verdict`/`Full suite` 等既有欄位, +從缺永久測試這一項)。樣板本身是執行者組裝 PR body 時實際會複製的文字,欄位缺席 +會讓遺漏顯性化(要嘛填實際記錄、要嘛明寫 `none`),不必再依賴幾個段落之前那句 +散文提醒。新增對應回歸測試斷言樣板含這個欄位。A/B 讀數已可信(上次讀數已解決), +故本票仍不結案的理由改變:現在是要觀察「樣板改結構之後,缺記錄事件是否消失」, +而非「A/B 本身能否讀出訊號」。下次讀數起看第四欄——**樣板生效後的缺記錄次數**。 + **Non-goals**: 不設 `max_full_review_rounds` 輪數上限——與 `commands/ship.md` 「round count 不是停止條件」直接衝突,且 [[CC-544]] 已證明放寬 gate 收斂條件會被 qa-tester/risk-reviewer 連擋並全數 revert。減量要從 finding 端做,不是從輪數端。 diff --git a/commands/ship.md b/commands/ship.md index 292600a4..ce3d24fb 100644 --- a/commands/ship.md +++ b/commands/ship.md @@ -315,6 +315,7 @@ gh pr create --title "(): " --body "$(cat <<'EOF - Rounds: - Final verdict: GO - Result file: +- Permanent test admissions: - Full suite: Ticket: @@ -322,6 +323,13 @@ EOF )" ``` +**The "Permanent test admissions" line is not optional filler** — Step 2.5 +required this record at the point each finding was remediated, and this +template field exists so composing the PR body forces a check for it: a +gate round that added no new permanent test gets `none`; a round that added +one gets the citation carried over from Step 2.5, not re-derived or skipped +because the paragraph that required it is several screens back by now. + Do not merge. GO is not merge authorization — merge only when the user explicitly says so. diff --git a/tests/shell/test-commands.sh b/tests/shell/test-commands.sh index a47509e1..ce565e9a 100755 --- a/tests/shell/test-commands.sh +++ b/tests/shell/test-commands.sh @@ -657,6 +657,7 @@ should_run "ship: any other NO-GO continues without asking" && assert_file_conta # PR template should_run "ship: opens PR via gh pr create" && assert_file_contains "ship: opens PR via gh pr create" "$SHIP" "gh pr create" && pass "ship: opens PR via gh pr create" should_run "ship: PR body template records gate rounds and verdict" && assert_file_contains "ship: PR body template records gate rounds and verdict" "$SHIP" "Final verdict" && pass "ship: PR body template records gate rounds and verdict" +should_run "ship: PR body template has a slot for permanent test admission decisions" && assert_file_contains "ship: PR body template has a slot for permanent test admission decisions" "$SHIP" "Permanent test admissions:" && pass "ship: PR body template has a slot for permanent test admission decisions" should_run "ship: GO is not merge authorization" && assert_file_contains "ship: GO is not merge authorization" "$SHIP" "GO is not merge authorization" && pass "ship: GO is not merge authorization" should_run "ship: no CC ticket references" && assert_not_contains "ship: no CC ticket references" "$SHIP" "CC-[0-9]" # git publication path: branch creation and push are the only side effects before PR creation From 34698d24e89146424ee3d8c3039daec006178c62 Mon Sep 17 00:00:00 2001 From: Lien Chen Date: Wed, 26 Aug 2026 23:56:44 +0900 Subject: [PATCH 2/2] fixup: clarify none is not a substitute for an alternative-path record Two gate reviewers (critic, architecture-reviewer) independently flagged that the template's `| none` fallback read as usable whenever no new permanent test was added -- including a round whose finding was resolved via a recorded alternative, which Step 2.5 still requires a line for. Reworded so `none` applies only when no finding this round was assessed against Step 2.5 at all, and added regression assertions for both the alternative-path requirement and the none-is-not-a-substitute wording. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0177ds9nxEMtsh3bwpBxNHYx --- commands/ship.md | 11 +++++++---- tests/shell/test-commands.sh | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/commands/ship.md b/commands/ship.md index ce3d24fb..e32c3006 100644 --- a/commands/ship.md +++ b/commands/ship.md @@ -315,7 +315,7 @@ gh pr create --title "(): " --body "$(cat <<'EOF - Rounds: - Final verdict: GO - Result file: -- Permanent test admissions: +- Permanent test admissions: - Full suite: Ticket: @@ -326,9 +326,12 @@ EOF **The "Permanent test admissions" line is not optional filler** — Step 2.5 required this record at the point each finding was remediated, and this template field exists so composing the PR body forces a check for it: a -gate round that added no new permanent test gets `none`; a round that added -one gets the citation carried over from Step 2.5, not re-derived or skipped -because the paragraph that required it is several screens back by now. +gate round with no finding whose remedy could have been a new permanent +test gets `none`; every other round gets one line per such finding, whether +it was admitted or resolved by a recorded alternative — `none` never stands +in for an alternative-path finding's own record, and the citation is carried +over from Step 2.5, not re-derived or skipped because that paragraph is +several screens back by now. Do not merge. GO is not merge authorization — merge only when the user explicitly says so. diff --git a/tests/shell/test-commands.sh b/tests/shell/test-commands.sh index ce565e9a..3fd132c5 100755 --- a/tests/shell/test-commands.sh +++ b/tests/shell/test-commands.sh @@ -658,6 +658,8 @@ should_run "ship: any other NO-GO continues without asking" && assert_file_conta should_run "ship: opens PR via gh pr create" && assert_file_contains "ship: opens PR via gh pr create" "$SHIP" "gh pr create" && pass "ship: opens PR via gh pr create" should_run "ship: PR body template records gate rounds and verdict" && assert_file_contains "ship: PR body template records gate rounds and verdict" "$SHIP" "Final verdict" && pass "ship: PR body template records gate rounds and verdict" should_run "ship: PR body template has a slot for permanent test admission decisions" && assert_file_contains "ship: PR body template has a slot for permanent test admission decisions" "$SHIP" "Permanent test admissions:" && pass "ship: PR body template has a slot for permanent test admission decisions" +should_run "ship: admission template requires alternative-path lines too, not just none" && assert_file_contains "ship: admission template requires alternative-path lines too, not just none" "$SHIP" "alternative lines name the alternative taken and why" && assert_file_contains "ship: admission template requires alternative-path lines too, not just none" "$SHIP" "none\` ONLY when no finding this round needed the assessment at all" && pass "ship: admission template requires alternative-path lines too, not just none" +should_run "ship: admission template explanation forbids none standing in for an alternative" && assert_file_contains "ship: admission template explanation forbids none standing in for an alternative" "$SHIP" "\`none\` never stands" && assert_file_contains "ship: admission template explanation forbids none standing in for an alternative" "$SHIP" "in for an alternative-path finding's own record" && pass "ship: admission template explanation forbids none standing in for an alternative" should_run "ship: GO is not merge authorization" && assert_file_contains "ship: GO is not merge authorization" "$SHIP" "GO is not merge authorization" && pass "ship: GO is not merge authorization" should_run "ship: no CC ticket references" && assert_not_contains "ship: no CC ticket references" "$SHIP" "CC-[0-9]" # git publication path: branch creation and push are the only side effects before PR creation