接手 SOP 註記:plan mode 限制只能寫此
~/.claude/plans/cached-marinating-puzzle.md。 ExitPlanMode + user approve 後,Phase Z 第一步是把本 plan copy 到 CLAUDE.md 規範位置docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-bug-pqr.md。
Bug O 收尾 E2E 測試時 user 發現 3 個跟 Bug O scope 無關的 bug,全部集中在 docx import preview UI 的負責單位 / 參與人員 sections。Bug P/Q/R 是 H-N arc 第 11~13 個 follow-up,本期 P/Q/R 是 H-N arc「user-facing complete」前的最後幾步 — 完成後 docx import update mode 整段才算 v1 stable。
3 bug 摘要:
| Bug | 症狀 | Root Cause | 影響範圍 |
|---|---|---|---|
| P | 對 organization party 點「連結帳號」會跳 Error,且 button label / dialog 應該是「連結組織單位」非「連結帳號」 | (a) wording:PartiesSection.vue org row 跟 person row 用同個 i18n key party_link_button=「連結帳號」(b) Error:root cause 尚未抓到 console,Phase 0.2 必須先 reproduce |
FE only |
| Q | Person party 缺「角色」下拉 | PartiesSection.vue 自 commit 47e9489 起只有 read-only ROLE_LABEL,從來沒有過 dropdown。template-edit 端 ModuleFramePartiesPanel.vue:438-446 才有 Dropdown + menuStore.sspPartyRoleMenu(9 role keys) |
FE only |
| R | Confirm 匯入後回 template-edit 看 parties 還是舊資料 | BE 確實有寫(log + import_summary.parties_written=5 雙重 verify);useModuleFrameParties.js module-scope 永久 cache 直到 invalidate(2026-05-21 故意改);SspDocxImportPage.vue:649-691 confirm 完只 reset 自己 store + router.push,從沒 call invalidate() → user 回 template-edit page,ModuleFramePartiesPanel.onMounted → loadParties cache hit 拿到 stale data |
FE only |
已驗證可重用的既有資源(不要 reinvent):
menuStore.sspPartyRoleMenu (9 OSCAL role keys) + roleLabel(key) 函式 → Bug Q 重用useModuleFrameParties().invalidate(mfUid) → Bug R 重用useSspParties (推測類似 composable,apiBase='ssp' 時 ModuleFramePartiesPanel 也適用) → Bug R 第二 caseFE-only 修補 3 個 bug,不動 BE / jedi-* 套件,使 docx import preview UI 的 parties section 跟 template-edit page parties tab 完整對齊,user confirm 匯入後 template-edit page 立刻看到新資料。
Dropdown 對 value: null 有 bug(per memory),role 預設可不選但 sentinel 處理(本期 role 必選,無此問題)| 檔案 | 動作 | 為何 |
|---|---|---|
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue |
Modify | Bug P button label 分流;Bug Q 補 role Dropdown;hardcoded ROLE_LABEL 5 entry 改用 menuStore.sspPartyRoleMenu + roleLabel(key) |
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue |
Modify | Bug R: confirm 成功後 (line 660 附近) call useModuleFrameParties().invalidate(targetUid);若 update-ssp mode 也要 call SSP context invalidate(探 useSspParties 是否存在) |
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/PartyLinkDialog.vue |
可能 Modify(Bug P Error 修補要看 Phase 0.2 reproduce 結果) | 待 reproduce 看 console 才能 finalize 是否要動 |
compliance-manager-fe/src/config/locales/i18n/zh-tw/ssp-docx-import.json |
Modify | 新增 party_link_button_org, party_link_button_user, party_relink_button_org, party_relink_button_user 4 個 wording 分流 key(若決定不分而是動態組 label 則 skip) |
compliance-manager-fe/src/config/locales/i18n/en/ssp-docx-import.json |
Modify | 同 zh-tw |
compliance-manager-be/docs/features/FR-028-2605-ssp-oscal-alignment/design.md |
Modify | Phase Z 收尾:加 §11.35 / §11.36 / §11.37 段;index 加 3 條 |
compliance-manager-be/docs/changelog/2026-05-25-fix-bug-pqr-parties-form.md |
Create | Phase Z 收尾 changelog(type=fix,FE only) |
compliance-manager-be/docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-pqr-FIXED-SUMMARY.md |
Create | Phase Z 收尾 SUMMARY |
原 handoff 2026-05-25-bug-p-q-r-parties-form-handoff.md |
Modify | Phase Z 收尾加 ✓ FIXED block on top |
不會動的檔案(明確排除):
目的:Bug P 的「跳 Error」尚未抓到 console error 內容,無法寫精準 fix 程式碼。本 phase 用 playwright MCP reproduce + 抓 console / network。
useSspParties composable 是否存在Checkpoint:Phase 0 完,Bug P 真實 root cause 應確認;若 Bug P 升級為 BE bug 或超出 FE scope,回頭跟 user 確認是否拆分本 plan。
SspDocxImportPage.vue import + call invalidateFiles:
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue:649-691(confirm fn)+ 上方 import 區import { useModuleFrameParties } from '@/composables/useModuleFrameParties'
// 若 Phase 0.3 確認 useSspParties 存在則一併 import:
// import { useSspParties } from '@/composables/useSspParties'const res = await SspDocxImportService.confirm(parseUid.value, payload)
const data = res?.data?.data ?? res?.data ?? res ?? {}
draftRef.clear(parseUid.value)
// Bug R fix (2026-05-25): confirm 寫完 parties → invalidate template-edit
// 端 ModuleFramePartiesPanel 用的永久 cache,否則 router.push 回 template-edit
// 後 loadParties cache hit 拿到 stale data。詳見 design.md §11.37。
const { invalidate: invalidateMfParties } = useModuleFrameParties()
if (isCreate.value || props.mode === 'update-mf') {
const targetMfUid = effectiveTargetUid || data.module_frame_uid || data.source_uid || props.targetUid
if (targetMfUid) invalidateMfParties(targetMfUid)
}
// 若 Phase 0.3 useSspParties 存在:
// if (props.mode === 'update-ssp') {
// const { invalidate: invalidateSspParties } = useSspParties()
// invalidateSspParties(props.targetUid)
// }
// 既有邏輯 line 662 onwards
parseUid.value = null
parsedResult.value = null
// ...預期:confirm 完 router push 回 template-edit page,parties tab 立刻顯示新名稱不需 reload
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
git add src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue
git commit -m "fix(ssp-oscal-alignment): Bug R — confirm 後 invalidate ModuleFrame parties cache
BE 寫入 parties OK 但 useModuleFrameParties 是 module-scope 永久 cache
(2026-05-21 故意改),SspDocxImportPage.confirm 完 router.push 回
template-edit 後 ModuleFramePartiesPanel.onMounted → loadParties cache
hit 拿到 stale data。fix:confirm 成功後 explicit call invalidate(mfUid)。
詳見 design.md §11.37。"PartiesSection.vue 補 role Dropdown + 對齊 menuStore masterFiles:
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue 整個 script + templateimport { storeToRefs } from 'pinia'
import { useMenuStore } from '@/stores/menuStore'
import Dropdown from 'primevue/dropdown'
import { onMounted, computed } from 'vue'
const menuStore = useMenuStore()
const { sspPartyRoleMenu } = storeToRefs(menuStore)
// 沿用 ModuleFramePartiesPanel.vue:101-105 同樣 pattern
function roleLabel(key) {
if (!key) return '—'
const i18nKey = `lang.oscal_role.ssp_party_role.${key}.label`
const v = t(i18nKey)
return v === i18nKey ? key : v
}
const roleOptions = computed(() =>
sspPartyRoleMenu.value.map((m) => ({
label: roleLabel(m.key),
value: m.key,
})),
)
onMounted(() => {
menuStore.fetchSspPartyRoleMenu() // 已有 cache + 並發合併,多 mount 共用同份
})對 org row(line 130-134 區段):
<div class="flex align-items-center gap-2">
<!-- 顯示用 label(保留現值時 read-only)-->
<span v-if="isPartyReadonly(p.party_uid)" class="font-semibold">
{{ roleLabel(p.role) }}
</span>
<!-- 編輯模式:Dropdown -->
<Dropdown
v-else
:model-value="p.role"
:options="roleOptions"
option-label="label"
option-value="value"
placeholder="(選擇角色)"
class="ssp-party-role-dropdown"
@update:model-value="(v) => onFieldEdit(idx, 'role', v)"
/>
<Tag :severity="statusSeverity(p)" :value="statusLabel(p)" />
<Tag v-if="isPartyReadonly(p.party_uid)" severity="secondary" value="保留現值" />
</div>
對 person row(line 194-198 區段)做同樣改動。
.ssp-party-role-dropdown {
min-width: 160px;
}
.ssp-party-role-dropdown :deep(.p-dropdown-label) {
font-weight: 600;
}預期:
git add src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue
git commit -m "fix(ssp-oscal-alignment): Bug Q — PartiesSection 補 role Dropdown
docx import preview 端 PartiesSection 自 commit 47e9489 就只有 read-only
ROLE_LABEL,從來沒有過 Dropdown。template-edit 端 ModuleFramePartiesPanel
早就有完整 Dropdown + menuStore.sspPartyRoleMenu (9 role keys)。
fix:preview 端也補上 Dropdown,重用同個 menuStore master 避免雙處
enum 走樣 (per Bug O 教訓「FE store 三處同步」)。read-only 模式
(保留現值 / keep_current)仍顯示 read-only label。
詳見 design.md §11.36。"Files:
compliance-manager-fe/src/config/locales/i18n/zh-tw/ssp-docx-import.jsoncompliance-manager-fe/src/config/locales/i18n/en/ssp-docx-import.json"party_link_button_user": "連結帳號",
"party_link_button_org": "連結組織單位",
"party_relink_button_user": "重新連結帳號",
"party_relink_button_org": "重新連結組織單位"保留既有 party_link_button / party_relink_button 不刪(其他元件可能 reference;本期 PartiesSection 改 ref 新 key)。
Files:
compliance-manager-fe/src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue org row line 145-151 + person row line 209-215<Button
size="small"
outlined
:label="isLinked(p)
? t('lang.ssp_docx_import.party_relink_button_org')
: t('lang.ssp_docx_import.party_link_button_org')"
icon="pi pi-building"
@click="openLinkDialog(p, idx)"
/>
<Button
size="small"
outlined
:label="isLinked(p)
? t('lang.ssp_docx_import.party_relink_button_user')
: t('lang.ssp_docx_import.party_link_button_user')"
icon="pi pi-user"
@click="openLinkDialog(p, idx)"
/>
預期:
待 Phase 0.2 抓到 console / network log 後再 finalize。可能的修補方向:
onSelect(item) 在 org 情境 item.id undefined → 加 guard if (!item?.id) { toast.warn('選項缺 id'); return }git add src/config/locales/i18n/zh-tw/ssp-docx-import.json \
src/config/locales/i18n/en/ssp-docx-import.json \
src/components/grc/ssp-docx-import-v2/sections/PartiesSection.vue \
# 若 Phase C.3 有改 PartyLinkDialog 一併 add
git commit -m "fix(ssp-oscal-alignment): Bug P — PartiesSection link button 對 party_type 分流 wording
PartiesSection 對 organization 跟 person 共用同個 'party_link_button'
i18n key (=「連結帳號」),wording 對 org 不對。dialog title 已有
party_link_dialog_title_org / _user 分流,button label 跟著對齊。
新增 4 個 i18n key (party_link_button_user/_org/relink_*),
保留舊 key 不刪(其他元件可能 reference)。icon 也分(建築 / 人形)。
(若 Phase C.3 有 Error 修補,commit message 加第二段說明)
詳見 design.md §11.35。"cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
poetry run pytest tests/test_ssp_docx_import_app_service.py \
tests/test_ssp_docx_diff_service.py \
tests/test_ssp_write_strategy.py -q預期:~210+ passed(跟 Pre-flight 一致)
按 CLAUDE.md「做 summary」段 step 5 必跑「回頭更新所有相關文件」。
Files:
compliance-manager-be/docs/features/FR-028-2605-ssp-oscal-alignment/design.mdFiles:
compliance-manager-be/docs/changelog/2026-05-25-fix-bug-pqr-parties-form.mdfrontmatter:
---
type: fix
modules: [ssp-oscal-alignment, frontend-only]
issue: docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-p-q-r-parties-form-handoff.md
---內容:3 bug 各一段(症狀 / fix / commit hash 待 commit 後回填)
Files:
compliance-manager-be/docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-pqr-FIXED-SUMMARY.md對齊 2026-05-25-bug-o-FIXED-SUMMARY.md 樣式:
Files:
compliance-manager-be/docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-p-q-r-parties-form-handoff.md在標題後加 block:
> ✓ FIXED — 2026-05-25 收尾,見
> [`2026-05-25-bug-pqr-FIXED-SUMMARY.md`](./2026-05-25-bug-pqr-FIXED-SUMMARY.md)feedback_permanent_cache_needs_invalidate_at_all_writers.md:永久 cache 設計必須伴隨「每個寫入 path 都 invalidate」SOP,本期 confirm path 漏掉feedback_button_label_align_dialog_title_per_type.md:dialog title 已對 type 分流,但 button label 沒跟著分是常見漏網點cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
git add docs/features/FR-028-2605-ssp-oscal-alignment/design.md \
docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-bug-pqr.md \
docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-pqr-FIXED-SUMMARY.md \
docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-p-q-r-parties-form-handoff.md \
docs/changelog/2026-05-25-fix-bug-pqr-parties-form.md
git commit -m "docs(ssp-oscal-alignment): Bug P/Q/R 收尾 — plan + design §11.35-37 + changelog + FIXED SUMMARY"cd ~/Projects/Billows/Audit-Manager/compliance-manager-be
python3 scripts/extract_claude_sessions.py --date 2026-05-25 --topic bug-pqr-parties-form --auto
wc -l docs/conversation-history/2026-05-25/bug-pqr-parties-form/*.md
git add docs/conversation-history/2026-05-25/bug-pqr-parties-form/
git commit -m "docs(conversation-history): 2026-05-25 — bug-pqr-parties-form session dump"不自動 push。報告 push 規模(FE N commits + BE M commits)給 user 拍板。
| Check | 命令 / 動作 | 預期 |
|---|---|---|
| Bug P wording | playwright Step 3 預覽 → 看 org row button label | 顯示「連結組織單位」 |
| Bug P Error | 點 org row 「連結組織單位」 | dialog 開「連結到組織單位」標題,無 console error |
| Bug Q dropdown | playwright Step 3 預覽 → person/org row 看 role 欄 | 顯示 Dropdown(非保留現值時),9 個 role 全列 |
| Bug R cache | playwright 改 party name → confirm → router 回 template-edit | parties tab 不需 reload 立刻顯示新 name |
| BE 不退化 | poetry run pytest tests/test_ssp_docx_import_app_service.py tests/test_ssp_docx_diff_service.py tests/test_ssp_write_strategy.py -q |
210+ passed |
| BE log 健全 | tail -100 log/app.log | grep ERROR |
無新 ERROR |
feature/ssp-oscal-alignmentgit add 顯式檔名(per memory feedback_subagent_explicit_git_add.md)— 每個 commit 都列檔useSspParties 不存在,標 follow-up)| Phase | 時間 |
|---|---|
| Phase 0 (Reproduce + verify) | 30 分 |
| Phase A (Bug R) | 30 分 |
| Phase B (Bug Q) | 60 分 |
| Phase C (Bug P) | 60-90 分(依 C.3 結果) |
| Phase D (E2E verify) | 30 分 |
| Phase Z (收尾) | 60 分 |
| 總計 | 3.5-5 小時 |