CR-028 hold 事件群四項矛盾之化解(CR-027 §5 #1~#4)
| 項目 |
內容 |
| 文件編號 |
CR-028 |
| 版本 |
1.0 |
| 提出日 |
2026-10-01 |
| 提出者 |
WorkBuddy AI(開發團隊) |
| 緣起 |
BEAM PMO 指示「批次 B(hold 事件群)動工前必須先裁定 CR-027 §5 #1~#4,請一一化解,不用急。我不求快,但求精準無誤」。本 CR 即為該四項之化解方案 + 執行紀錄
|
| 影響範圍 |
SAD-002 §3.1/§3.2、SAD-004 §5.2、SDD-006 §4.2、GOV-001 §4.4、SCS-002 §7.6
|
| 狀態 |
✅ 已化解並執行(文件層);程式碼零影響(見 §5) |
1. 化解方法(先查證、再擬案、後動手)
BEAM PMO 要求「精準無誤」,故本次不憑文件互相比較就下結論,而是先取客觀證據:
| 證據來源 |
取法 |
| 程式碼是否曾實作該事件 |
全庫搜尋 authorization.hold.
|
| payload 是否實質相同 |
比對 SDD-006 §4.2 之兩列 |
| 權威欄位是否足以支撐 |
直接查 user_tab_columns(真實 Oracle) |
2. 查證結果(四項證據,皆可複驗)
證據 A|authorization.hold.* 全庫程式碼零引用
搜尋 authorization\.hold\. 於 cardcore/ 全庫,命中僅 5 處,全在文件:
| 位置 |
內容 |
SAD-002 §3.1(行 89) |
authorization 之「事件(發布)」清單 |
SAD-004 §5.2(行 302/303) |
事件清單兩列 |
SDD-006 §4.2(行 409/410) |
事件 payload 兩列 |
GOV-001 §4.4(行 165) |
命名範例(非契約) |
→ 零程式引用:AuthorizeUseCase 從未發射此二事件;limit-service 從未訂閱。
→ 故廢除之「程式影響」為零(僅文件需修)。
證據 B|authorization.hold.created.v1 與 limit.hold.created.v1 是同一件事
SDD-006 §4.2 之 authorization.hold.created.v1 payload = holdId, accountId, holdAmount, holdType。
而 SAD-002 §3.2 稱 limit 發布 limit.hold.created.v1——本專案 #A-122 已實作,其 payload(依 SCS-002 §7.6)逐欄相同。
→ 同一語意、兩個前綴;limit.hold.created.v1 從未被登錄於 SDD-006 §4.2(清單漏列)。
證據 C|limit_holds 之權威在 CC_LIM
| 表 |
服務 |
性質 |
CC_LIM.LIMIT_HOLDS |
limit-service |
權威(SAD-002 §3.2/SCS-002 §8:「本埠為唯一權威出入口」) |
CC_AUTH.LIMIT_HOLDS |
authorization-service |
本地投影(V2__read_model.sql 明文:「權威在 CC_LIM.LIMIT_HOLDS」) |
→ hold 之事實由 limit 產生;authorization 只能消費,不能發布。
證據 D|兩張 limit_holds 皆有 AUTHORIZATION_ID
| 表 |
欄位(實查 user_tab_columns) |
CC_LIM.LIMIT_HOLDS |
ID/ACCOUNT_ID/AUTHORIZATION_ID/HOLD_AMOUNT/RELEASED_AMOUNT/HOLD_TYPE/STATUS/EXPIRES_AT/CREATED_AT/UPDATED_AT/VERSION
|
CC_AUTH.LIMIT_HOLDS |
ID/ACCOUNT_ID/AUTHORIZATION_ID/CURRENCY/HOLD_AMOUNT/RELEASED_AMOUNT/STATUS/EXPIRES_AT/CREATED_AT/UPDATED_AT/VERSION
|
→ limit 有能力提供 authorizationId;authorization 需要它以維護本地投影。
3. 逐項化解
#1 hold 事件之方向與權威 → 定案:廢除 authorization.hold.*,只保留 limit.hold.*
| 項目 |
內容 |
| 矛盾 |
SAD-002 §3.1 稱 authorization 發布 authorization.hold.created.v1/.released.v1;§3.2 稱 limit 發布 limit.hold.created.v1/.released.v1——同一事實兩個生產者
|
| 證據 |
A(零程式引用)、B(payload 逐欄相同)、C(權威在 CC_LIM) |
| 定案 |
(a) 廢除 authorization.hold.created.v1/authorization.hold.released.v1;hold 事件一律由 limit-service 發布(limit.hold.created.v1/limit.hold.released.v1) |
| 理由 |
① authorization.hold.created.v1 與 limit.hold.created.v1 是同一件事——保留兩個名字必然造成「同一事實兩則事件」之重複消費;② authorization 不是 hold 之權威(CC_LIM.LIMIT_HOLDS 才是),由其發布「佔用已建立」是事實歸屬錯誤;③ authorization 對 limit 之佔用請求是同步 API(POST /limit-holds)——那是命令,不是事件(GOV-001 §4.4:事件為過去式既成事實) |
| ⚠️ 一併釐清 |
authorization.hold.released.v1 之 payload 為 holdId, releasedAmount, reason(含 reason),與 limit.hold.released.v1(holdId, accountId, releasedAmount)不同欄。惟「帶原因」正顯示其為命令(「請釋放,原因為 X」)——原因屬請求參數,非事件事實。故一併廢除
|
| 影響 |
文件 4 處(SAD-002 §3.1、SAD-004 §5.2、SDD-006 §4.2、GOV-001 §4.4 範例);程式 0 處
|
#2 authorization 訂閱清單 → 定案:以 SAD-002 為準,auth 訂閱 limit.hold.created.v1
| 項目 |
內容 |
| 矛盾 |
SAD-002 §3.1 之 auth 訂閱清單含 limit.hold.created.v1;SAD-004 §5.2 之事件清單無此事件(僅有 limit.hold.released.v1) |
| 證據 |
C(auth 有本地投影 CC_AUTH.LIMIT_HOLDS,需被餵養) |
| 定案 |
以 SAD-002 為準——auth 訂閱 limit.hold.created.v1;並補登至 SAD-004 §5.2
|
| 理由 |
若只訂閱 released 而不知 created,消費者會「釋放一筆不存在的佔用」——本地投影將永遠缺列(與 card_status_caches 曾恆空之缺陷同型) |
#3 limit.hold.released.v1 之消費者 → 定案:消費者為 authorization(與 #2 同批處理)
| 項目 |
內容 |
| 矛盾 |
SAD-004 §5.2 載消費者=authorization;SAD-002 §3.1 之 auth 訂閱清單未含它 |
| 定案 |
補進 SAD-002 §3.1——auth 訂閱 limit.hold.created.v1 與 limit.hold.released.v1
|
| 理由 |
二者為同一本地投影之生命週期(建立→釋放),拆開訂閱必造成投影狀態落後(如 released_amount 永不更新) |
#4 limit.hold.created.v1 payload 缺 authorizationId → 定案:補為「可選」欄位,不升版
| 項目 |
內容 |
| 矛盾 |
SDD-006 §4.2 之 authorization.hold.created.v1 payload 為 holdId, accountId, holdAmount, holdType——無 authorizationId,惟 authorization 之本地投影有 AUTHORIZATION_ID 欄位 |
| 證據 |
D(兩張表皆有該欄位) |
| 定案 |
(b) 補 authorizationId 為可選欄位(SAD-004 §5.3:「新增可選欄位 → 不升版」);併登錄 limit.hold.created.v1 之完整 payload(含 authorizationId) |
| 理由 |
① limit 有能力提供(權威表有該欄);② authorization 需要它(否則無法把 hold 對應回自己的授權);③ 為可選——stand-in 等無對應授權之情境可為 null,故不升 v2、無雙軌成本 |
| 影響 |
SCS-002 §7.6(改「刻意不納入」→「可選」)+ LimitEventFactory(下一輪實作,屬批次 B) |
4. 需同步修訂之文件(本 CR 已執行)
| # |
文件 |
修訂 |
| 1 |
SAD-002 §3.1 |
「事件(發布)」移除 authorization.hold.created.v1/.released.v1;「事件(訂閱)」補 limit.hold.created.v1、limit.hold.released.v1
|
| 2 |
SAD-002 §3.2 |
「事件(發布)」補 limit.hold.created.v1(原已列 .released.v1) |
| 3 |
SAD-004 §5.2 |
刪兩列 authorization.hold.*;補 limit.hold.created.v1 一列(生產者 limit、消費者 authorization) |
| 4 |
SDD-006 §4.2 |
刪兩列 authorization.hold.*;補 limit.hold.created.v1(含 authorizationId 可選) |
| 5 |
GOV-001 §4.4 |
命名範例 authorization.hold.created.v1 → limit.hold.created.v1
|
| 6 |
SCS-002 §7.6 |
authorizationId 由「刻意不納入」改為「可選欄位」;移除「SAD-002 §3.1 矛盾待裁定」之註記 |
5. 對程式碼之影響:零
| 項目 |
說明 |
authorization-service |
無——從未發射 authorization.hold.*(證據 A) |
limit-service |
已實作 limit.hold.created.v1/limit.hold.released.v1(#A-122)→ 本 CR 不動程式;僅 authorizationId 之補入屬批次 B
|
| 其他服務 |
無 |
⚠️ 故本 CR 無需重編譯、無需真機驗證——這是文件層之化解。
(符合 GOV-003 條件 9:「先有規格、才寫程式」——此處連程式都不需改。)
6. 化解後之批次 B 藍圖(供下一輪動工)
| 步驟 |
內容 |
| ① 規格先行 |
SCS-002 §7.6 補 authorizationId(已於本 CR 完成);SCS-001 §7.15 新增「佔用事件消費」 |
| ② 生產端 |
LimitEventFactory.holdCreatedEnvelope 補 authorizationId(可選,由 LimitApplicationService.hold 傳入) |
| ③ 消費端 |
authorization-service 消費 cc.limit.limit.hold.created/.released → upsert 本地 limit_holds(冪等+亂序,沿用 consumed_events) |
| ④ 真機 |
建立佔用 → limit_holds 本地投影落列;部分釋放 → released_amount 更新 |
7. 未竟(誠實揭露)
-
本 CR 未動任何程式——批次 B 之實作(含
authorizationId 之補入)尚待動工。
-
limit.hold.created.v1 之消費者尚未實作 → 現階段 CC_AUTH.LIMIT_HOLDS 仍無餵養者(僅 stand-in 路徑寫入)。
-
CR-027 §5 其餘 8 項(#5~#12)仍待裁定——其中 #5(事件清單權威) 與本 CR 相關:
本 CR 已將 limit.hold.created.v1 補登至 SAD-004 §5.2,惟兩份清單是否合併為單一權威仍待 BEAM PMO 裁定。
8. 修訂記錄
| 版本 |
說明 |
| 1.0 |
初版:hold 事件群四項矛盾之化解——先取四項客觀證據(零程式引用/payload 逐欄相同/權威在 CC_LIM/兩表皆有 AUTHORIZATION_ID),再逐項定案;已執行 6 份文件之同步修訂;程式碼零影響
|