Báo cáo sai lệch — batch/create — vòng 1
0. Kết luận nhanh
- Điều kiện đạt:
G1 ✅ G2 ✅ G3 ✅ G4 — G5 ✅ G6 ✅→ CHỜ KIỂM SONAR - Trạng thái: SẴN SÀNG CHO NGƯỜI XEM
- Tầng rủi ro: B → người cần đọc: spec + báo cáo + đoạn bị gắn cờ (mục 3)
- Số quy tắc: 14 · PASS 8 · DEVIATION có chủ đích 4 (R-01/R-12 D-02, R-02 D-01, R-07 D-11, R-13 D-05) · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED 3 (R-06 collation, R-11 dirty-check, R-14 gói dịch vụ)
- Coverage thấp nhất: F-01 100% dòng / 91% nhánh
- Finding logic: CRITICAL 0 · MAJOR 0 · MINOR 3 · UNSURE 0 (không cần xác minh)
- Nghi vấn bug code cũ (mục 3c): 5 (CAO 0) · Quyết định tự chốt cần xác nhận (mục 3d): 9
- Chạy bằng:
/mig-auto(spec dospec-reviewerkiểm 2 lần, chưa có người duyệt) · Số vòng: 1 / lần sửa 0/3
1. Điều kiện đạt
| Mã | Mục tiêu | Kết quả | Bằng chứng |
|---|---|---|---|
| G1 | mvnw verify |
✅ | verify/round-1/build.md (584 test) |
| G2 | Test khớp test-plan | ✅ | verify/round-1/tc-map.md (32/32), oracle.md |
| G3 | Coverage | ✅ | verify/round-1/coverage.md |
| G4 | Sonar | CHỜ NGƯỜI | sonar-ide.md |
| G5 | Finding CRITICAL/MAJOR | ✅ | verify/round-1/review-logic.md (3 MINOR) |
| G6 | Lách cổng | ✅ | verify/round-1/gates.md |
Không chặn nhưng cần người: Integration test CHƯA CHẠY · Golden master CHƯA CHẠY (GM-01)
Coverage theo luồng
| Luồng | Tên | % dòng | % nhánh |
|---|---|---|---|
| F-01 | Lưu lô (tạo; /create kèm id thì sửa) |
100% (252/252) | 91% (91/100) |
2. Ma trận truy vết
| Quy tắc | Tầng | Code mới | Test | Golden | Kết luận |
|---|---|---|---|---|---|
| R-01 | B | BatchSaveRequest, BatchController.create |
TC-01..05 | — | DEVIATION có chủ đích (D-02 body lỗi) |
| R-02 | B | BatchManagementService.requireCompany |
TC-06, 07 | — | DEVIATION có chủ đích (D-01) |
| R-03 | B | BatchExpiryWarning |
TC-08 | — | PASS |
| R-04 | B | BatchDateParser, service |
TC-09..11 | — | PASS |
| R-05 | B | service loadOwnBatch |
TC-12, 13 | GM-01 | PASS (giữ D-04) |
| R-06 | B | service, BatchJpaRepository.findDuplicate |
TC-14..17 | GM-01 | UNVERIFIED (collation, JPQL IS NULL chưa chạy MSSQL) |
| R-07 | B | BatchWriter (khoá + đếm) |
TC-18..21 | GM-01 | DEVIATION có chủ đích (D-11 khoá); giữ D-03 |
| R-08 | B | LegacyCleanText, service |
TC-22, 23 | — | PASS |
| R-09 | B | BatchStatusPolicy |
TC-24 | — | PASS |
| R-10 | B | BatchNormalizedName, service |
TC-25, 26 | — | PASS (giữ D-07) |
| R-11 | B | BatchDirtyCheck, service |
TC-27, 28 | GM-01 | UNVERIFIED (dirty-check Hibernate 5.6, D-08) |
| R-12 | B | controller, BatchItemResponse |
TC-29, 30 | — | PASS (giữ D-09) |
| R-13 | B | service @Transactional, translate |
TC-31, 32 | — | DEVIATION có chủ đích (D-05 417→500) |
| R-14 | B | — | — | — | UNVERIFIED (D-10) |
3. Người cần xem
| # | Vị trí | Vì sao cần người xem |
|---|---|---|
| 1 | infrastructure/relational/batch/adapter/BatchWriter.java:18-53 |
sp_getapplock nhiều lệnh chưa chạy trên MSSQL; chờ > 10 s → 500 (F-logic-2) |
| 2 | BatchWriter.java:68-89, BatchRelationalRepository.java:148-160 |
F-logic-1 (MINOR): nhánh sửa ghi lúc commit, lỗi DB lúc flush không qua translate → có thể ra UNCERTAIN_ERROR thay vì EXCEPTION_ERROR |
| 3 | application/batch/BatchManagementService.java:94-169 |
F-logic-3 (MINOR): dựng giá trị ghi nằm ở application thay vì BatchDraft (domain) như spec mục 5 |
| 4 | BatchJpaRepository.java:27-34 |
JPQL kiểm trùng viết tay thay derived query (Checkstyle ≤ 3 tham số) |
| 5 | BatchDirtyCheck.java, service update |
mô phỏng dirty-check Hibernate 5.6 (D-08) |
| 6 | Các file của batch/detail bị sửa: BatchController, BatchWebMapper, BatchErrorCode, BatchRepository, BatchRelationalRepository, BatchJpaEntity, BatchControllerTest, BatchRelationalRepositoryTest |
K-28: đã chạy lại test và verify đầy đủ — xanh |
| 7 | G4 | Chưa kiểm Sonar |
3b. Phân tích luồng sau chuyển
Chi tiết: verify/round-1/flow-analysis.md
| Luồng | Tên | Số bước KHỚP / KHÁC / CHỈ CÓ Ở CŨ / CHỈ CÓ Ở MỚI | Lệch luồng đã duyệt (spec mục 6) | Điểm dev cần chú ý |
|---|---|---|---|---|
| F-01 | Lưu lô (tạo; /create kèm id thì sửa) | KHỚP 11 / KHÁC 4 (D-01, D-05, D-11 + F-logic-2, F-logic-1) / CHỈ CÓ Ở CŨ 1 (kiểm gói dịch vụ, D-10) / CHỈ CÓ Ở MỚI 0 | không | Câu khoá nhiều lệnh BatchWriter.java:18-53 chưa chạy trên MSSQL thật; nhánh sửa ghi lúc commit ngoài translate (BatchWriter.java:68-89); mô phỏng dirty-check và response trả lotNo thô (BatchManagementService.java:120-150); kiểm trùng viết tay JPQL (BatchJpaRepository.java:27-34) |
3c. Nghi vấn bug / sai ở code cũ (đã GIỮ nguyên khi chuyển)
B-01 Mã lô có thể trùng sau khi xoá lô
- Mức nghi ngờ: TRUNG BÌNH — mã lô lẽ ra duy nhất; các mã khác (kho, sản phẩm) đã chuyển sang bộ đếm riêng.
- Ở đâu: code cũ
base:services/BaseSequenceService.java:337-374→ code mới (giữ)infrastructure/relational/batch/adapter/BatchWriter.java(countByComId),application/batch/BatchManagementService.java(create) - Code cũ đang làm gì: mã lô mới = "LH" + (số lô hiện có của công ty + 1), không kiểm mã đã dùng chưa.
- Ví dụ cụ thể: công ty có
LH1,LH2,LH3; xoáLH2→ còn 2 lô → lô mới được mãLH3, trùng lô đang có. - Vì sao nghi là sai: mã dùng để tìm/in nhãn, trùng mã gây nhầm lô.
- Ảnh hưởng nếu đúng là bug: công ty từng xoá lô sẽ có mã trùng ở mỗi lần tạo tiếp theo cho tới khi số lượng vượt mã lớn nhất.
- Đã xử lý khi chuyển: GIỮ. Test khoá:
TC-19(BatchManagementServiceTest#codeFromCountAfterDelete). - Nếu muốn sửa: dùng bộ đếm (
SequenceService+ seedmax(mã)) ởBatchManagementService.create; đổi TC-18, TC-19. Hệ thống cũ chạy song song vẫn sinh mã theo đếm → hai bên có thể đụng mã. - Liên quan: D-03, R-07
B-02 Thêm số lô có dấu cách đầu lọt kiểm trùng
- Mức nghi ngờ: TRUNG BÌNH
- Ở đâu: code cũ
backend:service/impl/BatchesManagementServiceImpl.java:206-217→ code mớiBatchManagementService.save(findDuplicatevới số lô thô) - Code cũ đang làm gì: so trùng bằng số lô chưa làm sạch rồi mới làm sạch khi lưu.
- Ví dụ cụ thể: đã có lô
A1(không NSX, HSD 2026-12-31). Thêm" A1"cùng ngày → không báo trùng, lưu thànhA1→ có 2 lôA1. Lần thêmA1sau đó → lỗi hệ thống 500 thay vì báo trùng. - Vì sao nghi là sai: mục đích kiểm trùng bị vô hiệu bởi khoảng trắng.
- Ảnh hưởng nếu đúng là bug: dữ liệu lô trùng; về sau thêm/sửa đúng số lô đó lỗi hệ thống.
- Đã xử lý khi chuyển: GIỮ. Test khoá:
TC-15 (a)(BatchManagementServiceTest#duplicateKeyUsesRawLotNo),TC-17. - Nếu muốn sửa: truyền
LegacyCleanText.clean(lotNo)vàoBatchDuplicateKey; đổi TC-15 (a). - Liên quan: D-06, R-06
B-03 /create kèm id sửa lô có sẵn
- Mức nghi ngờ: THẤP — có thể có chủ đích (dùng chung hàm lưu).
- Ở đâu: code cũ
backend:web/rest/BatchesManagementResource.java:40-52→ code mớiBatchController.create→BatchManagementService.save - Code cũ đang làm gì: API "thêm" gửi kèm
idsẽ sửa lô đó. - Ví dụ cụ thể:
POST /create {"id":5,"comId":10,"lotNo":"B2",…}→ lô 5 đổi số lô thànhB2, trả "Cập nhật thành công!". - Vì sao nghi là sai: tên API là thêm.
- Ảnh hưởng nếu đúng là bug: client gửi nhầm
idsẽ sửa dữ liệu. - Đã xử lý khi chuyển: GIỮ. Test khoá:
TC-12,TC-13(BatchManagementServiceTest#idOfOtherCompany,#createWithIdUpdates). - Nếu muốn sửa: controller
/createbỏidkhi map command; đổi TC-13. - Liên quan: D-04, R-05
B-04 Tab trong số lô làm tên tìm kiếm có dấu cách
- Mức nghi ngờ: THẤP
- Ở đâu: code cũ
backend:util/Common.java:1315-1329+CleanTextListener→ code mớiBatchNormalizedName,BatchManagementService - Code cũ đang làm gì: tên chuẩn hoá tính trên số lô thô (chỉ xoá dấu cách thường), sau đó làm sạch đổi tab thành dấu cách.
- Ví dụ cụ thể: số lô
"A<tab>B"→ lưulot_no="A B",normalized_name="lh6|a b"→ tìm "ab" trong danh sách lô không ra. - Vì sao nghi là sai: tên chuẩn hoá lẽ ra không còn dấu cách.
- Ảnh hưởng nếu đúng là bug: hiếm (cần dán tab vào ô số lô).
- Đã xử lý khi chuyển: GIỮ. Test khoá:
TC-26 (a)(BatchManagementServiceTest#tabInLotNo). - Nếu muốn sửa: tính tên chuẩn hoá trên giá trị đã làm sạch; đổi TC-26 (a).
- Liên quan: D-07, R-10
B-05 Sửa lô trả số lô chưa làm sạch
- Mức nghi ngờ: THẤP
- Ở đâu: code cũ
backend:service/impl/BatchesManagementServiceImpl.java:248-258→ code mớiBatchManagementService.update - Code cũ đang làm gì: khi sửa, response dựng trước khi lưu nên trả số lô đúng như client gửi; DB lưu bản đã làm sạch.
- Ví dụ cụ thể: sửa số lô
" A 1 "→ response" A 1 ", DB"A 1". - Vì sao nghi là sai: response khác dữ liệu đã lưu (khi tạo thì đã làm sạch).
- Ảnh hưởng nếu đúng là bug: giao diện hiển thị khác tới khi tải lại.
- Đã xử lý khi chuyển: GIỮ. Test khoá:
TC-30 (b)(BatchManagementServiceTest#updatedItemHasRawLotNo). - Nếu muốn sửa: dùng giá trị đã làm sạch trong
BatchManagementService.update; đổi TC-30 (b). - Liên quan: D-09, R-12
3d. Quyết định AI tự chốt và thay đổi tự động (cần người xác nhận)
| # | Nguồn | AI đã làm gì | Khác code cũ ở điểm nào (input → cũ / mới) | Người cần xác nhận gì |
|---|---|---|---|---|
| 1 | spec-review | Spec qua 2 lần review (lần 2 thu hẹp); đã sửa theo CRITICAL/MAJOR: R-07, R-08, R-10, R-12, R-13, D-03, D-07, thêm D-11 | — | Đọc kỹ R-07, R-08, R-10 |
| 2 | D-11 (LỖI KỸ THUẬT) + F-logic-2 | Khoá sp_getapplock theo công ty trước khi đếm mã |
2 request tạo cùng lúc (5 lô) → cũ LH6,LH6 / mới LH6,LH7; chờ khoá > 10 s → cũ vẫn tạo / mới 500 không ghi |
Chấp nhận khoá và thời gian chờ 10 s |
| 3 | D-01 (PHỤ THUỘC NGOÀI) | Chỉ giữ 2 kiểm token/công ty | token cũ sau đổi mật khẩu → cũ 500 TOKEN_EXPIRED / mới tạo lô |
Chấp nhận |
| 4 | D-02 (ADR BẮT KHÁC) | Body theo starter | trùng lô → cũ có "data":null / mới không có key data; body hỏng → cũ 400 rỗng / mới INVALID_REQUEST |
Client không phụ thuộc key data khi trùng |
| 5 | D-05 (ADR BẮT KHÁC) | 417 → 500 giữ EXCEPTION_ERROR |
2 lô trùng sẵn → cũ 417 / mới 500 | Client không xử lý riêng 417 |
| 6 | D-08 (MƠ HỒ) | Mô phỏng dirty-check: chỉ ghi updater/update_time khi giá trị thô khác DB |
sửa không đổi gì → cả hai không ghi (UNVERIFIED) | Chạy GM-01 xác nhận |
| 7 | D-10 (PHỤ THUỘC NGOÀI) | Không kiểm gói dịch vụ | công ty hết hạn dùng thử → cũ 400 / mới tạo lô | Gói kiểm ở gateway? |
| 8 | spec mục 7 | Câu đếm mã lỗi do timeout: cũ có thể vẫn lưu LH1 (Hibernate không rollback-only với timeout) / mới 500 không ghi |
UNVERIFIED | Chấp nhận |
| 9 | impl-notes giả định 1 | JPQL (:x IS NULL AND col IS NULL) OR col = :x thay derived query |
cùng ngữ nghĩa (chưa chạy MSSQL) | Chạy GM-01 |
4. Finding đã xác nhận
Không có finding CRITICAL/MAJOR. Ba finding MINOR (không qua xác minh, không sửa trong vòng lặp):
F-logic-1
- Mức độ: MINOR · Loại: transaction · Quy tắc: R-13 (nhánh sửa)
- Mô tả: nhánh sửa ghi UPDATE lúc commit, ngoài
translate→ lỗi DB lúc flush có thể raUNCERTAIN_ERRORthay vìEXCEPTION_ERROR. Đề xuấtentityManager.flush()trongBatchWriter.saveở nhánh sửa. Chi tiết:verify/round-1/review-logic.md.
F-logic-2
- Mức độ: MINOR · Loại: parity · Quy tắc: R-07 (D-11)
- Mô tả: chờ khoá > 10 s → 500, không ghi; cũ không có nhánh này. Đã đưa vào 3d #2.
F-logic-3
- Mức độ: MINOR · Loại: architecture · Quy tắc: R-08, R-11
- Mô tả: không có
BatchDraft(domain) như spec mục 5; dựng giá trị ghi nằm ở application service.
5. Finding bị loại
Không có.
6. Xử lý của người
| Vấn đề | Cổng | Chỉ thị |
|---|---|---|
| Chưa kiểm Sonar | G4 | |
F-logic-1 (MINOR) — flush nhánh sửa trong translate |
— (không chặn) | |
F-logic-3 (MINOR) — tách BatchDraft sang domain |
— (không chặn) |
7. So với vòng trước
Vòng đầu.
8. Thay đổi trong repo đích
28 file (verify/round-1/changed-files.md): 22 file src/main/java (16 mới, 6 sửa — các file sửa thuộc batch/detail), 2 file i18n, 4 file test. Không có file ngoài phạm vi.
9. Đề xuất bổ sung kinh nghiệm
| Đề xuất | Đưa vào đâu |
|---|---|
ArchUnit R13 chặn cả sealed interface tên *Result → kết quả nhiều nhánh viết thành record có cờ + factory |
lessons.md 1b |
Spring Data derived query 4 tham số vi phạm Checkstyle → @Query JPQL + SpEL trên một object tham số, giữ IS NULL bằng (:x IS NULL AND col IS NULL) OR col = :x |
lessons.md 1b |
LF-31: ghi rõ \n,\r bị xoá hẳn (không thành dấu cách) — spec lần 1 hiểu sai |
legacy-facts.md LF-31 |
catch nuốt lỗi JPA trong transaction chung vẫn rollback-only, trừ QueryTimeoutException/LockTimeoutException (Hibernate không đánh dấu) |
lessons.md K-03 |
Sinh mã LH (lô) đếm bảng, không qua Redis — thêm vào LF-42 |
legacy-facts.md LF-42 |