Project

General

Profile

CR #219 » CR-018_report-service之失敗原因未納入契約.md

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

 

CR-018 report-service 之 ReportJobView 失敗原因未納入契約(實作有、契約無)

項目 內容
文件編號 CR-018
版本 1.0(已執行並真機複驗,見 §4)
提出日 2026-09-22
提出者 WorkBuddy AI(開發團隊)
緣起 GOV-006 3.2.x(C-14 WebUI)批次一動工前之查證——欲接 /system/reports 頁時發現
影響文件 contracts/openapi/report-service.yaml(產生器 tools/gen_openapi.py)、SCS-017
關聯前例 CR-016 §8(同日、同類:動工前查證攔下契約與實作脫鉤)、CR-016 §2.5(契約示例與實作不符)

1. 緣起

C-14 批次一之報表作業頁(/system/reports,SDD-007 §5.4.12)需呈現「作業為何失敗」——
SCS-017 §7 明訂「FAILED 必載 errorDetail(領域層強制,未載即拒)」。
惟查證契約後發現:ReportJobView 未宣告該欄,而實作自 C-7(#A-83)起即回傳之。

→ 消費端(WebUI)無從依契約取得失敗原因,只能依賴「未宣告之額外欄位」——
一旦後端依契約整肅欄位即斷裂。此為契約缺漏,非實作缺陷。


2. 缺口明細(實測 2026-09-22)

來源 errorDetail 備註
契約 ReportJobView ❌ 未宣告 僅 jobId/status/rowCount/downloadUrl/startedAt/finishedAt
實作 ReportJobView(com.beam.cardcore.rpt.application.dto) ✅ 有 第 7 個元件,型別 String
SCS-017 §7 ✅ 要求 「FAILED 必載 errorDetail(領域層強制,未載即拒)」
SDD-006 錯誤碼 — CC-RPT-* 與此無關

實機證據(GET /api/v1/report-jobs/{jobId} → 200):

{"data":{"jobId":"c1ec06ee-…","status":"COMPLETED","rowCount":4,
         "downloadUrl":"file:///…/RPTJ202609000001.csv",
         "startedAt":"2026-09-22T11:18:39.134104Z",
         "finishedAt":"2026-09-22T11:18:39.187199Z",
         "errorDetail":null}}

——errorDetail 確實在回應中,契約卻無此欄。


3. 判定與修正

# 項目 內容
a 判定 契約缺漏(實作正確)。理由:①SCS-017 §7 已明文要求;②無此欄則客戶端無法區分「失敗原因」與「未知失敗」,違反「失敗必載原因、不得靜默失敗」之設計原則;③該欄為新增可選欄位(nullable),不破壞既有相容性
b 修正 tools/gen_openapi.py 之 ReportJobView 補 errorDetail(type: string, nullable: true,附說明)+示例補 "errorDetail": None → 重生契約
c 影響範圍(已嚴格驗證) 以「cp -r 基準 → 重生 → diff -rq 全目錄比對」確認:18 份契約中僅 report-service.yaml 變動(+4 行 schema、+1 行示例);OpenAPI 驗證 0 錯誤/74 端點
d 真機複驗 GET /api/v1/report-jobs/{jobId} → 200,回應含 errorDetail(本例 null,因 COMPLETED)——與修正後契約相符
e 未變更 後端程式不動;SCS-017 之敘述與實作一致,不須改;SDD-001 不動

4. 執行清單(2026-09-22)

# 動作 結果
1 gen_openapi.py:ReportJobView 補 errorDetail ✅
2 重生全部契約 ✅ 0 錯誤/74 端點
3 全目錄 diff 驗證影響範圍 ✅ 僅 report-service.yaml
4 真機複驗端點 ✅ 200,含 errorDetail
5 本 CR 建檔 ✅

5. 誠實揭露

  • 本 CR 未經事前裁定即執行——理由:屬契約缺漏之補正(新增可選欄位、不破壞相容性、
    且 SCS-017 §7 本即要求該欄),無設計決策空間(對照 CR-016 §8 之型別修正,同屬「唯一正解」型)。
    若 BEAM PMO 認為仍應先裁定,請指正,本 CR 之修正可隨時回退(單行改動)。
  • 同類風險提示:CR-016 §8 與本 CR 於同一日、同一次 C-14 動工前查證中發現,
    顯示「契約 vs 實作之逐端點核對」尚未形成例行檢查點。
    建議(供裁定):於 CSP-001 或 SCS-000 增列「新增/修改端點時,須逐欄核對回應與契約」之檢查項;
    或於 tools/ 增一支靜態比對器(以 Java DTO 之元件名比對契約 properties)——
    惟後者需先確認可行性(record 元件名可由原始碼解析,屬可行)。
  • 未處理之相鄰議題(僅記錄):ReportJobView 示例之 downloadUrl 為
    https://files.beam-card.internal/rpt/...(正式環境設計意圖),而本期實作為 file://
    (物件儲存未部署,SCS-017 §10.1)。示例為設計意圖、非現況——保留不動,
    但已於 SDD-007 §5.4.12 要求畫面標示「本地開發 stand-in」,避免誤導。

6. 修訂記錄

版本 日期 修訂內容
1.0 2026-09-22 提出並執行。C-14 批次一動工前查證發現 ReportJobView.errorDetail(實作有、契約無);補入產生器 → 重生(僅 report-service.yaml 變動、0 錯誤)→ 真機複驗(200 含該欄)。併提「契約 vs 實作逐端點核對」之檢查點建議
    (1-1/1)