Báo cáo sai lệch — inventory/listener-cogs-completion — vòng 1
0. Kết luận nhanh
- Điều kiện đạt:
G1 ✅ G2 ✅ G3 ✅ G4 — G5 ✅ G6 ✅ → CHỜ KIỂM SONAR (máy đạt hết, chờ người kiểm G4)
- Trạng thái: SẴN SÀNG CHO NGƯỜI XEM
- Tầng rủi ro: A (ghi
cogs_history, sinh task log cập nhật đơn giá phiếu/hoá đơn) → người cần đọc: spec + báo cáo + toàn bộ diff
- Số quy tắc: 9 · PASS 4 (R-02, R-04, R-05, R-08) · DEVIATION có chủ đích 4 (R-01 D-04/D-09, R-03 D-01, R-06 D-09 của cogs-calculate, R-07 D-06/D-07) · DEVIATION KHÔNG chủ đích 0 · UNVERIFIED một phần R-01 (hành vi container), R-06 (
ppuIds rỗng); R-09 PASS sau khi sửa adapter của cogs-calculate
- Coverage thấp nhất: F-01 100% dòng / 96.2% nhánh
- Finding logic: CRITICAL 0 · MAJOR 0 · MINOR 3 · UNSURE 0
- Nghi vấn bug code cũ (mục 3c): 1 (CAO 0) — kèm nhắc lại 2 nghi bug CAO của
cogs-calculate có hiệu lực khi bật listener · Quyết định tự chốt cần xác nhận (mục 3d): 9
- Chạy bằng:
/mig-auto lượt 20261105-2144 (spec qua 2 lần spec-reviewer, chưa có người duyệt) · Số vòng: 1 verify / lần sửa 0/3
- Phạm vi còn nghi vấn (❓) — listener của API
cogs/calculate (mục 1.2 ❓) và "easyposasync ❓" (mục 1.7).
- Unit này sửa code và test-plan của unit
inventory/cogs-calculate (adapter task log + TC-38) — xem mục 3d dòng 1.
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 (738 test, SpotBugs 0, ArchUnit 36/36) |
| G2 |
Test khớp test-plan |
✅ |
verify/round-1/oracle.md (23/23 TC tự động; TC-17 UNVERIFIED theo test-plan) |
| G3 |
Coverage mỗi luồng |
✅ |
verify/round-1/coverage.md |
| G4 |
Sonar |
CHỜ NGƯỜI |
sonar-ide.md |
| G5 |
0 CRITICAL/MAJOR |
✅ |
verify/round-1/review-logic.md (chỉ MINOR, không cần xác minh) |
| G6 |
Không lách cổng |
✅ |
verify/round-1/gates.md; 16 file đều có trong impl-notes.md |
Không chặn nhưng cần người: chạy thử với RabbitMQ/Mongo thật CHƯA CHẠY · Golden master GM-01 CHƯA CHẠY (tầng A).
Coverage theo luồng
| Luồng |
Tên |
% dòng |
% nhánh |
| F-01 |
Nhận message, đọc task log, ghi kết quả, ack/nack |
100.0% (86/86) |
96.2% (25/26) |
| F-02 |
Tính giá vốn từ nội dung task log |
100.0% (10/10) |
N/A (0/0) |
2. Ma trận truy vết
| Quy tắc |
Tầng |
Code mới |
Test |
Golden |
Kết luận |
| R-01 |
A |
CogsCompletionConsumer |
TC-01, 02 |
GM-01 |
DEVIATION (có chủ đích, D-04, D-09); hành vi container UNVERIFIED |
| R-02 |
C |
CogsCompletionConsumer |
TC-03 |
— |
PASS (D-02 GIỮ) |
| R-03 |
B |
CogsCompletionTaskService, CogsTaskLogMongoStore.find |
TC-04..07, 21 |
— |
PASS — giữ NGHI BUG D-01 |
| R-04 |
A |
CogsCompletionTaskService |
TC-08, 09 |
— |
PASS (D-05 lệch ADR-0301 có chủ đích) |
| R-05 |
B |
CogsTaskLogMongoStore.parseCompletion |
TC-10..12 |
— |
PASS (text lỗi parse khác — F-logic-2) |
| R-06 |
A |
CogsCompletionTaskService.compute, CogsTaskPeriod, CogsComputationService |
TC-13..16 |
GM-01 |
PASS; ppuIds rỗng UNVERIFIED |
| R-07 |
A |
CogsCompletionTaskService, CogsTaskLogMongoStore.markResult |
TC-18..22 |
GM-01 |
DEVIATION (có chủ đích, D-06 text lỗi, D-07 $set) |
| R-08 |
A |
CogsComputationService.calculate |
TC-23 |
— |
PASS |
| R-09 |
C |
CogsTaskLogMongoRabbitAdapter (sửa) |
TC-24 |
GM-01 |
PASS |
3. Người cần xem
| # |
Vị trí |
Vì sao cần người xem |
| 1 |
Toàn bộ diff (verify/round-1/changes.diff, 16 file) |
Tầng A |
| 2 |
…/infrastructure/messaging/CogsTaskLogMongoRabbitAdapter.java:131-133 + test TC-38 |
Đổi hành vi unit cogs-calculate (không user → creator/updater = 0), test-plan/spec unit đó sửa theo code cũ — migrations/inventory/cogs-calculate/auto-changes.md |
| 3 |
…/presentation/messaging/CogsCompletionConsumer.java |
Cần bật cả app.rabbit.listener.enabled=true và app.rabbitmq.activate=enabled (container MANUAL của starter); nếu cả async cũ và service mới cùng bật → 2 consumer tranh một queue |
| 4 |
F-logic-1 (MINOR) |
content = "null" → error_message là message NPE của Java mới thay vì không có field (producer không ghi như vậy) |
| 5 |
F-logic-2 (MINOR) |
Text lỗi đọc JSON khác (Jackson mới ẩn "Source") |
| 6 |
F-logic-3 (MINOR) |
Ghi kết quả không upsert: document bị xoá giữa chừng thì cũ tạo lại, mới không |
| 7 |
UNVERIFIED |
Hành vi container spring-amqp MANUAL khi listener ném lỗi; converter của starter; ppuIds rỗng |
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 |
Nhận message, đọc task log, ghi kết quả, ack/nack |
6 / 3 (D-04/D-09, D-06, D-07) / 2 (APM, BaseRequestContext — D-08) / 0 |
không |
thứ tự kiểm null; $set không upsert; bật cờ starter; sửa adapter cogs-calculate |
| F-02 |
Tính giá vốn từ nội dung task log |
5 / 1 (from/to giờ VN — D-09 cogs-calculate) / 0 / 0 |
không |
norm theo zone message, from/to giờ VN; task log gửi trước commit |
3c. Nghi vấn bug / sai ở code cũ (đã GIỮ nguyên khi chuyển)
B-01 Task log không còn: message bị treo, không bao giờ được dọn
- Mức nghi ngờ: TRUNG BÌNH — chỉ xảy ra khi document bị xoá hoặc id sai, nhưng mỗi message như vậy chiếm một chỗ prefetch tới khi consumer khởi động lại, rồi lại treo.
- Ở đâu: code cũ
async:src/main/java/sds/ep/async/queueListener/CogsCompletionListener.java:61-65 → code mới (giữ nguyên) …/application/cogs/CogsCompletionTaskService.java:40-41, …/presentation/messaging/CogsCompletionConsumer.java
- Code cũ đang làm gì: không tìm thấy task log thì ném lỗi ra ngoài; vì chế độ ack thủ công nên message không được xác nhận cũng không bị bỏ.
- Ví dụ cụ thể: queue có 10 message mà document đã bị xoá, prefetch 10 → consumer giữ 10 message "chưa xác nhận" và không nhận thêm message mới trên kênh đó tới khi khởi động lại.
- Vì sao nghi là sai: message lỗi vĩnh viễn nên được bỏ hoặc đưa vào DLQ, không giữ mãi.
- Ảnh hưởng nếu đúng là bug: tính giá vốn chậm/ngừng cho các message sau trên cùng kênh.
- Đã xử lý khi chuyển: GIỮ. Test khoá: TC-04 (
CogsCompletionConsumerTest#missingTaskLogNotAcked, CogsCompletionTaskServiceTest#missingTaskLog).
- Nếu muốn sửa: consumer bắt
TASK_LOG_NOT_FOUND và basicNack(requeue=false); đổi TC-04.
- Liên quan: D-01, R-03
Nhắc lại (không tính vào số B của unit này): cogs-calculate B-01, B-02 (mức CAO) mô tả hậu quả "nếu consumer easyposasync bật". Trong code đã commit của easyposasync — cả 1119968c (branch deployRefWarehousePro, checkout lúc lượt 20261105-1351 chạy) lẫn 2fa9b05 (branch deploy20260519, hiện tại) — @RabbitListener của 2 consumer không bị comment, bật theo cờ app.rabbit.listener.enabled (ENABLE_QUEUE_AND_SCHEDULE). Reflog repo nguồn có reset: moving to HEAD lúc 21:42 rồi đổi branch: nhiều khả năng lượt trước đọc thay đổi chưa commit trong working tree (dòng //@RabbitLisstener), nay đã mất — không kiểm lại được. Code chạy trên prod là code đã deploy → người xác nhận cờ prod rồi xem lại B-01, B-02 của cogs-calculate.
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 |
auto-changes (cogs-calculate) |
Sửa adapter task log của cogs-calculate + TC-38 + spec R-15 của unit đó theo code cũ |
không user → cũ creator/updater = 0; cogs-calculate trước đây không ghi key — nay ghi 0 như cũ |
Đồng ý sửa chéo unit; xem migrations/inventory/cogs-calculate/auto-changes.md |
| 2 |
D-05 |
Không dùng IdempotencyStore (lệch ADR-0301 có chủ đích), chống trùng bằng status |
không khác cũ |
Chốt ngoại lệ ADR-0301 cho consumer này |
| 3 |
D-02 |
Giữ chờ 2 s (cấu hình app.rabbitmq.cogs.listener-delay-ms) |
không khác |
Có cần giữ chờ không |
| 4 |
D-03 |
Lỗi → nack không requeue, không retry |
không khác |
Broker có DLX cho queue này không |
| 5 |
D-04 |
Cờ app.rabbit.listener.enabled (mặc định tắt) |
không khác |
Bật ở service nào khi triển khai |
| 6 |
D-06 |
error_message: ngày/ppuIds null → không field (như cũ); lỗi khác → message của cause |
config.business_type = "99" → cũ "…BaseInternalServerException…BUSINESS_NOT_EXISTS" / mới "EXCEPTION_ERROR" |
Chấp nhận mất mã nguyên nhân trong error_message |
| 7 |
D-07 |
Ghi kết quả bằng $set (status, error_message, update_time, updater 0) |
không upsert (F-logic-3) |
Chấp nhận |
| 8 |
D-08 |
Bỏ APM name, đếm retry, BaseRequestContext.clear() |
chỉ giám sát |
Chấp nhận |
| 9 |
D-09 |
Dùng container mặc định của starter-config |
cấu hình theo app.rabbitmq.*, không spring.rabbitmq.* (sửa hướng dẫn D-07 của cogs-calculate) |
Bổ sung cấu hình khi triển khai |
Spec qua 2 lần review (lần 1 và 2 đều có CRITICAL); mọi finding đã CHẤP NHẬN, không còn CHƯA QUYẾT.
4. Finding đã xác nhận
Không có finding CRITICAL/MAJOR. MINOR (không qua xác minh): F-logic-1, F-logic-2, F-logic-3 — nguyên văn ở verify/round-1/review-logic.md.
5. Finding bị loại
6. Xử lý của người
| Vấn đề |
Cổng |
Chỉ thị |
Kiểm Sonar trong IDE (sonar-ide.md) |
G4 |
|
7. So với vòng trước
Vòng đầu.
8. Thay đổi trong repo đích
16 file (verify/round-1/changed-files.md): 9 file main (6 mới — consumer, service, port, Mongo store, CogsTaskPeriod, CogsTaskOutcome/CogsTaskLogEntry; sửa CogsErrorCode, CogsTaskLogMongoRabbitAdapter của cogs-calculate), i18n vi/en, 5 lớp test (4 mới, sửa CogsTaskLogMongoRabbitAdapterTest TC-38). Chưa thêm khoá cấu hình vào yml.
9. Đề xuất bổ sung kinh nghiệm (/mig-learn gom vào proposal để người duyệt)
| Đề xuất |
Đưa vào đâu |
App monolith quét sds.ep.baseservice → kéo theo EasyPosBaseApplication → sds.ep.configservice (@EnableMongoAuditing, auditor 0 khi không token): Mongo document luôn có creator/updater, save đặt update_time |
legacy-facts.md (LF mới) |
CacheIdempotencyStore.checkAndMark trả false khi Redis lỗi — không dùng làm điều kiện "đã xử lý" khi code cũ không có Redis |
lessons.md / review-criteria |
Repo đích chạy Java mới: NPE có message (helpful NPE), Java 11 cũ là null — mọi chỗ ghi e.getMessage() ra dữ liệu cần kiểm |
lessons.md |
Consumer Rabbit: dùng container rabbitListenerContainerFactory của starter-config (MANUAL) — cần app.rabbitmq.activate=enabled |
target-cheatsheet.md |