From 744eee04ba466a2be4635b220e893db3bbaa6272 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 22 Sep 2026 15:06:08 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(sdlc-analyze):=20=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E4=BA=A4=E4=BB=98=E5=84=AA=E5=85=88=E7=A2=BA=E8=AA=8D=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 讓 sdlc-analyze 逐項確認七種交付文件與 PERT 三點估算,排序交付工作包並在確認前阻擋建立與排程;補上流程正本測試。 --- prompts/sdlc-analyze.md | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/prompts/sdlc-analyze.md b/prompts/sdlc-analyze.md index 09c9160..eba8b97 100644 --- a/prompts/sdlc-analyze.md +++ b/prompts/sdlc-analyze.md @@ -16,19 +16,40 @@ description: 僅由 /sdlc-analyze 指令叫用。對一顆需求議題執行可 3. `references/feasibility-data.md` 4. `references/feasibility-schedule.md` -能從程式碼查證的事項自行查證;只有需要使用者決策的事項才提問。架構、邏輯、資料、時程四類依序完成,每次只問一題,每題提供建議與手動輸入。最後輸出共識摘要、變更假設、未決事項與人天估算;摘要只印終端,不寫入 Gitea。 +能從程式碼查證的事項自行查證;只有需要使用者決策的事項才提問。架構、邏輯、資料、時程四類依序完成,每次只問一題,每題提供建議與理由,以及手動輸入的方式。最後輸出共識摘要、變更假設、未決事項與人天估算;摘要只印終端,不寫入 Gitea。 -使用者確認共識摘要後,**先列出要交付或驗收的項目,逐項向使用者確認**。使用者未確認或拒絕時,立即停止,不建立工作包、不排程、不寫入後續資料。 +### 交付文件判斷 + +使用者確認共識摘要後,讀取 `references/delivery-types.md`,列出這次需求需要交付或驗收的文件,並依序逐一詢問: + +1. **需求描述概要** +2. **WBS(工作分解結構)** +3. **流程圖** +4. **甘特圖** +5. **PERT 圖** +6. **關鍵路徑圖** +7. **API 契約文件** + +每一種文件都要先展示必要內容骨架,再給出是否需要的建議與理由,最後讓使用者確認、拒絕或手動調整;不得把七種文件合併成一次確認。確認結果要保留文件順序、必要內容、產出位置與 ELI5 變體規則。API 契約文件只能交付預覽或使用者確認的位置,禁止寫入目標專案 repo。 + +使用者未確認或拒絕任何一項時,立即停止,不建立工作包、不排程、不建立相依、不寫入 Milestone、看板或其他後續資料。 + +### PERT 三點估算 + +對每一個需要排程的工作包,分別逐題詢問樂觀時間(O)、最可能時間(M)、悲觀時間(P);每題都提供建議、理由與手動輸入方式。三個值都確認後才納入排程資料,不得用單一人天估算代替,也不得在確認前建立工作包或排程。 ## 第二段:產生工作包 -確認交付/驗收項目後,依共識切出可獨立完成的工作包,套用 `templates/work-package-issue.md`。每顆工作包的待辦與驗收都要可逐項勾選;對應已確認交付項目的待辦置於第一項。工作包整體也依交付優先排序,但不得違反先決關係。 +確認交付/驗收項目與所有必要的 PERT 三點估算後,依共識切出可獨立完成的工作包,套用 `templates/work-package-issue.md`。每顆工作包的待辦與驗收都要可逐項勾選;對應已確認交付項目的待辦置於第一項。 + +工作包排序先放已確認的交付文件工作包,再放純程式碼工作包;排序只在不違反先決關係時生效,若交付文件工作包依賴其他工作包,仍以拓撲順序為準。每顆工作包只做一種交付,並在描述中保留文件類型、必要內容、產出位置與驗收方式。 每顆工作包先以 `scripts/issue-create.js --dry-run` 檢查,再移除旗標實跑。只使用既有標籤。建立後回報編號、標題與網址。 +重跑同一需求時,先以既有議題與標題查重;已存在的工作包只沿用其編號與相依,不建立重複工作包。 ## 第三段:排程 -以 `startDate`、`days` 與 `depends` 組成計畫檔,執行 `scripts/schedule.js` 計算截止日;依序用 `issue-link.js`、`issue-update.js` 與 `project-add.js` 補上既有相依、Milestone、看板、截止日與人天估算。各腳本先 dry-run,再實跑。日期與人天是排程資料,不是耗時統計。 +所有工作包建立且相依關係確認後,以 `startDate`、`days` 與 `depends` 組成計畫檔,執行 `scripts/schedule.js` 計算截止日;依序用 `issue-link.js`、`issue-update.js` 與 `project-add.js` 補上既有相依、Milestone、看板、截止日與人天估算。各腳本先 dry-run,再實跑。日期與人天是排程資料,不是耗時統計。 ## 邊界 @@ -36,4 +57,5 @@ description: 僅由 /sdlc-analyze 指令叫用。對一顆需求議題執行可 - 不建立 Milestone 或專案看板。 - 不修改使用者專案檔案。 - 不關閉或刪除既有議題。 -- 共識摘要與交付確認前不建立任何工作包。 +- 不把 API 契約文件寫入目標專案 repo。 +- 共識摘要、交付文件確認與 PERT 三點估算完成前,不建立任何工作包、不排程、不寫入後續資料。 -- 2.53.0 From 76cdedc980d6ccd26d1dd0a9fe726e3934616ee2 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Tue, 22 Sep 2026 15:06:08 +0800 Subject: [PATCH 2/2] =?UTF-8?q?test(sdlc-analyze-assets):=20=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E4=BA=A4=E4=BB=98=E5=84=AA=E5=85=88=E7=A2=BA=E8=AA=8D?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 讓 sdlc-analyze 逐項確認七種交付文件與 PERT 三點估算,排序交付工作包並在確認前阻擋建立與排程;補上流程正本測試。 --- test/sdlc-analyze-assets.test.js | 99 ++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 test/sdlc-analyze-assets.test.js diff --git a/test/sdlc-analyze-assets.test.js b/test/sdlc-analyze-assets.test.js new file mode 100644 index 0000000..ff59c14 --- /dev/null +++ b/test/sdlc-analyze-assets.test.js @@ -0,0 +1,99 @@ +/** + * /sdlc-analyze 的流程正本。 + * + * 這些測試鎖定交付文件確認與排程前置條件;漏掉其中任一個閘門, + * agent 就可能在使用者尚未確認時建立工作包或排程。 + */ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { + assertNeutralPrompt, + assertPromptListsSections, + readPrompt, +} from './helpers/prompt-doc.js'; + +const prompt = readPrompt('sdlc-analyze'); +const delivery = prompt.slice(prompt.indexOf('### 交付文件判斷'), prompt.indexOf('## 第二段')); +const packages = prompt.slice(prompt.indexOf('## 第二段'), prompt.indexOf('## 第三段')); +const schedule = prompt.slice(prompt.indexOf('## 第三段'), prompt.indexOf('## 邊界')); +const boundary = prompt.slice(prompt.indexOf('## 邊界')); +const TYPES = [ + '需求描述概要', + 'WBS(工作分解結構)', + '流程圖', + '甘特圖', + 'PERT 圖', + '關鍵路徑圖', + 'API 契約文件', +]; + +// ── 交付文件確認 ──────────────────────────────────────────────── + +test('正本讀取七種交付文件規則,且依規則順序逐項確認', () => { + assert.match(delivery, /references\/delivery-types\.md/); + assertPromptListsSections(delivery, TYPES); + assert.match(delivery, /依序逐一詢問/); + assert.match(delivery, /不得把七種文件合併成一次確認/); +}); + +test('每種文件確認都保留必要內容、產出位置與 ELI5 規則', () => { + assert.match(delivery, /必要內容骨架/); + assert.match(delivery, /產出位置/); + assert.match(delivery, /ELI5 變體規則/); +}); + +test('交付文件未確認或遭拒時,所有後續副作用都被阻擋', () => { + assert.match(delivery, /未確認或拒絕任何一項時,立即停止/); + assert.match(delivery, /不建立工作包、不排程、不建立相依/); + assert.match(delivery, /不寫入 Milestone、看板或其他後續資料/); +}); + +// ── PERT 與工作包優先 ──────────────────────────────────────────── + +test('PERT 的 O、M、P 分別逐題確認,且不能用單一人天替代', () => { + const pert = prompt.slice(prompt.indexOf('### PERT 三點估算'), prompt.indexOf('## 第二段')); + assert.match(pert, /樂觀時間(O)/); + assert.match(pert, /最可能時間(M)/); + assert.match(pert, /悲觀時間(P)/); + assert.match(pert, /分別逐題詢問/); + assert.match(pert, /不得用單一人天估算代替/); + assert.match(pert, /三個值都確認後才納入排程資料/); +}); + +test('交付文件工作包優先,但以先決關係的拓撲順序為準', () => { + assert.match(packages, /先放已確認的交付文件工作包,再放純程式碼工作包/); + assert.match(packages, /不違反先決關係/); + assert.match(packages, /拓撲順序/); +}); + +test('每個工作包只承擔一種交付並保留驗收所需欄位', () => { + assert.match(packages, /每顆工作包只做一種交付/); + assert.match(packages, /文件類型、必要內容、產出位置與驗收方式/); + assert.match(packages, /對應已確認交付項目的待辦置於第一項/); +}); + +// ── 建立與排程邊界 ──────────────────────────────────────────────── +test('重跑需求會以既有議題與標題查重,不建立重複工作包', () => { + assert.match(packages, /重跑同一需求時,先以既有議題與標題查重/); + assert.match(packages, /不建立重複工作包/); +}); + +test('工作包建立與排程仍要求 dry-run,且排程在相依確認後', () => { + assert.match(packages, /issue-create\.js --dry-run/); + assert.match(schedule, /所有工作包建立且相依關係確認後/); + assert.match(schedule, /schedule\.js/); + assert.match(schedule, /各腳本先 dry-run,再實跑/); +}); + +test('共識、交付確認與 PERT 完成前不建立任何後續資料', () => { + assert.match(boundary, /共識摘要、交付文件確認與 PERT 三點估算完成前/); + assert.match(boundary, /不建立任何工作包、不排程、不寫入後續資料/); +}); + +test('API 契約不寫入目標專案,且流程維持終端摘要與平台中立', () => { + assert.match(delivery, /API 契約文件只能交付預覽或使用者確認的位置/); + assert.match(delivery, /禁止寫入目標專案 repo/); + assert.match(prompt, /摘要只印終端,不寫入 Gitea/); + assert.match(boundary, /不把 API 契約文件寫入目標專案 repo/); + assertNeutralPrompt(prompt, 'sdlc-analyze'); +}); -- 2.53.0