CR #204 » CR-003_狀態機值域與DDL不一致.md
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/CLOSEDSTATEMENT_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 |
一併處置二項既有債:
-
移除不可達轉換——原轉換 3「
CUR到期且餘額 < 0 →CUR」,
因BALANCE >= 0之 CHECK 使負餘額不可能存在(實測),已刪除。
(SCS-010 §10.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 |