[CLAUDE] PurchaseEvaluation: Mig 61 backfill EndedByLevelFinalize từ Changelogs (fix Mig 60 wrong-table) — phiếu finalize-CCM hết hiện sai "Đã được CEO duyệt" (anh Kiệt FDC UAT)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m12s

- Root-cause: Mig 60 backfill query PurchaseEvaluationApprovals cho marker "[Duyệt KẾT THÚC tại]", nhưng marker do LogTransitionAsync ghi vào PurchaseEvaluationChangelogs (approval-history là record riêng dòng :745) → match 0 dòng
- Phiếu finalize-sớm pre-Mig60 (PE/2026/A/005, A/008 — CCM Cấp 2 Phan Văn Chương duyệt-thay-CEO, KHÔNG qua CEO) giữ EndedByLevelFinalize=0 → endsBeforeCeo=False → badge SAI "Đã được CEO duyệt"
- Mig 61: backfill ĐÚNG bảng Changelogs (ContextNote LIKE N'%Duyệt KẾT THÚC tại%' + PhaseAtChange=7), idempotent, SQL-Server-only (tests SQLite no-replay)
- Verified prod: A/005/A/008 fin_marker=1 (finalize CCM) vs A/010 fin_marker=0 (CEO thật). gotcha #79

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-01 21:30:30 +07:00
parent 21be786c9e
commit fb2dfa9f7a
3 changed files with 6325 additions and 0 deletions

View File

@ -1322,6 +1322,14 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
**Fix (root-cause, Mig 60 `8037fa0`):** thêm field RUNTIME `EndedByLevelFinalize` (set true CHỈ nhánh level-finalize service) `EndsBeforeCeo` cho phiếu DaDuyet đọc runtime thay config (ChoDuyet giữ heads-up config); FE gate làm-mờ theo `endsBeforeCeo`; backfill marker "Duyệt KẾT THÚC tại". prod-verified Run #482 (PE-detail endsBeforeCeo=False live). **Quy tắc:** flag hiển-thị/trạng-thái = "instance NÀY ĐÃ làm-gì" (RUNTIME) KHÔNG "workflow THỂ làm-gì" (CONFIG); config-flag chỉ đúng khi instance không-bao-giờ-lệch-config đổi default opt-in/opt-out làm lệch phổ-biến soi lại mọi display suy-từ-config. Liên-quan `feedback_cardinality_change_grep_consumers` · `feedback_root_cause_over_symptom`. **Fix (root-cause, Mig 60 `8037fa0`):** thêm field RUNTIME `EndedByLevelFinalize` (set true CHỈ nhánh level-finalize service) `EndsBeforeCeo` cho phiếu DaDuyet đọc runtime thay config (ChoDuyet giữ heads-up config); FE gate làm-mờ theo `endsBeforeCeo`; backfill marker "Duyệt KẾT THÚC tại". prod-verified Run #482 (PE-detail endsBeforeCeo=False live). **Quy tắc:** flag hiển-thị/trạng-thái = "instance NÀY ĐÃ làm-gì" (RUNTIME) KHÔNG "workflow THỂ làm-gì" (CONFIG); config-flag chỉ đúng khi instance không-bao-giờ-lệch-config đổi default opt-in/opt-out làm lệch phổ-biến soi lại mọi display suy-từ-config. Liên-quan `feedback_cardinality_change_grep_consumers` · `feedback_root_cause_over_symptom`.
### 79. Backfill marker soi NHẦM bảng — transition-marker ở Changelogs KHÔNG phải Approvals (Session 97)
**Triệu chứng:** Mig 60 backfill `EndedByLevelFinalize` (nhận diện phiếu finalize-sớm qua marker "[Duyệt KẾT THÚC tại...]") match **0 dòng** trên prod phiếu finalize pre-Mig60 (PE/2026/A/005, A/008) giữ `=0` hiển thị SAI "Đã được CEO duyệt" thay "Kết thúc tại CCM".
**Cơ chế:** 2 bảng lịch-sử RIÊNG trong PE workflow: (1) `PurchaseEvaluationApprovals` = record per-approver (thêm main-flow `ApproveV2Async:745`, comment "[Bước X Cấp Y] {user}"); (2) `PurchaseEvaluationChangelogs` = transition-log (`LogTransitionAsync:1073` "chỉ log Changelog đây", ContextNote = marker "[Duyệt KẾT THÚC tại...không trình CEO]"). Marker finalize CHỈ nằm Changelogs. Backfill query `Approvals.Comment LIKE '%KẾT THÚC%'` sai bảng 0 match. (Bonus: approval-record `ToPhase=evaluation.Phase` chụp TRƯỚC khi terminal-branch đổi Phase MỌI approval-record `ToPhase=ChoDuyet`; terminal chỉ ghi Changelog `PhaseAtChange=DaDuyet` đừng tìm `ToPhase=7` Approvals.)
**Fix (Mig 61 `BackfillEndedByLevelFinalizeFromChangelog`):** query ĐÚNG `PurchaseEvaluationChangelogs.ContextNote LIKE N'%Duyệt KẾT THÚC tại%'` + `PhaseAtChange=7`. **Quy tắc:** trước khi viết backfill/query dựa "transition-marker", XÁC ĐỊNH bảng nào thực-sự lưu marker (đọc code writer) PE 2 bảng lịch sử tách vai (Approvals=ai-duyệt · Changelogs=chuyển-phase+marker). Verify marker-count trên prod TRƯỚC khi tin backfill. Liên-quan #78 · #64 (data-migrate Sql prod).
--- ---
## Checklist debug bug mới ## Checklist debug bug mới

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SolutionErp.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class BackfillEndedByLevelFinalizeFromChangelog : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// [S97 anh Kiệt FDC — data-fix] Mig 60 backfill soi NHẦM bảng: nó query
// PurchaseEvaluationApprovals cho marker "[Duyệt KẾT THÚC tại...]", nhưng marker đó do
// LogTransitionAsync ghi vào PurchaseEvaluationChangelogs.ContextNote (approval-history
// là record RIÊNG ở dòng :745, LogTransition CHỈ ghi Changelog dòng :1073). → Mig 60
// match 0 dòng; phiếu finalize-sớm PRE-Mig60 (vd PE/2026/A/005, A/008 — Phan Văn Chương
// duyệt-thay-CEO tại CCM Cấp 2, KHÔNG qua CEO) giữ EndedByLevelFinalize=0 → hiển thị SAI
// "Đã được CEO duyệt" thay vì "Kết thúc tại CCM". Đính chính: set =1 cho phiếu DaDuyet có
// Changelog terminal (PhaseAtChange=7) chứa marker finalize. Idempotent (WHERE ...=0).
// SQL-Server-only (tests SQLite EnsureCreated no-replay migration, gotcha #63). Gotcha #79.
migrationBuilder.Sql(@"
UPDATE pe SET EndedByLevelFinalize = 1
FROM PurchaseEvaluations pe
WHERE pe.Phase = 7 AND pe.EndedByLevelFinalize = 0
AND EXISTS (
SELECT 1 FROM PurchaseEvaluationChangelogs c
WHERE c.PurchaseEvaluationId = pe.Id
AND c.PhaseAtChange = 7
AND c.ContextNote LIKE N'%Duyệt KẾT THÚC tại%');");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
// Data-fix đính chính (Mig 60 wrong-table) — KHÔNG reverse (không snapshot trạng thái
// trước; revert = tái tạo lỗi). No-op an toàn.
}
}
}