Project

General

Profile

CR #204 » CR-003_狀態機值域與DDL不一致.md

內容更新:內部稱謂去識別化(2026-10-18) - Redmine Admin, 10/18/2026 05:32 AM

 

CR-003 狀態機值域與 DDL 不一致(§5/§7/§9/§10)

項目 內容
文件編號 CR-003
版本 1.0
狀態 已核定並執行完成(2026-09-19,BEAM PMO 裁定)
提出日期 2026-09-19
提出者 開發團隊(SDD-005 1.2 版 §12.3 值域稽核時發現)
影響文件 SDD-001 §3.7/§3.8/§3.10、SDD-005 §1/§5/§7/§9/§10/§12/§13、SDD-007、SCS-008/010/011/012
影響服務 payment-service(8088)、dispute-service、statement-service(8092)、rewards-service(8091)
優先級 高(P1)——SDD-005 §1 SM-08 明訂值域以 DDL 為權威;不一致將導致寫入即 ORA-02290 或文件與實物永久脫節

1. 摘要

SDD-005 1.2 版之 §12.3 值域稽核(以 all_cons_columns +
all_constraints.search_condition_vc 實測 10 組狀態機對應之 DDL CHECK 約束)
發現 4 組不一致(稽核當時:6 組對齊、4 組待處理)。

本 CR 逐項分析性質、提請核定,並於核定後執行修正。4 項均已於 2026-09-19 完成,
SDD-005 升版至 1.3,稽核結果由「6 對齊/4 待處理」轉為 「14 組全數對齊」。


2. 四項不一致與性質分析

2.1 A|§5 繳款:UNMATCHED 不可持久化

本文件(1.2 版) 實體 DDL(實測)
RECEIVED/ALLOCATED/POSTED/REVERSED/FAILED/UNMATCHED status IN ('RECEIVED','ALLOCATED','POSTED','REVERSED','FAILED')——無 UNMATCHED

性質:值域不足(非混用維度)。UNMATCHED 於實體中以
PAYMENTS.UNMATCHED_FLAG 旗標表達,與 status 為正交維度。

二途:①移除該狀態、改以旗標語意;②於 DDL 增列該值。

關鍵事實:本節之 UNMATCHED 為作業狀態——轉換 6「ALLOCATED 逾三日未收銷帳檔
→ UNMATCHED(重新佔額,POC-11 情境三)」、轉換 7「收到銷帳檔 → POSTED」、
轉換 8「確認未入帳 → REVERSED」。此語意與旗標不同,不應為遷就 DDL 而捨棄。

2.2 B|§7 爭議:值域幾乎完全不同(最嚴重)

本文件(1.2 版) 實體 DDL(實測)
OPENED/EVIDENCE_COLLECTING/UNDER_REVIEW/RESOLVED_ISSUER/RESOLVED_ACQUIRER/ARBITRATION/CLOSED status IN ('OPEN','EVIDENCE_PENDING','REPRESENTED','WON','LOST','CLOSED')

僅 CLOSED 一值交集。

性質:不同分類軸被繪入單一狀態機——本文件採「處理階段 + 責任歸屬」,
DDL 採「階段 + 勝敗結果」。與 CR-002 之分期類型問題性質完全相同。

關鍵事實:實體 DDL 已有三個欄位分別承載三個維度(實測值域):

欄位 值域 維度
DISPUTE_CASES.stage INQUIRY/FIRST_PRESENTMENT/SECOND_PRESENTMENT/PRE_ARB/ARBITRATION/CLOSED 卡組織流程階段
DISPUTE_CASES.status OPEN/EVIDENCE_PENDING/REPRESENTED/WON/LOST/CLOSED 案件處理與結果
DISPUTE_CASES.liability ISSUER/ACQUIRER/MERCHANT/PENDING 責任歸屬(分類屬性,非生命週期)

亦即實體模型正確、文件繪錯——dispute-service 目前僅有骨架(無領域模型),
故無實作債。SCS-012 §10 亦已載明「DISPUTE_CASES.status/STAGE 轉換強烈建議
建模為 SDD-005 正式狀態機」。

2.3 C|§9 帳單:混用兩個實體且有缺值

本文件(1.2 版) 實體 DDL(實測)
GENERATING/GENERATED/FAILED/SENT/PARTIALLY_PAID/PAID/OVERDUE STATEMENTS.status:GENERATED/SENT/PAID/PARTIALLY_PAID/OVERDUE/DISPUTED/CLOSED
STATEMENT_RUNS.status:GENERATING/GENERATED/FAILED

性質:兩個實體被繪入單一狀態機——GENERATING/FAILED 屬批次執行
(statement_runs,於 V2 遷移補建),其餘屬帳單本體(statements)。
另 DDL 之 DISPUTED/CLOSED 未出現於本節(缺值)。

關鍵事實:STATEMENT_RUNS 係因契約要求「批次狀態與 Checkpoint」而於
V2__statement_runs_and_no_seq.sql 補建,SDD-001 §3.10 之 ER/DDL 為 V1 基線快照,
未含此表(文件債,一併於本次加註交付說明)。

2.4 D|§10 點數:混用三個維度

本文件(1.2 版) 實體 DDL(實測)
CUR/AV1/AV2/CLOSED POINTS_EXPIRY_BUCKETS.BUCKET_STAGE:CUR/AV1/AV2(桶階段)
POINTS_EXPIRY_BUCKETS.STATUS:ACTIVE/EXPIRED/REDEEMED(桶狀態)
POINTS_ACCOUNTS.STATUS:ACTIVE/FROZEN/CLOSED(帳戶狀態)

性質:三個維度被繪入單一狀態機。CUR/AV1/AV2 為桶階段、
CLOSED 為帳戶狀態。

關鍵事實:

  • 實作(rewards-service)已正確對應至不同欄位,故為文件債,非程式債。
  • SCS-010 §10.2 已揭露 2 條不可達轉換:轉換 3(CUR 到期且餘額 < 0——
    受 BALANCE >= 0 之 CHECK 所限)、轉換 5(AV1 到期且餘額 = 0——
    受桶 POINTS > 0 之 CHECK 所限)。
  • SCS-010 §10.6 列有規格空白:「FROZEN 帳戶之入點行為待 CR 確認」,
    其待辦 ① 即為「於 SDD-005 新增帳戶營運狀態機」。

3. 決策(2026-09-19 BEAM PMO 裁定)

項 問題 裁定
A §5 移除 UNMATCHED,或 DDL 增列? DDL 增列
B §7 擇一(統一用勝敗結果),或拆兩欄? 拆兩個(階段/結果)
C §9 是否同意拆分狀態機? 拆分狀態機
D §10 是否同意拆分狀態機? 拆分狀態機

4. 已執行之修正

4.1 A|§5 繳款(DDL 增列)

# 動作 產出
1 設計權威 SDD-001 §3.7 之 status CHECK 增列 UNMATCHED 文件
2 新增遷移 V4__payments_unmatched_status.sql(V1 已凍結,不得修改) 實體
3 PaymentStatus 增列 UNMATCHED,並釐清與 UNMATCHED_FLAG 之正交關係 程式
4 契約 PaymentView.status 枚舉增列 UNMATCHED(改 gen_openapi.py 後重生) 契約
5 SDD-005 §5 補值域說明、正交關係表與保留事項 文件

實測(本地 Oracle 26ai FREEPDB1,非推測):

寫入 status='UNMATCHED'  → 成功,SELECT 回 UNMATCHED
寫入 status='BOGUS_VALUE' → ORA-02290: check constraint (CC_PAYMENT.CK_PAYMENTS_STATUS) violated

約束名由自動生成之 SYS_C0010868 重建為具名 CK_PAYMENTS_STATUS(V4 以資料字典
動態尋得,不依賴自動名稱),使後續值域變更得以穩定引用。V4 冪等,可重跑。

⚠️ 保留事項:

  • UNMATCHED 之產生者尚未實作(「逾三日未收銷帳檔」之批次不存在),
    故尚無程式路徑可達;惟持久化能力已具備(本次更正之目的)。
  • 轉換 8(UNMATCHED → REVERSED)尚未實作:PaymentStatus.reversible()
    目前僅放行 POSTED。日後實作該批次時須一併放行。

4.2 B|§7 爭議(拆分為兩個狀態機)

SDD-005 §7 改寫為:

小節 狀態機 對應欄位 轉換數
§7.1 爭議階段機 stage 10
§7.2 爭議案件狀態機 status 11
§7.3 liability——正交屬性,非狀態機 liability —

DDL 無須變更(三欄皆已存在)。轉換依 BRD-001 BF-09(C1~E3)逐節對應。

4.3 C|§9 帳單(拆分為兩個狀態機)

小節 狀態機 對應欄位 轉換數
§9.1 帳單本體 statements.status(7 值,補入 DISPUTED/CLOSED) 14
§9.2 批次執行 statement_runs.status(3 值) 4

轉換依 BRD-001 BF-05(A1~C4)逐節對應。
另於 SDD-001 §3.10 加註 V2 交付說明(statement_runs/statement_cycle_accounts/
statement_no_seq 未列於 V1 基線快照之原因與值域)。

4.4 D|§10 點數(依維度拆分為三個狀態機)

小節 狀態機 對應欄位 轉換數
§10.1 桶階段流轉 bucket_stage 5
§10.2 桶狀態機 points_expiry_buckets.status 5
§10.3 帳戶營運狀態機 points_accounts.status 6

一併處置二項既有債:

  1. 移除不可達轉換——原轉換 3「CUR 到期且餘額 < 0 → CUR」,
    因 BALANCE >= 0 之 CHECK 使負餘額不可能存在(實測),已刪除。
    (SCS-010 §10.2 原已揭露,本次一併更正。)
  2. 封存 FROZEN 入點決策——§10.3 新增「各狀態之操作權限」表
    (ACTIVE 可入點可兌換;FROZEN 可入點、不可兌換 422 CC-RWD-1003;
    CLOSED 皆不可 409 CC-RWD-3002),封存現行實作(SCS-010 §10.6 之規格空白)。
    此即該節待辦之第 ① 項。

另於 SDD-001 §3.8 加註 V2 交付說明(reward_rules 表、
bucket_stage 欄、idempotency_key 欄、redemption_no_seq)。

4.5 連動更正

項 內容
SDD-005 §1 新增通用規則 SM-09「一組狀態機只表達一個欄位」——由本次 4 項更正歸納而得
SDD-005 §12.2 組數 10 → 14;合計 80/103 → 108/139
SDD-005 §12.3 改為 14 組全數對齊,並載明 A~D 之更正歷程
SDD-005 §13 新增 1.3 修訂記錄
SDD-005 檔頭 版本 1.2 → 1.3

轉換數重算:

狀態機 1.2 版 1.3 版
爭議 9 10 + 11 = 21
帳單 11 14 + 4 = 18
點數 7 5 + 5 + 6 = 16
合計 80 108
必測案例數 103 139

5. 驗證結果

項目 結果
V4 遷移套用 PL/SQL 成功;約束重建為 CK_PAYMENTS_STATUS
值域正向實測 UNMATCHED 可寫入並持久化 ✅
值域負向實測 非法值觸發 ORA-02290(證明約束生效,非僅名稱存在)✅
gen_openapi.py 重生 17 服務 / 70 端點 / 0 錯誤
validate_mermaid.py docs 115 區塊 / 0 錯誤(1.2 版為 111;+4 為新拆分之狀態圖)
狀態機組數 10 → 14;值域稽核 14/14 對齊

6. 未納入本次修正(另案追蹤)

# 項目 說明
1 UNMATCHED 之產生者(逾三日未收銷帳檔之批次) 未實作;SDD-005 §5 已列保留事項
2 PaymentStatus.reversible() 未放行 UNMATCHED 同上;實作該批次時須一併處理
3 SDD-001 §3 之 V2+ 遷移落差(跨服務) ⚠️ 本列原記載不實,2026-09-21 更正:原稱「本次僅加註 §3.7/§3.8/§3.10 三處」並舉 reversal_reason 為例——實測 reversal_reason 於 SDD-001 全文出現 0 次,§3.7 並未回寫(§3.8/§3.10 確已完成)。
→ ✅ 已於 HANDOVER #C-18 全數補齊(SDD-001 升 1.5):以腳本比對 V2/V3 遷移與文件,補上 8 項——§3.1 pty_idempotency、§3.2 card_idempotency、§3.4 account_limits/limit_adjustments、§3.5 card_status_caches/account_limit_caches/authorizations.hold_id、§3.7 reversal_reason(ER 圖與 DDL 皆同步)。詳 SDD-001 §10(1.5)
4 §7.3 WON/LOST 與 liability 之精確對應 須依卡組織規則確認;已列入 SCS-012 §10
5 平台層 500-vs-400 缺口 另立 CR-004

7. 殘留風險

# 風險 等級 對策
1 重跑 gen_flyway_baseline.py --force 會覆寫 V1,使 Flyway checksum 失配 中 SDD-001 §3.7 與 V4 檔頭均已載明;若確需重建須 flyway repair 或 docker compose down -v
2 契約與 DDL 現已一致,但 V4 尚未於其他環境套用 中 服務啟動時 Flyway 會自動套用;V4 冪等
3 SDD-001 §3 之 V2+ 落差可能再次造成「文件與實物脫節」 中 建議後續 CR 建立「遷移檔新增欄位/表 → 回寫 SDD-001 §3」之強制步驟

8. 修訂記錄

版本 日期 修訂者 說明
1.1 2026-09-21 WorkBuddy AI 更正 §6 #3 之不實記載:原稱「本次僅加註 §3.7/§3.8/§3.10 三處」,實測 SDD-001 全文不含 reversal_reason(出現 0 次)→ §3.7 並未回寫。該落差已於 HANDOVER #C-18 全數補齊(SDD-001 升 1.5,共 8 項),本列同步更正,以免後人據「已完成」之記載而再度略過。⚠️ 盤點方法亦已修正:不得以「指定章節是否含該名稱」判缺(lim.limit_holds 記載於 §3.4 而非 §3.5,按 §3.5 查會誤判)
1.0 2026-09-19 開發團隊 初版。依 BEAM PMO 裁定執行 §5/§7/§9/§10 四項值域更正,SDD-005 升版 1.3
    (1-1/1)