Files
solution-erp/.claude/workflows/runs/2026-07-29-S159-tong-quan-pipeline-menu/cicd-verify-ea962b1.md
2026-07-29 14:53:58 +07:00

14 KiB
Raw Blame History

cicd-verify ea962b1 — S159 ĐỢT-5 "menu 6-leaf y-chang-Duyệt-NCC + GET /contracts/deleted + bỏ hero"

Ghi-TRỌN-RA-ĐĨA (chống #53). Lead /pause — file này là sản phẩm chính, đọc ở phiên sau qua /tiep. Đợt-1 b5799fc PASS 9/9 · đợt-2 1a47a61 PARTIAL 8/9 · đợt-3 2a72695 PASS 9/9 · đợt-4 a2bbcb9 PASS 9/9 — 4 file cũ KHÔNG chạm. Bắt đầu: 2026-07-29 ~14:42+07 · cicd-monitor (READ-only)


M1 — Push + phạm vi · PASS

git log -1 → ea962b1e59432bd6b003836cf0c93bed73732abf
             [CLAUDE] Contract+FE-User: dot-5 menu 6-leaf y-chang-Duyet-NCC
             + GET /contracts/deleted + bo hero + "Tong quan quy trinh"
             2026-07-29 14:40:10 +0700
git log origin/main..HEAD → EMPTY (đã push)

Range ceeebf3..ea962b1 = 10 file, 173+/371 (net âm vì gỡ hero + gỡ code cũ). Khớp brief.

File vai trò
src/Backend/…/Api/Controllers/ContractsController.cs +GET deleted
src/Backend/…/Application/Contracts/ContractFeatures.cs ListDeletedContractsQuery
src/Backend/…/Application/PurchaseEvaluations/PeSoftDeleteFeatures.cs comment
src/Backend/…/Persistence/DbInitializer.cs 🔴 seeder: Ct +3 leaf ×7 · Khkk 6 · labelBackfill · reviewKeys
fe-user/src/pages/UserDashboardPage.tsx BỎ HERO + đổi title
fe-user/src/pages/contracts/MyContractsPage.tsx phase/deleted + guard
fe-user/src/pages/pe/WorkflowMatrixViewPage.tsx matrix + type=3
fe-user/src/App.tsx · fe-user/src/components/Layout.tsx route alias · Ct-regex + staticMap + MenuLeaf-caps
fe-admin/src/components/Layout.tsx staticMap + 2

Cả 2 app FE đều sửa ⇒ bundle 2 app đều phải rotate.

M2 — Migration VẮNG là ĐÚNG · PASS

git diff --name-only ceeebf3..ea962b1 -- '*Migrations*'  →  0

BE thêm query + endpoint + seeder, không schema. Mig giữ 68 / 89 bảng. ⇒ Toàn bộ thay đổi menu đi qua SEEDER lúc app khởi động → rủi ro thật nằm ở M6 (seeder-run).

📌 BASELINE TRƯỚC DEPLOY (đo 14:4114:42+07, run chưa land — pool CHƯA recycle)

Đây là "vế TRƯỚC" để chứng minh seeder thật sự chạy (delta 0→7 rất sắc):

Phép đo TRƯỚC
Ct_%_WfView (MenuItems) 0
Ct_%_Approved 0
Ct_%_Deleted 0
Khkk_% 5
Ct_%_PendingLabel LIKE N'Đang%' 0 (trên tổng 7 key Pending)
DashboardLabel LIKE N'%quy tr%' 0
MenuItems TỔNG 119
38-key set min=13 max=13 keys=38

Bundle trước deploy: admin js CC1pGE1F css DWDbm5As · user js CLfAftby css B6bUSFBt — khớp baseline hậu-đợt-4 ⇒ hợp lệ.

🔎 M3-pre — Marker kỳ vọng (dự đoán TRƯỚC khi đo, khuôn đợt-4)

UserDashboardPage.tsx (50.142 B — đợt-4 là 63.124 B, giảm đúng với "bỏ hero"):

Chuỗi trong UserDashboardPage vai trò
Tổng quan quy trình 1 dương
Toàn trình 4 giai đoạn 0 (hero h2 đã gỡ)
Quy trình mua sắm 0 (eyebrow hero đã gỡ)

⚠️⚠️ CẢNH BÁO: 1 trong 2 control ÂM của brief KHÔNG HỢP LỆ — đã soi TRƯỚC khi đo

grep -rn toàn fe-user/src + fe-admin/src:

fe-user/src/components/pe/PePipelineStrip.tsx:24:   aria-label="Toàn trình 4 giai đoạn"
fe-admin/src/components/pe/PePipelineStrip.tsx:24:  aria-label="Toàn trình 4 giai đoạn"

⇒ Chuỗi Toàn trình 4 giai đoạn VẪN SỐNG trong PePipelineStrip (aria-label, thêm từ đợt-2). Nó KHÔNG độc quyền cho hero ⇒ dự đoán bundle USER = 1, KHÔNG phải 0. Nếu máy móc áp "phải VẮNG" sẽ báo FAIL OAN — trong khi hero thật sự đã gỡ. → Xử lý: coi đây là control KHÔNG dùng được, thay bằng phép đúng ở dưới.

Quy trình mua sắm: grep -rc toàn 2 app = 0 hit ở mọi filecontrol ÂM HỢP LỆ, dự đoán bundle = 0. Đây là phép chứng "hero đã gỡ" đáng tin của lượt này.

(Đúng bài đợt-4: marker phổ-thông/dùng-chung chỉ kết luận "≥1", muốn phép ÂM phải chọn chuỗi ĐỘC QUYỀN.)

🔎 M7-pre — Endpoint mới (đọc code, chốt kỳ vọng)

ContractsController.cs:

[ApiController]
[Route("api/contracts")]      // L12
[Authorize]                   // L13  (class-level)

[HttpGet("deleted")]                        // L28
[Authorize(Policy = "Contracts.Read")]      // L29  (chặt hơn [Authorize] trần)
public async Task<ActionResult<PagedResult<ContractListItemDto>>> ListDeleted()

⇒ URL thật = GET /api/contracts/deleted (brief ghi /contracts/deleted, thiếu prefix api). Kỳ vọng 401 khi không token (route tồn tại) · 404 = FAIL (route không tồn tại). 👍 Ghi nhận: có policy method-level chứ không dựa [Authorize] trần — đúng bài 2-tầng authz (#82).

M4 — Poll terminal · PASS

  • id=539 · run_number=426 · head_sha ea962b1e · created 14:40:15 → status=success 14:45:53
  • Duration 5m38s (đợt 1-4: 5m59s / 5m44s / 5m56s / 5m40s) — ổn định.

M4b — Test gate · 562 EXACT

Passed! - Failed: 0, Passed:  45, Skipped: 0, Total:  45, 151 ms - SolutionErp.Domain.Tests.dll
Passed! - Failed: 0, Passed: 517, Skipped: 0, Total: 517, 1m23s  - SolutionErp.Infrastructure.Tests.dll

Failed! ×0 ⇒ 562. Guard đợt-3 (StillHiddenKeys/ReopenedKeys) nằm trong 517 này, vẫn xanh.

M5 — Bundle · PASS (đo 14:46:14, sau status=success)

App asset TRƯỚC SAU KQ
admin js CC1pGE1F D0sXA0fe ROTATE
admin css DWDbm5As DWDbm5As FROZEN — lành tính (chứng dưới)
user js CLfAftby Y6dW_5CM ROTATE
user css B6bUSFBt 6YIAufJR ROTATE

"Bundle ×2 rotate (cả 2 app đổi)" — đạt qua JS cả 2 app .

USER  index-Y6dW_5CM.js  ct=application/javascript  size=1.595.577  LM=14:45:25+07 (in-window)
ADMIN index-D0sXA0fe.js  ct=application/javascript  size=1.678.823  LM=14:44:29+07 (in-window)
ADMIN index-DWDbm5As.css ct=text/css                size=   83.705  LM=14:44:29+07 (in-window)  ← FROZEN

🔑 admin-css FROZEN nhưng Last-Modified 14:44:29 NẰM TRONG cửa sổ deploy (14:40:15→14:45:53) ⇒ file đã được ghi lại, chỉ là thay đổi fe-admin lần này là staticMap trong Layout.tsx (JS thuần, không thêm class Tailwind mới) nên CSS ra byte y hệt. Đúng khuôn #69 mode-B đã dùng ở đợt-4: frozen + LM-in-window = re-ship giống hệt (khác "bundle cũ kẹt lại" — cái đó LM sẽ cũ).

Control âm 2 tầng: hash CŨ CLfAftby / CC1pGE1F đều → ct=text/html 876/900 B ⇒ bundle đợt-4 đã biến mất khỏi đĩa = chứng ghi-đè thật.

M3 — Byte-marker · PASS (dự đoán TRƯỚC khớp ĐO 100%)

Chuỗi USER ADMIN Kỳ vọng đã chốt trước KQ
Tổng quan quy trình 1 0 dương ở user (chỉ fe-user có)
Quy trình mua sắm 0 0 ÂM (control HỢP LỆ)
Toàn trình 4 giai đoạn 1 1 dự đoán 1, KHÔNG phải 0 đúng dự đoán

🔑 CỨU MỘT FALSE-FAIL — điểm quan trọng nhất lượt này: Brief yêu cầu control âm Toàn trình 4 giai đoạn phải VẮNG. Nếu áp máy móc thì lượt này FAIL OAN, vì đo ra 1. Nhưng tao đã soi TRƯỚC KHI ĐO và biết lý do:

fe-user/src/components/pe/PePipelineStrip.tsx:24:  aria-label="Toàn trình 4 giai đoạn"
fe-admin/src/components/pe/PePipelineStrip.tsx:24: aria-label="Toàn trình 4 giai đoạn"

Chuỗi này không độc quyền cho hero — nó còn sống trong PePipelineStrip (thêm từ đợt-2) dưới dạng aria-label. Hero thật sự đã gỡ (UserDashboardPage chứa 0 lần; file giảm 63.124 → 50.142 B). ⟹ Kết luận: control này KHÔNG DÙNG ĐƯỢC, thay bằng Quy trình mua sắm (eyebrow hero) — grep -rc toàn 2 app = 0 hit ở mọi file ⇒ độc quyền ⇒ bundle = 0chứng hero đã gỡ.

Luật rút ra (nối tiếp đợt-4): trước khi nhận một chuỗi làm control ÂM, phải grep repo-wide xác nhận nó ĐỘC QUYỀN cho thứ mình muốn chứng vắng. Chuỗi dùng-chung chỉ làm marker DƯƠNG.

M6 — 🔴 SEEDER-RUN sau restart · PASS (delta khớp từng đơn vị)

Bước 0 — chứng minh restart THẬT (khuôn 3 chân kiềng, đợt-3):

Bằng chứng Giá trị
Dòng ĐẦU log solution-erp-20260729.log 14:45:37.283 +07:00 [INF] Applying migrations...
w3wp StartTime mới nhất 14:45:32 (và 14:45:31)

Deploy xoá logs/ ⇒ log mở lại 14:45:37 = boot mới; DbInitializer đã chạy. Đo SAU mốc này.

Phép đo TRƯỚC (14:41) SAU (14:46) Δ KQ
Ct_%_WfView 0 7 +7
Ct_%_Approved 0 7 +7
Ct_%_Deleted 0 7 +7
Khkk_% 5 7 +2 (6 leaf + G1)
Ct_%_Pending nhãn N'Đang%' 0/7 7/7 +7 labelBackfill ăn
Dashboard nhãn N'%quy tr%' 0 1 +1
MenuItems TỔNG 119 142 +23
root 12 0 không double-insert
DUPKEYS 0

🔑 Toán khớp từng đồng: +23 = 7 (WfView) + 7 (Approved) + 7 (Deleted) + 2 (Khkk) = 23 . Không có row thừa nào ⇒ seeder insert ĐÚNG tập, không nhân đôi.

Permission cho key MỚI (nhánh insert của reviewKeys — key chưa có row nên insert ăn):

F_NEWPERM  min=13  max=13  keys=21        (21 = 7 WfView + 7 Approved + 7 Deleted)

Mỗi key mới đủ 13/13 role canread. Đây đúng như ghi chú code đợt-3: nhánh grant là skip-existing nên chỉ ăn với key MỚI — lần này key hoàn toàn mới ⇒ grant thành công (khác tình huống đợt-2/3 nơi row false sẵn có không được nâng).

M7 — Endpoint mới GET /api/contracts/deleted · PASS (401, KHÔNG 404)

Probe HTTP Đọc
GET /api/contracts/deleted (no token) 401 route TỒN TẠI, auth chặn đúng
GET /api/contracts/zzznope (route bịa) 404 control — 404 vẫn hoạt động ⇒ 401 ở trên CÓ NGHĨA
GET /api/contracts (route cũ đã biết) 401 nhất quán

🔑control 404 nên 401 không thể là "server trả 401 cho mọi thứ" — discriminator sạch. (Nếu chỉ đo mỗi 401 thì không loại trừ được khả năng catch-all.)

M8 — Restart-durability lần 3 · PASS

Phép đo Kết quả SAU restart KQ
38-key set min=13 max=13 keys=38 · totcr=494/494 GIỮ (lần 3)
Control ÂM Hrm%/Off%/Personal non-Admin canread 0 revoker CÒN SỐNG
Pe% 197 / 185
Hdc_* nhãn - Bảng cứng (%-%) 7 nguyên
3 root ẩn — SUM(IsVisible) 0 cả 3 vẫn ẩn

⚠️ Lưu ý hình-dạng-truy-vấn (quan trọng cho lần sau): đợt này Ct_* đẻ thêm 21 key mới (_WfView/_Approved/_Deleted). Nếu vẫn dùng LEFT(MenuKey,3)='Ct_' như các đợt trước thì "38-key set" sẽ thành 59 keykhông so sánh được với 4 đợt trước. Nên tao cố ý loại 3 hậu tố mới khỏi mệnh đề để giữ đúng tập 38 gốc:

WHERE MenuKey IN (10 key Master-set + 'Contracts')
   OR (LEFT(MenuKey,3)='Ct_'
       AND MenuKey NOT LIKE 'Ct[_]%[_]WfView'
       AND MenuKey NOT LIKE 'Ct[_]%[_]Approved'
       AND MenuKey NOT LIKE 'Ct[_]%[_]Deleted')

⇒ ra đúng 38 key, so được apples-to-apples với đợt 2/3/4. (Bài học query-shape từ đợt-1: khi tập dữ liệu nở ra, phải neo lại phạm vi truy vấn, nếu không con số "tăng" sẽ bị đọc nhầm thành drift.)

M9 — Smoke · PASS 4/4

/health/live 200 Healthy · /health/ready 200 Healthy · admin 200 · eoffice 200

VERDICT: PASS — 9/9

# Mục KQ
1 Push + range 10 file (173+/371, net âm do bỏ hero)
2 Migration VẮNG là ĐÚNG
3 Run #426 success 5m38s
4 Test gate 562 (45+517, 0 fail)
5 Bundle: JS rotate cả 2 app; admin-css frozen chứng minh lành tính bằng LM-in-window
6 Marker Tổng quan quy trình=1 · control ÂM HỢP LỆ Quy trình mua sắm=0
7 SEEDER-RUN: 0→7 ×3 · Khkk 5→7 · Pending-label 7 · Dashboard-label 1 · tổng 119→142 (+23 khớp) · root 12 · DUPKEYS 0 · 21 key mới 13/13
8 Endpoint /api/contracts/deleted = 401 (route sống) + control bịa 404
9 Durability lần 3: 38-key 494/494 · control âm 0 · Pe 197/185 · Hdc nhãn 7 · 3 root ẩn

Không có cờ đỏ. Không khuyến nghị rollback.

⚠️ 1 điểm cần owner biết (KHÔNG phải lỗi deploy)

Control âm Toàn trình 4 giai đoạn trong brief không dùng được — chuỗi vẫn sống hợp lệ ở PePipelineStrip.tsx (aria-label, cả 2 app). Hero đã gỡ đúng (chứng bằng Quy trình mua sắm=0 + UserDashboardPage 63.124→50.142 B). Lần sau nếu muốn phép ÂM cho hero, dùng Quy trình mua sắm.

Baseline mới: admin js D0sXA0fe / css DWDbm5As(frozen hợp lệ) · user js Y6dW_5CM / css 6YIAufJR · gate 562 · Mig 68 / 89 bảng · MenuItems 142 · root 12 · 38-key 13/13 · Ct_ leaf mới 21 key × 13.

Arc S159 — 5 đợt

đợt-1 PASS 9/9 → đợt-2 PARTIAL 8/9 (bắt regression revoker ăn 447/494 row) → đợt-3 PASS 9/9 (đóng regression, 3 chân kiềng) → đợt-4 PASS 9/9 (durability lần 2) → đợt-5 PASS 9/9 (durability lần 3 + seeder-insert delta khớp toán + endpoint mới sống).