Bug S/T/U Implementation Plan — Components silent-fail + keep_current 砍鉤稽 link + FE 漏 v3 decisions

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

項目 內容
緣由 2026-05-26 user 用 mf b8065ad5 + 亞航-CMMC-SSP-20260520-1.docx 跑 template-edit docx import,三個問題:(S) components/leveraged 沒匯入 DB(DB 0 row 但 docx 解出 4+1);(T) 部分 STEP 2 選 keep_current 的 party 鉤稽(responsible_party link)被砍;(U) FE confirm payload 完全沒帶 4 個 v3 decision keys
Branch feature/ssp-oscal-alignment
Bug 編號 S = stale-link cleanup 砍 keep_current;T = v2-bundle silent fail;U = FE 漏 v3 decisions wire
預估時間 4-6 小時(含 Phase 0 verify + 3 個 fix + manual E2E)

Goal: 修 docx import → mf template-edit 流程的 3 個 bug,讓 user 在 STEP 2 選的 use_docx / keep_current 決策都正確生效,且 components / leveraged / inventory 真實寫入 DB。

Architecture: Phase 0 先 patch BE 加 debug log + 請 user 重啟 + 重做一次 import 才 pin Bug T 確切位置;Phase 1-3 順序 fix S/T/U;Phase 4 manual E2E;Phase 5 收尾(等 user 下令才 commit 收尾文件)。

Tech Stack: Python 3.11 / Flask / SQLAlchemy / dependency-injector / Vue 3 / Pinia


§1

Pre-flight Commands(必跑)

# 1. branch + working tree
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be branch --show-current
# 預期:feature/ssp-oscal-alignment
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe branch --show-current
# 預期:feature/ssp-oscal-alignment

git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be status --short | grep -E '\.py$|\.md$' | head -20
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe status --short

# 2. BE listener
lsof -t -i:8000 && echo "BE up" || echo "BE down — restart needed"

# 3. BE smoke tests
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 tests/test_module_frame_write_strategy_v2_parties.py -q
# 預期:全 pass

§2

Verify Hypotheses(plan 開工前必跑,per memory feedback_plan_vs_reality_verify_first

# A. 確認 mf 343 + SSP shell 219/228 + components/leveraged 0 row
PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -A -F$'\t' -c "
SET app.is_super_admin='t';
SELECT mf.id, mf.uid, mf.name FROM public.module_frames mf WHERE mf.uid='b8065ad5-e169-4df4-9bd3-5ec0d03b2e1d';
SELECT ssp.id, ssp.uid FROM oscal.system_security_plans ssp WHERE ssp.template_module_frame_id=343;
SELECT 'comp' k, count(*) FROM oscal.ssp_components WHERE ssp_id IN (219,228);
SELECT 'la' k, count(*) FROM oscal.ssp_leveraged_authorizations WHERE ssp_id IN (219,228);
SELECT 'rp_mf' k, count(*) FROM oscal.oscal_responsible_parties WHERE context_type='module_frame' AND context_id=343;
"
# 預期:mf=343, shell=219+228, comp=0, la=0, rp_mf=5

# B. 確認 parse_job 223 含 v2-bundle + components=4 + leveraged=1
PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -A -F$'\t' -c "
SET app.is_super_admin='t';
SELECT id, status, (parsed_result->>'schema_version') schema,
       jsonb_array_length(parsed_result->'components') comp_n,
       jsonb_array_length(parsed_result->'leveraged_authorizations') la_n
  FROM oscal.ssp_docx_parse_jobs WHERE id=223;
"
# 預期:comp_n=4, la_n=1, schema=v2-bundle

# C. 確認 ModuleFrameWriteStrategy.write_parties 仍有 L539-544 stale-link cleanup
grep -nA 6 'existing_link_map.items' ~/Projects/Billows/Audit-Manager/compliance-manager-be/domain/oscal/strategy/module_frame_write_strategy.py
# 預期:line 540-544 顯示 `if uuid not in processed_uuids: delete_by_id`

# D. 確認 FE SspDocxImportPage L736-744 payload 仍漏 4 個 v3 keys
grep -A 10 'const payload = {' ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue
# 預期:只看到 decisions / parties_decisions,沒看到 components_decisions / la_decisions / inventory_items_decisions / system_characteristic_decision

# E. 確認 sspDocxImportStore.buildConfirmPayload 已正確帶 4 個 v3 keys(之後 FE 改用它)
grep -nA 6 'buildConfirmPayload' ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/stores/sspDocxImportStore.js
# 預期:line ~214 包 components_decisions / leveraged_authorizations_decisions / inventory_items_decisions / system_characteristic_decision

任一條 verify 不符 → 停下回報 user,不開工。


§3

Phase 0: Pin Bug T silent-fail 確切位置(必跑)

Bug T silent-fail 在 confirm_service.confirm() 內某處,inline reproduction 失敗(DI deepcopy block),改 patch BE 加 5 行 debug log 後重啟 → 請 user 重做一次 import → 看 log。

Task 0.1: Patch _run_v2_bundle_confirm 加 debug log

Files:

  • Modify: app/oscal/service/ssp_docx_import_app_service.py:791-897

加在 L819 if self._confirm_service is None: 之前:

self._safe_log_info(
    "[v2-bundle-debug] _run_v2_bundle_confirm enter: confirm_service=%s shell_service=%s "
    "source_type=%s source_uid=%s parsed_components=%d parsed_la=%d parsed_inv=%d sc=%s",
    "wired" if self._confirm_service is not None else "None",
    "wired" if self._ssp_shell_service is not None else "None",
    source_type,
    effective_source_uid,
    len(parsed_result.get("components") or []),
    len(parsed_result.get("leveraged_authorizations") or []),
    len(parsed_result.get("inventory_items") or []),
    "present" if parsed_result.get("system_characteristic") else "None",
)

加在 L865 if ssp_id is None: 之前(ensure_shell 成功時記下 ssp_id):

if source_type == "module_frame" and ssp_id is not None:
    self._safe_log_info(
        "[v2-bundle-debug] ensure_shell OK ssp_id=%s", ssp_id,
    )

加在 L872 result = self._confirm_service.confirm(...) 前後:

self._safe_log_info(
    "[v2-bundle-debug] calling _confirm_service.confirm ssp_id=%s parsed_components=%d parsed_la=%d parsed_inv=%d",
    ssp_id,
    len(parsed_result.get("components") or []),
    len(parsed_result.get("leveraged_authorizations") or []),
    len(parsed_result.get("inventory_items") or []),
)
result = self._confirm_service.confirm(
    parsed_result=parsed_result,
    ssp_id=ssp_id,
    catalog_id=catalog_id,
    user_context=user_context,
)
self._safe_log_info(
    "[v2-bundle-debug] _confirm_service.confirm returned: %s", result,
)

Files:

  • Modify: domain/oscal/import_pipeline/confirm_service.py:41-115

加在 L52 bundle = dict_to_bundle(parsed_result) 後 + L84 / L89 / L98 write 之前:

logger.info(
    "[v2-bundle-debug] confirm: bundle.parsed_components=%d parsed_la=%d parsed_inv=%d parsed_parties=%d",
    len(bundle.parsed_components),
    len(bundle.parsed_leveraged_authorizations),
    len(bundle.parsed_inventory_items),
    len(bundle.parsed_parties),
)
# ... existing normalize ...
logger.info(
    "[v2-bundle-debug] confirm post-normalize: bundle.parsed_components=%d parsed_la=%d parsed_inv=%d",
    len(bundle.parsed_components),
    len(bundle.parsed_leveraged_authorizations),
    len(bundle.parsed_inventory_items),
)

並在每個 self._leveraged.write(...) / self._component.write(...) / self._inventory.write(...) 後 log return value。

請重啟 BE(patch 加了 debug log)。然後請:
1. 用 mf b8065ad5 跑一次 import-docx 上傳同一份 docx
2. STEP 2 全選「採用新值」
3. STEP 3 確認後按確認匯入
我會從 log 找確切 silent fail 位置。
grep -nE '\[v2-bundle-debug\]' ~/Projects/Billows/Audit-Manager/compliance-manager-be/log/app.log | tail -30

從 log 看出:

  • (a) _run_v2_bundle_confirm enter 顯示 parsed_components 是否非 0
  • (b) ensure_shell ssp_id 是 219 還是 228
  • (c) confirm enter 跟 post-normalize 之間 bundle.parsed_components 變化
  • (d) leveraged/component write return value

不 commit 這個 patch(debug 用,root cause pin 後拿掉,per Task 2.5)。


§5

Phase 2: Fix Bug T — v2-bundle silent fail(confirm_service 寫 0 row)

必前置完成 Phase 0 — 拿到 debug log 確切位置才能寫 fix。

Task 2.1: 根據 Phase 0 log 寫 failing test

從 Phase 0 grep 結果應該看到下列其中一條:

觀察 Root cause Fix 方向
[v2-bundle-debug] _run_v2_bundle_confirm enter: parsed_components=0 _apply_v3_decisions 把 parsed_result['components'] 弄空 _apply_v3_decisions
_run_v2_bundle_confirm enter: parsed_components=4confirm: bundle.parsed_components=0 dict_to_bundle silent skip bundle_restore._restore_component
confirm: bundle.parsed_components=4_confirm_service.confirm returned: written_components=0 _component.write() per-row insert 全失敗(logger 沒寫 app.log) 補 logger config / 修 insert
_confirm_service.confirm returned: written_components=4 但 DB 還是 0 row transaction rollback 在更晚 step 找 transaction boundary
沒看到 _run_v2_bundle_confirm enter log confirm_import 整個 try block 抓到 exception 沒走進 v2-bundle 看 confirm_import line 760 try block

範例(假設 root cause 是 _apply_v3_decisions 在 components_decisions=[] 時把 components 弄空 — inline repro 證偽,所以這條候選低):

# tests/test_ssp_docx_import_app_service.py 加
def test_v2_bundle_confirm_writes_components_when_decisions_empty(
    app_service, mock_confirm_service, sample_parsed_result_with_components,
):
    """FE 沒送 components_decisions / la_decisions 時,BE 應該仍寫入 docx 帶來的
    components/leveraged(mirror added × None default → use_docx semantics)。
    """
    # arrange parsed_result 帶 4 個 components + 1 個 leveraged
    job = MagicMock(parsed_result=sample_parsed_result_with_components,
                    source_type="module_frame", source_uid="mf-uid",
                    status="awaiting_review", mode="statement_only")
    # ... fixture
    # act
    app_service.confirm_import(parse_uid="job-uid", payload={
        "decisions": [], "parties_decisions": [],
        "components_decisions": [],  # 空
        "leveraged_authorizations_decisions": [],
        "source_uid": "mf-uid",
    }, user_context=mock_user_context)
    # assert
    args, _ = mock_confirm_service.confirm.call_args
    assert len(args[0]["components"]) == 4, "components shouldn't be wiped"
    assert len(args[0]["leveraged_authorizations"]) == 1
poetry run pytest tests/test_ssp_docx_import_app_service.py::test_v2_bundle_confirm_writes_components_when_decisions_empty -v

Task 2.2: Fix root cause

poetry run pytest tests/ -q

Task 2.3: 拿掉 Phase 0 加的 debug log

grep -nE '\[v2-bundle-debug\]' app/oscal/service/ssp_docx_import_app_service.py domain/oscal/import_pipeline/confirm_service.py
# 應該沒輸出
poetry run pytest tests/test_ssp_docx_import_app_service.py -q

Task 2.4: Commit Bug T fix

git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be add \
  <修改的檔案們>
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be commit -m "$(cat <<'EOF'
fix(ssp-oscal-alignment): Bug T — v2-bundle confirm silent fail 0 row components/leveraged

Root cause: <根據 Phase 0 結論填>

Fix: <根據 fix code 填>

Test: tests/test_ssp_docx_import_app_service.py 加
test_v2_bundle_confirm_writes_components_when_decisions_empty。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"

§6

Phase 3: Fix Bug U — FE confirm payload 漏 4 個 v3 decision keys

SspDocxImportPage.vue L736-744 手刻 payload,沒 wire components_decisions / leveraged_authorizations_decisions / inventory_items_decisions / system_characteristic_decision。store 的 buildConfirmPayload() 已正確含這 4 個 keys 但沒被用。

Files:

  • Modify: compliance-manager-fe/src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue:617-744

Task 3.1: 跨 repo 必讀 FE CLAUDE.md

head -200 ~/Projects/Billows/Audit-Manager/compliance-manager-fe/CLAUDE.md

Task 3.2: 改 confirm payload 補 4 個 v3 keys

// 在 L736 const payload = { 內加:
const components_decisions = Object.entries(diffStore.decisions.components || {}).map(
    ([row_uid, d]) => ({ row_uid, action: d.action ?? 'skip' })
)
const leveraged_authorizations_decisions = Object.entries(diffStore.decisions.leveraged_authorizations || {}).map(
    ([row_uid, d]) => ({ row_uid, action: d.action ?? 'skip' })
)
const inventory_items_decisions = Object.entries(diffStore.decisions.inventory_items || {}).map(
    ([row_uid, d]) => ({ row_uid, action: d.action ?? 'skip' })
)
const system_characteristic_decision = diffStore.decisions.system_characteristic?.action ?? null

const payload = {
    decisions,
    parties_decisions,
    components_decisions,
    leveraged_authorizations_decisions,
    inventory_items_decisions,
    system_characteristic_decision,
    manual_assignments: [],
    skipped_paragraph_idxs: [],
    predicted_controls_user_selection: parsedResult.value?.predicted_module_frame_controls || [],
    source_uid: effectiveTargetUid || props.targetUid || undefined,
    content_overrides: contentOverrides,
}
cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe
npm run lint -- src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue

預期:no error

Task 3.3: Commit Bug U fix

git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe add \
  src/components/grc/ssp-docx-import-v2/SspDocxImportPage.vue
git -C ~/Projects/Billows/Audit-Manager/compliance-manager-fe commit -m "$(cat <<'EOF'
fix(ssp-oscal-alignment): Bug U — confirm payload 補 4 個 v3 decision keys

Root cause: SspDocxImportPage.vue L736-744 手刻 confirm payload,沒帶
components_decisions / leveraged_authorizations_decisions /
inventory_items_decisions / system_characteristic_decision。
diffStore.buildConfirmPayload 已正確含這 4 keys 但沒被使用。
BE 端 _apply_v3_decisions 對「沒給 decision」走 backfill cur path —
若 current 為空 final_list 也空 → components 永遠不寫入。

Fix: payload 內補 4 個 v3 keys 從 diffStore.decisions 收集。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"

§7

Phase 4: Manual E2E verify(user 操作)

Task 4.1: 提醒 user 重啟 BE

Phase 1-3 BE + FE fix 完成。請:
1. 重啟 BE(service 層改了)— 不要直接吃 cache,用 kill -9 找 :8000 listener
2. FE: cd ~/Projects/Billows/Audit-Manager/compliance-manager-fe && npm run dev(如果還沒起)
3. 走完整流程:
   (a) 開 /module-frame/b8065ad5-e169-4df4-9bd3-5ec0d03b2e1d/template-edit 看 parties 5 個 + components 0 個(baseline)
   (b) 上 /module-frame/b8065ad5-e169-4df4-9bd3-5ec0d03b2e1d/import-docx 上傳同份 docx
   (c) STEP 2 全選「採用新值」(含 components / leveraged tab)
   (d) STEP 3 確認後按確認匯入
   (e) 回 template-edit 確認 components 出現 4 個 + leveraged 出現 1 個
   (f) 再做一次同樣動作但 STEP 2 部分 party 改選「保留現值」(mix scenario)
   (g) 確認保留現值的 party 鉤稽資料 + link 都還在

Task 4.2: User verify 完回報後跑 DB SQL 確認

PGPASSWORD='jedi@123!' psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -A -F$'\t' -c "
SET app.is_super_admin='t';
SELECT 'comp_after' k, count(*) FROM oscal.ssp_components WHERE ssp_id IN (219, 228);
SELECT 'la_after' k, count(*) FROM oscal.ssp_leveraged_authorizations WHERE ssp_id IN (219, 228);
SELECT 'rp_mf_after' k, count(*) FROM oscal.oscal_responsible_parties WHERE context_type='module_frame' AND context_id=343;
SELECT p.id, p.name, p.user_id, p.org_unit_id FROM oscal.oscal_parties p
  JOIN oscal.oscal_responsible_parties rp ON rp.party_uuid = p.uid::text
 WHERE rp.context_type='module_frame' AND rp.context_id=343 ORDER BY p.id;
"

預期(fix 成功):

  • comp_after >= 4(兩個 shell 合計)
  • la_after >= 1
  • rp_mf_after = 5(不少不多)
  • parties 內 user_id / org_unit_id 應保留 user 之前鉤稽的值

不符 → STOP,回 root cause Phase 0 重新 verify。


§8

Phase 5: 收尾(等 user 明確說「收尾」/「verify 通了,收尾」才執行

per memory feedback_wait_for_user_command_to_close.md:fix code commit 完只給 user 一句話 status + 手測 checklist。預先寫好的 BE docs 留 working tree 不 commit。user verify pass + 明確下令才 stage + commit 收尾文件。

Task 5.1: design.md 加 §11.39

涵蓋:Bug S/T/U root cause + commits + 教訓

Task 5.2: changelog

frontmatter type=fix,modules=[oscal, ssp-docx-import, frontend],commit=<填 BE/FE hash>

Task 5.3: FIXED-SUMMARY

Task 5.4: Memory feedback(2 條)

write_strategy.write_parties 不該在 caller 沒傳進來時自作主張砍 link — caller (_collect_parties_to_unlink) 已明確收集要砍的,write strategy 只負責「caller 給的這批寫入」。Bug S 踩過 mf strategy 內 stale cleanup 砍 keep_current link,造成鉤稽資料消失。SspWriteStrategy 本來就沒這 cleanup(對的)。

FE 對 BE confirm/submit payload 要走 store 統一的 buildXxxPayload(),不要在 view 內手刻 — store 已維護完整 schema,view 手刻容易漏 key(Bug U 漏 4 個 v3 decision keys 兩個月)。新增 BE accept 的 payload key 後,先驗 store builder 有沒有,再驗 view 是否用 builder。

Task 5.5: 對話歷史歸檔

python3 scripts/extract_claude_sessions.py --date 2026-05-26 --topic bug-stu-docx-import-components --auto

Task 5.6: 標 ✓ FIXED 標頭(既有 handoff)

  • docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-r-diff-service-duplicate-entry-handoff.md(如果本期 fix 涵蓋這些)
  • docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-bug-pqr.md
  • docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-bug-r-deeper.md

Task 5.7: 橫向文件更新(per CLAUDE.md「回頭更新文件」step)

  • docs/claude/frontend-overview.md — FE buildConfirmPayload pattern 新增說明(若先前沒提)
  • docs/api/oscal/api-spec.md — confirm endpoint payload 加 4 個 v3 keys 文件化
  • design.md §11 index — 加 §11.39 對應 link

Task 5.8: Commit 收尾文件(等 user 下令

git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be add \
  docs/features/FR-028-2605-ssp-oscal-alignment/design.md \
  docs/changelog/2026-05-26-fix-bug-stu-*.md \
  docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-26-bug-stu-FIXED-SUMMARY.md \
  docs/features/FR-028-2605-ssp-oscal-alignment/handoff/2026-05-25-bug-r-diff-service-duplicate-entry-handoff.md \
  docs/conversation-history/2026-05-26/bug-stu-docx-import-components/ \
  docs/claude/frontend-overview.md \
  docs/api/oscal/api-spec.md

git -C ~/Projects/Billows/Audit-Manager/compliance-manager-be commit -m "$(cat <<'EOF'
docs(ssp-oscal-alignment): Bug S/T/U 收尾橫向文件更新

- design.md §11.39 + §11 index 補 Bug S/T/U 三 bug 紀錄
- changelog: 2026-05-26-fix-bug-stu-docx-import-components-and-keep-current.md
- handoff: 2026-05-26-bug-stu-FIXED-SUMMARY.md 收尾報告
- 對話歷史歸檔 → docs/conversation-history/2026-05-26/bug-stu-docx-import-components/
- frontend-overview.md / api-spec.md 同步本期改動

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
收尾 commit 完成。BE 領先 origin <N> commits(Phase 1 + Phase 2 + Phase 5),
FE 領先 origin <M> commits(Phase 3)。要 push 哪個 repo?(per CLAUDE.md
「push 永遠要 user 明確指示」)

§9

不在本期 scope

  • Bug ② 對 SspWriteStrategy 等其他 strategy 的影響:本期僅 ModuleFrameWriteStrategy 有此 bug(SspWriteStrategy 已 verify 沒此 cleanup)
  • FE buildConfirmPayload 對應的 store schema 重寫:本期只補 view payload 4 個 keys,store schema 維持現狀
  • jedi-oscal 套件版本 bump:本期 BE 改動全在主專案,無套件異動
  • BE/FE 版號 bump:本期是 bug fix,user 拍板才 bump

§10

行為規範重要提醒(per CLAUDE.md + memory)

  • 永不切 branch(per memory feedback_no_branch_switch
  • 可自行 commit,不自動 push(per memory feedback_stage_commit_no_ask
  • 改 BE service 層後必提醒 user 重啟 BE(per memory feedback_be_restart_after_service_change
  • 跨 repo 改 FE 必 read FE CLAUDE.md(Task 3.1)
  • DB 兩張表都 verify 才算 done(Task 4.2 同時驗 oscal_responsible_parties + ssp_components
  • 修 bug 前先驗證 DB / response 真實狀態(Verify Hypotheses 段)
  • plan 假設先 verify(Verify Hypotheses A-E)
  • 收尾必須等 user 下命令才做(Phase 5)
  • 服務都 user 自己起,Claude 不啟動(Phase 4 只請 user 起,不附 python main_socketio.py
  • 可人工驗證就切人工(Phase 4 不再跑 playwright,請 user 手測)
  • 不要晶晶體(per memory feedback_no_chinglish
  • subagent dispatch 必加「git add 顯式檔名」(如果 dispatch subagent,禁用 -am

§11

給 fresh session 的超短 prompt(若要換 session 接手執行)

請閱讀並執行 implementation plan:
docs/features/FR-028-2605-ssp-oscal-alignment/implementation-plan-bug-stu.md

3 個 bug:(S) ModuleFrameWriteStrategy 砍 keep_current link;
(T) v2-bundle confirm 寫 0 row components;(U) FE 漏 4 個 v3 decisions wire。

按 Phase 0 → 1 → 2 → 3 → 4 → 5 順序。Phase 0 必先 patch debug log 請
user 重啟 + 重做 1 次 import → pin Bug T 確切位置才能往 Phase 2 寫 fix。

注意行為規範:不切 branch / 不自動 push / 改 BE service 必提醒重啟 /
收尾等 user 下令 / 可人工驗證就切人工。