wal: flush 20260729T1932
This commit is contained in:
@ -10,7 +10,8 @@ chain:
|
|||||||
- [x] 3 quyết owner @S161: (1) mã phiếu OK `KHKK/{YYYY}/{Seq:D3}` · (2) "Bỏ cái MB đi" → dry-run cấm HĐ MuaBan + codegen = nợ tuyên án · (3) GĐ4 = 1-MỐC (verbatim "Upload file cứng lên -> Là xem như xong") — khắc vào plan-cha #6/#7/#8/#9 + W1/W2/W5/W7 (16 edit)
|
- [x] 3 quyết owner @S161: (1) mã phiếu OK `KHKK/{YYYY}/{Seq:D3}` · (2) "Bỏ cái MB đi" → dry-run cấm HĐ MuaBan + codegen = nợ tuyên án · (3) GĐ4 = 1-MỐC (verbatim "Upload file cứng lên -> Là xem như xong") — khắc vào plan-cha #6/#7/#8/#9 + W1/W2/W5/W7 (16 edit)
|
||||||
- [x] gate 5-anchor W1 PASS 5/5 (mở tươi @S161 — slot 10 trống · :41 const · ∉All · :138-139 lưới · :1779-1786 seed)
|
- [x] gate 5-anchor W1 PASS 5/5 (mở tươi @S161 — slot 10 trống · :41 const · ∉All · :138-139 lưới · :1779-1786 seed)
|
||||||
- [x] wf đợt-1 `wf_7d6fb81b-640`: FE lane CLEAN (Designer type-10, containment 2-lớp, build tươi lead-verify PASS, đã harvest) · BE lane chết #53 sau Domain-layer (8 entity + type-10 + 4/7 config trên đĩa, 0 sub-md)
|
- [x] wf đợt-1 `wf_7d6fb81b-640`: FE lane CLEAN (Designer type-10, containment 2-lớp, build tươi lead-verify PASS, đã harvest) · BE lane chết #53 sau Domain-layer (8 entity + type-10 + 4/7 config trên đĩa, 0 sub-md)
|
||||||
- [!] wf: RELAUNCH-CẮT-GỌT BE `wf_f8c806d2-5a3` ĐANG CHẠY — còn {3 config · DbSets · Mig 69 · MenuKeys All+= · seeder UPGRADE · CodeGen KHKK · 3 site AWV2Admin · build} — run-folder `.claude/workflows/runs/2026-07-29-S161-khkk-w1-schema/`
|
- [x] wf BE `wf_f8c806d2-5a3` chết #53 lần 2 NHƯNG sub-md ghi-từng-mục cứu trọn (Mig 69 apply 2 DB, 96 bảng) → lead solo đuôi {seeder SeedKeHoachKyKetAccessAsync + CodeGen KHKK + DI + 3 site AWV2Admin} → **build 0W/0E 47s**; harvest 2 diary on-behalf xong
|
||||||
|
- [!] wf: ĐỢT-2 `wf_a95c9909-14b` ĐANG CHẠY — {test-specialist: SchemaTests + CodeGen format A6 · database-agent: design-review Mig 69} — sau đó: lead acceptance (dotnet test ≥564 · Down-script · đo CỜ) → reviewer → commit/push → cicd
|
||||||
- [ ] đợt-2 SAU khi wf về: test-specialist + database-agent (song song) → lead acceptance §③-B (build·test·sqlcmd 96·Down sạch·đo CỜ) → reviewer → commit/push → cicd-monitor 3-chân-kiềng
|
- [ ] đợt-2 SAU khi wf về: test-specialist + database-agent (song song) → lead acceptance §③-B (build·test·sqlcmd 96·Down sạch·đo CỜ) → reviewer → commit/push → cicd-monitor 3-chân-kiềng
|
||||||
- [ ] setup thủ công TRƯỚC W5 (SAU W1 vì type=10 cần mig 69): dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm)
|
- [ ] setup thủ công TRƯỚC W5 (SAU W1 vì type=10 cần mig 69): dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm)
|
||||||
- [ ] housekeeping @pause/closeout kế: nén MIND-1 5.447B (trần `_mind` 83,2% — MIND-5 chắc vượt) · re-carry 2 ý D rơi (vá-GỐC-Phase-3.5-refresh {mới-nêu} CÒN SỐNG + khuôn-5-đợt→sổ bền {gần-chốt}) · STATUS:6 bổ arc dry-run S160 (mù có lý do — land 15:27 trước pipeline) · hạ nhãn DR/WF-3-trạm đã-định-đoạt · E đếm 7 sub-file (không 6) · mở lại slot-45 trần `_mind` (tiền-đề lật: file SỐNG 83,2%) · quyết bookkeeping OVERDUE:light (cặp H24 chạy @S159 bookend mà `last_audit` đứng 27)
|
- [ ] housekeeping @pause/closeout kế: nén MIND-1 5.447B (trần `_mind` 83,2% — MIND-5 chắc vượt) · re-carry 2 ý D rơi (vá-GỐC-Phase-3.5-refresh {mới-nêu} CÒN SỐNG + khuôn-5-đợt→sổ bền {gần-chốt}) · STATUS:6 bổ arc dry-run S160 (mù có lý do — land 15:27 trước pipeline) · hạ nhãn DR/WF-3-trạm đã-định-đoạt · E đếm 7 sub-file (không 6) · mở lại slot-45 trần `_mind` (tiền-đề lật: file SỐNG 83,2%) · quyết bookkeeping OVERDUE:light (cặp H24 chạy @S159 bookend mà `last_audit` đứng 27)
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
# Implementer-Backend Agent — Persistent Memory
|
# Implementer-Backend Agent — Persistent Memory
|
||||||
|
|
||||||
|
- **S161 (07-29) W1 KHKK schema Mig 69 `[hmw wf_7d6fb81b-640 + wf_f8c806d2-5a3 · CẢ 2 lượt chết #53 (×2 cùng task) NHƯNG lượt-2 sub-md 6.2KB ghi-TỪNG-MỤC-trong-lúc-làm cứu TRỌN narrative + code đĩa sống 100%; lead verify build 0W/0E + solo đuôi; entry on-behalf]`:** Module `Domain/ContractSigningPlans/` 7 entity + 3 enum (Phase 1/2/3/98/99 · DossierItemKind/Status trong DossierItem.cs, start=1) + `ApplicableType.ContractSigningPlan=10` append-only + 7 Configuration + DbSets ×2 file + **Mig 69 `20260729122015_AddContractSigningPlans`** (7 CreateTable · 0 ALTER · Down 7 DropTable · UNIQUE filtered `(PlanId,SupplierId) WHERE IsDeleted=0` #57 · MaKeHoach unique filter NOT-NULL · FK 6-con Cascade 1-hop + Plan→AWF Restrict — **0 multiple-cascade-path by design**: Attachment.DossierItemId chỉ HasIndex KHÔNG FK) · apply 2 DB **0 drift** (khác S133) · sys.tables 89→96 · MenuKeys.All+=KeHoachKyKet:179. Lead solo đuôi: seeder `SeedKeHoachKyKetAccessAsync` (khuôn S118 + MỞ RỘNG vế CanDelete Drafter/Admin, UPGRADE-if-exists F-S1, call SAU revoke) + `ContractSigningPlanCodeGenerator` (KHKK/{YYYY}/{Seq:D3}, SERIALIZABLE, `WorkflowAppCodeSequences` dùng chung ns Domain.Office) + DI + 3 site AWV2Admin (count/retained/orphan — danh sách kết ở VehicleBooking, ItTicket KHÔNG có LevelOpinions). Learned: (1) **ghi-sub-md-TỪNG-MỤC = thứ duy nhất sống khi return chết** — lượt-1 dồn cuối mất trắng narrative, lượt-2 ghi từng mục giữ đủ grep-proof; (2) audit-first §0 bảng đo trước khi làm tiếp = relaunch-cắt-gọt chuẩn; (3) Changelog/Approval = BaseEntity KHÔNG HasQueryFilter (parity PE) — schema-test phải assert theo THỰC TẾ entity không đoán. Tag `[s161, w1-khkk-mig69, sub-md-tung-muc-cuu-narrative, 53-x2-cung-task, cascade-1-hop, upgrade-if-exists-candelete]`
|
||||||
|
|
||||||
- **S153 (07-26) arc ctx-adopt T1 + T3 (2 lượt hmw đợt-1) `[lead seed on-behalf @closeout M9; T1 return mất schema-fail → derive-from-body; T3 return CLEAN]`:** **T1 máy `mind-check`** — EXTEND `scripts/session_ctx.py` (+528 dòng, ADD-only: `_TS_KEY_RE` module-level canonical + subcommand + parser + dispatch; 2 subcommand cũ BẤT ĐỘNG). 7 phép + 2 phụ · 4 mức {đạt·trượt·cờ·bỏ-qua-có-khai} · draft/closed/`--root`/`--session` PIN · exit {0,1,3}. **9 quyết-định thiết-kế có lý-do đo được**, đắt nhất: **D1 config đọc LAZY** — chỉ đọc `memory-budget.json` khi CÓ tệp để đo, vì 2 dòng acceptance chỉ đồng-thời đúng theo thứ tự đó ("không có gì để đo thì không đọc trần; có thứ để đo thì TỪ CHỐI đoán trần") · D3 marker VẮNG ⇒ quét TRỌN + CỜ (hướng hỏng NGHIÊM: tệp thiếu marker = tệp sai khuôn, phải lộ) · D4 rào-3 in pattern-name + `file:line` **KHÔNG in snippet** (gate chống rò không được tự rò ra log) · D6 `_ascii_safe()` backslashreplace (console cp1252 gặp diacritic ⇒ `UnicodeEncodeError` = máy chết GIỮA gate).
|
- **S153 (07-26) arc ctx-adopt T1 + T3 (2 lượt hmw đợt-1) `[lead seed on-behalf @closeout M9; T1 return mất schema-fail → derive-from-body; T3 return CLEAN]`:** **T1 máy `mind-check`** — EXTEND `scripts/session_ctx.py` (+528 dòng, ADD-only: `_TS_KEY_RE` module-level canonical + subcommand + parser + dispatch; 2 subcommand cũ BẤT ĐỘNG). 7 phép + 2 phụ · 4 mức {đạt·trượt·cờ·bỏ-qua-có-khai} · draft/closed/`--root`/`--session` PIN · exit {0,1,3}. **9 quyết-định thiết-kế có lý-do đo được**, đắt nhất: **D1 config đọc LAZY** — chỉ đọc `memory-budget.json` khi CÓ tệp để đo, vì 2 dòng acceptance chỉ đồng-thời đúng theo thứ tự đó ("không có gì để đo thì không đọc trần; có thứ để đo thì TỪ CHỐI đoán trần") · D3 marker VẮNG ⇒ quét TRỌN + CỜ (hướng hỏng NGHIÊM: tệp thiếu marker = tệp sai khuôn, phải lộ) · D4 rào-3 in pattern-name + `file:line` **KHÔNG in snippet** (gate chống rò không được tự rò ra log) · D6 `_ascii_safe()` backslashreplace (console cp1252 gặp diacritic ⇒ `UnicodeEncodeError` = máy chết GIỮA gate).
|
||||||
**T3 persona `ctx-audit`** 11/11 acceptance (14.347B): CHỈNH-1 của lead landed đúng nấc (`tools:` = **mô-tả ý-định**, backstop thật = git-diff commit-gate) + verify 2 chiều `grep -c 'chặn-bằng-thiếu-tool'` = 0 (cụm đó sống ở `harness-eval.md:60`, KHÔNG carry sang) · M-1 hình-B **từ lúc sinh** (đọc `lead-stale-auditor.md:51-54` CHỈ để tránh, 0 chữ chép). **5 phát hiện thêm:** vai tự nhập lưới INFORM-only của detector khi file land (`:1721-1742` đọc LIVE frontmatter) · PHẦN-B #22 sẽ FIRE THẬT nếu lead scribe mà chưa seed diary · H25 parse greedy ⇒ `sub-ctx-audit-open` UNMAPPED không flag (no-name-guessing) · C11(a) `$roleNameRx` KHÔNG áp ctx-audit ⇒ đúng khi persona không bắt gắn class-tag.
|
**T3 persona `ctx-audit`** 11/11 acceptance (14.347B): CHỈNH-1 của lead landed đúng nấc (`tools:` = **mô-tả ý-định**, backstop thật = git-diff commit-gate) + verify 2 chiều `grep -c 'chặn-bằng-thiếu-tool'` = 0 (cụm đó sống ở `harness-eval.md:60`, KHÔNG carry sang) · M-1 hình-B **từ lúc sinh** (đọc `lead-stale-auditor.md:51-54` CHỈ để tránh, 0 chữ chép). **5 phát hiện thêm:** vai tự nhập lưới INFORM-only của detector khi file land (`:1721-1742` đọc LIVE frontmatter) · PHẦN-B #22 sẽ FIRE THẬT nếu lead scribe mà chưa seed diary · H25 parse greedy ⇒ `sub-ctx-audit-open` UNMAPPED không flag (no-name-guessing) · C11(a) `$roleNameRx` KHÔNG áp ctx-audit ⇒ đúng khi persona không bắt gắn class-tag.
|
||||||
Tag `[s153, t1-mind-check-extend-python, d1-config-lazy, d4-khong-in-snippet, t3-persona-11-11, tu-nhap-luoi-inform-only]`
|
Tag `[s153, t1-mind-check-extend-python, d1-config-lazy, d4-khong-in-snippet, t3-persona-11-11, tu-nhap-luoi-inform-only]`
|
||||||
|
|
||||||
- **S139 (07-17) Governance wave adap-3-bản 2-lane [wf_f9981ae5-903 · L1 CLEAN · L2 #53-garble → sub-1.md ON-BEHALF em-main verify-2-nguồn] `[engine: opus-worker]`:** L1 = MASTER-CHECKLIST 2-tầng in 4 cửa (ss Phase-3 · se Phase-4 "TỔNG-HỢP CHỐT" · pause ý-6 · tiep §3-bis bold-block KHÔNG heading) + C1 2-câu đóng-băng bề-mặt-đo (§L.b(c) prepend + mirror §2.1.2) + C6i do-record ×2 + luật-số sàn-5 §L.b(j)(iv) — PASS 6/6 (heading 26/28/7/14 bất-biến · 0 checklist-file mới · BƯỚC-0 intact ×8 · 10/10 config-token preserved · add-only 26+/2−). L2 = +C6 cite-2-nấc + H24-4 pending-flip vào governance-detectors.ps1 (+260/0 add-only) — fault-inject **13/13 2-chiều** (C6 7/7 lane chạy; H24-4 6/6 em-main hoàn tất — lane chết GIỮA fix harness-bug), live-run TOTAL 45 GIỮ + 2 net mới 0-flag count-riêng + exit-0 + ASCII 0-byte>127 + clean-diff 0-FOREIGN-line. Learned: (1) heading-invariant proof = block chèn toàn `>`/bullet + `grep '^+#'`=none (mạnh hơn đọc-mắt, họ insertion-only S134); (2) test-harness PS1 cần CÙNG kỷ-luật naming như production — bẫy `$h`/`$H` case-insensitive cắn chính harness dù script-đích đã né (`:813`); (3) 2 lane cùng chạm bề-mặt-đo (L1 sửa file nằm trong scan-scope L2) → số đo giữa-chừng trôi, clean-diff PHẢI cùng-snapshot. Tag `[s139, adap-3-ban, master-checklist-4-cua, c6-cite-2-nac, h24-4-pending-flip, faultinject-13-13, 53-writelane-onbehalf]`
|
- **S139 (07-17) Governance wave adap-3-bản 2-lane [wf_f9981ae5-903 · L1 CLEAN · L2 #53-garble → sub-1.md ON-BEHALF em-main verify-2-nguồn] `[engine: opus-worker]`:** L1 = MASTER-CHECKLIST 2-tầng in 4 cửa (ss Phase-3 · se Phase-4 "TỔNG-HỢP CHỐT" · pause ý-6 · tiep §3-bis bold-block KHÔNG heading) + C1 2-câu đóng-băng bề-mặt-đo (§L.b(c) prepend + mirror §2.1.2) + C6i do-record ×2 + luật-số sàn-5 §L.b(j)(iv) — PASS 6/6 (heading 26/28/7/14 bất-biến · 0 checklist-file mới · BƯỚC-0 intact ×8 · 10/10 config-token preserved · add-only 26+/2−). L2 = +C6 cite-2-nấc + H24-4 pending-flip vào governance-detectors.ps1 (+260/0 add-only) — fault-inject **13/13 2-chiều** (C6 7/7 lane chạy; H24-4 6/6 em-main hoàn tất — lane chết GIỮA fix harness-bug), live-run TOTAL 45 GIỮ + 2 net mới 0-flag count-riêng + exit-0 + ASCII 0-byte>127 + clean-diff 0-FOREIGN-line. Learned: (1) heading-invariant proof = block chèn toàn `>`/bullet + `grep '^+#'`=none (mạnh hơn đọc-mắt, họ insertion-only S134); (2) test-harness PS1 cần CÙNG kỷ-luật naming như production — bẫy `$h`/`$H` case-insensitive cắn chính harness dù script-đích đã né (`:813`); (3) 2 lane cùng chạm bề-mặt-đo (L1 sửa file nằm trong scan-scope L2) → số đo giữa-chừng trôi, clean-diff PHẢI cùng-snapshot. Tag `[s139, adap-3-ban, master-checklist-4-cua, c6-cite-2-nac, h24-4-pending-flip, faultinject-13-13, 53-writelane-onbehalf]`
|
||||||
|
|
||||||
- **S134 (07-17) PE lũy kế TẠM TÍNH BE [wf_58302bd5-b9f INV-2.A · return sạch 0-garble] `[engine: opus-worker]`:** +`ComputePendingAsync` + `PePendingAccumulation` (PeBudgetAccumulator.cs pure-add +68/0) + `PePendingPriorPeDto` + `PeBudgetSummaryDto` append-cuối 5 field (2 construction site: `:946` frozen-defaults 0/0/0/0/null · `:985` live-fill) + D4 audit-note TRONG `ApplyBudgetSnapshotOnFinalizeAsync` (Action=**Update** KHÔNG Transition — #49 tránh UI đọc 2 lần chuyển-phase; insertion-only +30/0; signature GIỮ → 5 call-site 0-diff, site cuối line-shift :1112→:1142 content bất động). Build slnx 0/0 · 0 mig · ComputeAsync body 0-diff (A1). Learned: (1) **insertion-only diff (grep `'^-'` = 0 real-removal) = bằng-chứng MẠNH NHẤT "thân method/call-site bất động"** — mạnh hơn đọc-mắt, chống báo-số-sai kiểu #53; (2) derived-audit thêm vào helper KHÔNG cần đổi signature nếu tính nội bộ từ field entity sẵn có (giữ call-site 0-diff); (3) accumulator ns ≠ DTO ns (`...Dtos`) → cần using tường minh dù cùng project. Tag `[s134, pe-luyke-tam-tinh, computepending, insertion-only-proof, d4-changelog-update-not-transition]`
|
- **S133+S134 (07-17) PE budget-freeze BE (Mig 67) + lũy kế TẠM TÍNH BE** → 📦 verbatim dời `archive/2026-07.md` (@S161 curate, moved-not-cut). Giữ hook: insertion-only-diff = proof thân-bất-động · backfill `Sql()` plain KHÔNG provider-guard (Mig 61/65/67 khuôn) · `TransitionAsync` KHÔNG SaveChanges nội bộ `:537` · Dev drift committed-chưa-apply → catch-up. Tag `[s133, s134, mig67, computepending, moved-l2]`
|
||||||
|
|
||||||
- **S133 (07-17) PE budget-freeze BE [wf_4bef08b8-730 INV-B · #53 return-fail → disk-truth + em-main-solo hoàn tất; entry on-behalf]:** lane sửa XONG 6 file + `PeBudgetAccumulator.cs` mới (Domain 11 props ApprovedBudget* + Config precision/maxlength + DTO append `BudgetFrozen=false` cuối positional-record + display-gate frozen/live 2-nhánh trong GetPurchaseEvaluationQuery + helper `ApplyBudgetSnapshotOnFinalizeAsync` gọi 4-site `:862/:901/:934/:1109` + 2 terminal-guard block-CẢ-Admin) rồi CHẾT TRƯỚC bước sinh migration → em-main solo: scaffold Mig 67 sạch 11 AddColumn (0 RenameColumn #63) + backfill `Sql()` OUTER APPLY ×3 khớp accumulator TỪNG điều kiện (Suppliers/Quotes = BaseEntity KHÔNG soft-delete filter → SQL không thêm IsDeleted trên s/q; WorkItemId-null → 4 lũy kế NULL mirror helper, SnapshotAt vẫn set) + apply 2 DB — **Dev lòi drift Mig 66 committed-chưa-apply-local, catch-up luôn** — + filter test 44/44 (T0 RED→GREEN không sửa test). Phát hiện đáng giữ của lane: `TransitionAsync` KHÔNG SaveChanges nội bộ `:537` → snapshot flush qua SaveChanges của caller (mirror ApprovedPrice pattern); khuôn backfill THẬT Mig 61/65 = plain `Sql()` KHÔNG C# provider-guard (SQLite EnsureCreated không replay = guard kiến trúc). Tag `[s133, pe-budget-freeze, mig67, 53-writelane-disk-recover]`
|
|
||||||
|
|
||||||
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
|
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
|
||||||
> Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
|
> Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
# Archive 2026-07 — implementer-backend (L2, moved-not-cut từ L1 @S161 curate)
|
||||||
|
|
||||||
|
> Verbatim entries dời khỏi MEMORY.md L1 khi chạm ~93% autoinject_cap (25.600B). KHÔNG nén — nguyên văn.
|
||||||
|
|
||||||
|
- **S134 (07-17) PE lũy kế TẠM TÍNH BE [wf_58302bd5-b9f INV-2.A · return sạch 0-garble] `[engine: opus-worker]`:** +`ComputePendingAsync` + `PePendingAccumulation` (PeBudgetAccumulator.cs pure-add +68/0) + `PePendingPriorPeDto` + `PeBudgetSummaryDto` append-cuối 5 field (2 construction site: `:946` frozen-defaults 0/0/0/0/null · `:985` live-fill) + D4 audit-note TRONG `ApplyBudgetSnapshotOnFinalizeAsync` (Action=**Update** KHÔNG Transition — #49 tránh UI đọc 2 lần chuyển-phase; insertion-only +30/0; signature GIỮ → 5 call-site 0-diff, site cuối line-shift :1112→:1142 content bất động). Build slnx 0/0 · 0 mig · ComputeAsync body 0-diff (A1). Learned: (1) **insertion-only diff (grep `'^-'` = 0 real-removal) = bằng-chứng MẠNH NHẤT "thân method/call-site bất động"** — mạnh hơn đọc-mắt, chống báo-số-sai kiểu #53; (2) derived-audit thêm vào helper KHÔNG cần đổi signature nếu tính nội bộ từ field entity sẵn có (giữ call-site 0-diff); (3) accumulator ns ≠ DTO ns (`...Dtos`) → cần using tường minh dù cùng project. Tag `[s134, pe-luyke-tam-tinh, computepending, insertion-only-proof, d4-changelog-update-not-transition]`
|
||||||
|
|
||||||
|
- **S133 (07-17) PE budget-freeze BE [wf_4bef08b8-730 INV-B · #53 return-fail → disk-truth + em-main-solo hoàn tất; entry on-behalf]:** lane sửa XONG 6 file + `PeBudgetAccumulator.cs` mới (Domain 11 props ApprovedBudget* + Config precision/maxlength + DTO append `BudgetFrozen=false` cuối positional-record + display-gate frozen/live 2-nhánh trong GetPurchaseEvaluationQuery + helper `ApplyBudgetSnapshotOnFinalizeAsync` gọi 4-site `:862/:901/:934/:1109` + 2 terminal-guard block-CẢ-Admin) rồi CHẾT TRƯỚC bước sinh migration → em-main solo: scaffold Mig 67 sạch 11 AddColumn (0 RenameColumn #63) + backfill `Sql()` OUTER APPLY ×3 khớp accumulator TỪNG điều kiện (Suppliers/Quotes = BaseEntity KHÔNG soft-delete filter → SQL không thêm IsDeleted trên s/q; WorkItemId-null → 4 lũy kế NULL mirror helper, SnapshotAt vẫn set) + apply 2 DB — **Dev lòi drift Mig 66 committed-chưa-apply-local, catch-up luôn** — + filter test 44/44 (T0 RED→GREEN không sửa test). Phát hiện đáng giữ của lane: `TransitionAsync` KHÔNG SaveChanges nội bộ `:537` → snapshot flush qua SaveChanges của caller (mirror ApprovedPrice pattern); khuôn backfill THẬT Mig 61/65 = plain `Sql()` KHÔNG C# provider-guard (SQLite EnsureCreated không replay = guard kiến trúc). Tag `[s133, pe-budget-freeze, mig67, 53-writelane-disk-recover]`
|
||||||
@ -64,3 +64,5 @@
|
|||||||
- S55 · BE master-data import · Mig 48 AddProjectMasterFields 4 AddColumn; SeedRealMasterDataAsync UNGATED 62 Project+71 WorkItem+3 Supplier; runtime Dev proof · substring:"S55 master-data import (Mig 48 `AddProjectMasterFields`"
|
- S55 · BE master-data import · Mig 48 AddProjectMasterFields 4 AddColumn; SeedRealMasterDataAsync UNGATED 62 Project+71 WorkItem+3 Supplier; runtime Dev proof · substring:"S55 master-data import (Mig 48 `AddProjectMasterFields`"
|
||||||
- S35 · [stub→git] BE CRUD 4 catalog + Contract V2 (S40 trim) · KEY absorbed into Pattern 12-bis foundation (catalog-mega + HRM .Where(!IsDeleted) + Validator MaxLength=EF) · substring:"Archived S35 G-H2 BE-CRUD-4-catalog + S29 Plan-B-Chunk-C Contract-V2-mirror"
|
- S35 · [stub→git] BE CRUD 4 catalog + Contract V2 (S40 trim) · KEY absorbed into Pattern 12-bis foundation (catalog-mega + HRM .Where(!IsDeleted) + Validator MaxLength=EF) · substring:"Archived S35 G-H2 BE-CRUD-4-catalog + S29 Plan-B-Chunk-C Contract-V2-mirror"
|
||||||
- S35 · [stub→git] FE/test + older BE (S40 curate) · git d2f52ba: S35 FE inline forms 5 satellite + S34 test +10 + S33 EmployeesListPage + S32 wrap/startup · substring:"Archived FE/test + older BE entries → `archive/2026-05-q4.md` + git d2f52ba (S40 curate)"
|
- S35 · [stub→git] FE/test + older BE (S40 curate) · git d2f52ba: S35 FE inline forms 5 satellite + S34 test +10 + S33 EmployeesListPage + S32 wrap/startup · substring:"Archived FE/test + older BE entries → `archive/2026-05-q4.md` + git d2f52ba (S40 curate)"
|
||||||
|
- S134 · PE lũy kế TẠM TÍNH BE · ComputePendingAsync + 5 field DTO append + D4 audit-note Update-not-Transition; insertion-only-proof · substring:"S134 (07-17) PE lũy kế TẠM TÍNH BE"
|
||||||
|
- S133 · PE budget-freeze BE Mig 67 · 11 props snapshot + backfill Sql() OUTER APPLY; #53 write-lane disk-recover; Dev drift catch-up · substring:"S133 (07-17) PE budget-freeze BE"
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
| # | Stage | Vai / cách | Trạng thái |
|
| # | Stage | Vai / cách | Trạng thái |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 1 | Đợt-1a BE: Domain 7 entity + 3 enum + ApplicableType=10 + EF Config ×7 + DbSets + **Mig 69** 3-file (apply 2 DB) + MenuKeys All+= + DbInitializer UPGRADE-if-exists (13/13 role) + CodeGen KHKK + 3 site AWV2AdminFeatures | hmw `implementer-backend` | [!] lane-1 `wf_7d6fb81b-640` chết #53 SAU Domain-layer (8 file entity ĐỦ RUỘT + ApplicableType=10 + 4/7 config — lead verify đĩa; 0 sub-md) → **RELAUNCH-CẮT-GỌT `wf_f8c806d2-5a3`** (3 config + DbSets + Mig 69 + MenuKeys + seeder + CodeGen + 3-site + build) ĐANG CHẠY |
|
| 1 | Đợt-1a BE: Domain 7 entity + 3 enum + ApplicableType=10 + EF Config ×7 + DbSets + **Mig 69** 3-file (apply 2 DB) + MenuKeys All+= + DbInitializer UPGRADE-if-exists (13/13 role) + CodeGen KHKK + 3 site AWV2AdminFeatures | hmw `implementer-backend` | [x] 3 chặng: lane-1 `wf_7d6fb81b-640` chết #53 sau Domain (8 entity + type-10 + 4/7 config) → lane-2 `wf_f8c806d2-5a3` cũng chết #53 NHƯNG sub-md 6.2KB ghi-trong-lúc-làm cứu trọn (audit 0-lệch + 3 config + DbSets + MenuKeys:179 + **Mig 69 `20260729122015` 3-file, apply 2 DB, sys.tables=96**, grep-proof trong sub-md) → **lead solo đuôi @S161**: seeder `SeedKeHoachKyKetAccessAsync` UPGRADE-if-exists+CanDelete (call sau revoke) + `ContractSigningPlanCodeGenerator` KHKK/{YYYY}/{Seq:D3} + DI + 3 site AWV2Admin (count/retained/orphan mirror VehicleBooking). **`dotnet build` 0W/0E 47s** |
|
||||||
| 2 | Đợt-1b FE: Designer type-10 `ApprovalWorkflowsV2Page.tsx` (TYPE_CODE_TO_INT + option + ẩn 2 checkbox early-finalize khi type=10) | hmw `implementer-frontend` | [x] `wf_7d6fb81b-640` lane-2 CLEAN — +67/−9, containment 2-LỚP render+payload; **lead verify build tươi PASS** (bundle `index-iNZq9job`; diagnostics giữa-agent = stale #68); harvest diary xong. Cờ đỏ: type-10 chưa có đường sidebar (allowlist `Layout.tsx:162-168` — cả type-3 xưa nay cũng vậy, đúng spec "menu KHÔNG đổi") |
|
| 2 | Đợt-1b FE: Designer type-10 `ApprovalWorkflowsV2Page.tsx` (TYPE_CODE_TO_INT + option + ẩn 2 checkbox early-finalize khi type=10) | hmw `implementer-frontend` | [x] `wf_7d6fb81b-640` lane-2 CLEAN — +67/−9, containment 2-LỚP render+payload; **lead verify build tươi PASS** (bundle `index-iNZq9job`; diagnostics giữa-agent = stale #68); harvest diary xong. Cờ đỏ: type-10 chưa có đường sidebar (allowlist `Layout.tsx:162-168` — cả type-3 xưa nay cũng vậy, đúng spec "menu KHÔNG đổi") |
|
||||||
| 3 | Đợt-2a: schema test + codegen format test (`ContractSigningPlanSchemaTests` + `SigningPlanCodeGenerator_Format_KhkkYearSeqD3`, N ≥ 2) | hmw `test-specialist` | [ ] |
|
| 3 | Đợt-2a: schema test + codegen format test (`ContractSigningPlanSchemaTests` + `SigningPlanCodeGenerator_Format_KhkkYearSeqD3`, N ≥ 2) | hmw `test-specialist` | [ ] |
|
||||||
| 4 | Đợt-2b: design-review Mig 69 TRƯỚC deploy (reversible Down · snapshot drift · FK/index) | hmw `database-agent` | [ ] |
|
| 4 | Đợt-2b: design-review Mig 69 TRƯỚC deploy (reversible Down · snapshot drift · FK/index) | hmw `database-agent` | [ ] |
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
# sub-database-agent-1 — Design-review Mig 69 `AddContractSigningPlans` (S161 W1, READ-ONLY advisory)
|
||||||
|
|
||||||
|
> Ghi TỪNG MỤC trong lúc làm (chống #53). Không sửa file production. Không commit.
|
||||||
|
> Nguồn đo: file migration + Designer + ModelSnapshot + 7 EF Configuration + sqlcmd LocalDB Dev/Design.
|
||||||
|
|
||||||
|
## VERDICT TỔNG (điền cuối, xem §END)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Vật liệu đã đọc (evidence anchors)
|
||||||
|
|
||||||
|
| Vật | Đường dẫn | Ghi chú |
|
||||||
|
|---|---|---|
|
||||||
|
| Migration | `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260729122015_AddContractSigningPlans.cs` | 373 dòng |
|
||||||
|
| Designer | `...20260729122015_AddContractSigningPlans.Designer.cs` | 264.515 B |
|
||||||
|
| Snapshot | `...Migrations/ApplicationDbContextModelSnapshot.cs` | 264.399 B, git diff +550/-0 |
|
||||||
|
| Config ×7 | `src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/ContractSigningPlan*.cs` | 7 file |
|
||||||
|
| Spec W1 | `.claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w1-schema-designer-29-07-2026.md:16-20` | §②-2/4/6 |
|
||||||
|
| Spec gốc maxLength | `.claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/spec-ke-hoach-ky-ket-hd-28-07-2026.md:134-137` | danh sách 11 cột chuỗi |
|
||||||
|
|
||||||
|
Đếm operation trong migration (grep + uniq):
|
||||||
|
- `CreateTable` ×7 · `CreateIndex` ×20 · `DropTable` ×7 (Down)
|
||||||
|
- `AddColumn` / `AlterColumn` / `DropColumn` / `RenameColumn` / `Sql(` = **0** (không match nào)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Đối chứng sqlcmd LocalDB (DB1/DB10 — schema THẬT, không trí nhớ)
|
||||||
|
|
||||||
|
`sqlcmd -S "(localdb)\MSSQLLocalDB" -d SolutionErp_Dev -E` :
|
||||||
|
|
||||||
|
```
|
||||||
|
TABLECOUNT|96
|
||||||
|
CSPTABLE|ContractSigningPlanApprovals
|
||||||
|
CSPTABLE|ContractSigningPlanAttachments
|
||||||
|
CSPTABLE|ContractSigningPlanChangelogs
|
||||||
|
CSPTABLE|ContractSigningPlanDossierItems
|
||||||
|
CSPTABLE|ContractSigningPlanLevelOpinions
|
||||||
|
CSPTABLE|ContractSigningPlanLines
|
||||||
|
CSPTABLE|ContractSigningPlans
|
||||||
|
MIGTOP|20260729122015_AddContractSigningPlans
|
||||||
|
MIGCOUNT|69
|
||||||
|
```
|
||||||
|
|
||||||
|
`-d SolutionErp_Design` :
|
||||||
|
```
|
||||||
|
DESIGN_TABLECOUNT|96 · DESIGN_CSP|7 · DESIGN_MIGTOP|20260729122015_AddContractSigningPlans · DESIGN_IXCOUNT|27
|
||||||
|
```
|
||||||
|
|
||||||
|
→ **2 DB parity TUYỆT ĐỐI** (96/96 bảng · 7/7 CSP · cùng mig-top · 27 index = 20 IX + 7 PK).
|
||||||
|
→ **KHÔNG có committed-but-unapplied-local drift** (khác bẫy S53).
|
||||||
|
→ Acceptance §③-B "sys.tables 89 → 96" = **ĐẠT** (đo được 96; delta +7 khớp 7 CreateTable).
|
||||||
|
|
||||||
|
### Index thật trong DB (27 dòng, khớp 1:1 file mig)
|
||||||
|
|
||||||
|
Nhóm filtered (soi gotcha #57):
|
||||||
|
```
|
||||||
|
ContractSigningPlanLines | IX_..._ContractSigningPlanId_SupplierId | unique=1 | ([IsDeleted]=(0)) | ContractSigningPlanId,SupplierId
|
||||||
|
ContractSigningPlans | IX_ContractSigningPlans_MaKeHoach | unique=1 | ([MaKeHoach] IS NOT NULL) | MaKeHoach
|
||||||
|
```
|
||||||
|
Các IX còn lại filter = `-` (không filter), unique=0 trừ `IX_ContractSigningPlanLevelOpinions_ContractSigningPlanId_ApprovalWorkflowLevelId` (unique=1, **không** filter — bàn ở §2e/§4).
|
||||||
|
|
||||||
|
### FK thật (8 FK, cột `delete_referential_action_desc`)
|
||||||
|
```
|
||||||
|
Approvals → ContractSigningPlans CASCADE
|
||||||
|
Attachments → ContractSigningPlans CASCADE
|
||||||
|
Changelogs → ContractSigningPlans CASCADE
|
||||||
|
DossierItems → ContractSigningPlans CASCADE
|
||||||
|
LevelOpinions→ ContractSigningPlans CASCADE
|
||||||
|
Lines → ContractSigningPlans CASCADE
|
||||||
|
LevelOpinions→ ApprovalWorkflowLevels NO_ACTION (= Restrict)
|
||||||
|
ContractSigningPlans → ApprovalWorkflows NO_ACTION (= Restrict)
|
||||||
|
```
|
||||||
|
→ 6 con Cascade 1-hop + 2 Restrict, **đúng y spec §②-2/4**. Zero FK vật lý sang PE/Project/Supplier/User/Contract (loose-Guid, convention Mig 49) — xác nhận bằng chính danh sách 8 FK trên (không có dòng nào trỏ `PurchaseEvaluations`/`Suppliers`/`Projects`).
|
||||||
|
|
||||||
|
---
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
# sub-implementer-backend-0 — W1 KHKK lane BE (RELAUNCH-CẮT-GỌT, tiếp lane chết #53)
|
||||||
|
|
||||||
|
> Ghi TỪNG MỤC ngay sau khi xong mục đó (lane trước chết trước khi kịp ghi).
|
||||||
|
> Run: `2026-07-29-S161-khkk-w1-schema` · spec `spec-wave-w1-schema-designer-29-07-2026.md` §② 2→9.
|
||||||
|
|
||||||
|
## §0 — AUDIT mục "✅ ĐÃ XONG" (trước khi làm tiếp)
|
||||||
|
|
||||||
|
| Vật | Đo | Verdict |
|
||||||
|
|---|---|---|
|
||||||
|
| `Domain/ContractSigningPlans/` | 8 file (7 entity + `ContractSigningPlanPhase.cs`) | PASS |
|
||||||
|
| `ContractSigningPlanPhase` | `:10-14` = DangSoanThao=1 / ChoDuyet=2 / DaDuyet=3 / TraLai=98 / TuChoi=99 | PASS khớp spec `:16` |
|
||||||
|
| `DossierItemKind` | `ContractSigningPlanDossierItem.cs:7-12` = MauVatLieu=1/Shopdrawing=2/Khac=99 | PASS |
|
||||||
|
| `DossierItemStatus` | `ContractSigningPlanDossierItem.cs:17-23` = ChuaNop=1..TvgsBac=4 (KHÔNG 0) | PASS — vá C2 |
|
||||||
|
| `ApprovalWorkflowApplicableType.ContractSigningPlan = 10` | `ApprovalWorkflow.cs:66` (append-only, sau `TravelRequest = 9`) | PASS |
|
||||||
|
| Header +`DepartmentId Guid?` (C5) | `ContractSigningPlan.cs:21` | PASS |
|
||||||
|
| Lines +`ContractId Guid?` (C6) | `ContractSigningPlanLine.cs:25` | PASS |
|
||||||
|
| Changelog ĐỦ 4 cột (C1) | `ContractSigningPlanChangelog.cs:29,30,34,36` EntityType/EntityId/UserName/FieldChangesJson | PASS |
|
||||||
|
| Configuration đã có | `ContractSigningPlanConfiguration` + `...Line` + `...DossierItem` + `...LevelOpinion` = 4/7 | đúng như brief |
|
||||||
|
| UNIQUE filtered Lines | `ContractSigningPlanLineConfiguration.cs:22-24` `(PlanId,SupplierId)` + `HasFilter("[IsDeleted] = 0")` | PASS gotcha #57 |
|
||||||
|
| UNIQUE LevelOpinions | `ContractSigningPlanLevelOpinionConfiguration.cs:36` `(PlanId,LevelId)` IsUnique KHÔNG filter | PASS (parity 7 twin, UPSERT) |
|
||||||
|
|
||||||
|
→ 0 lệch spec ⇒ KHÔNG sửa gì phần đã xong.
|
||||||
|
|
||||||
|
## MỤC 1 — 3 Configuration còn lại ✅
|
||||||
|
|
||||||
|
3 file MỚI (khuôn = 4 config đã có + twin PE `PurchaseEvaluationConfiguration.cs:156-210`):
|
||||||
|
|
||||||
|
1. `Configurations/ContractSigningPlanAttachmentConfiguration.cs`
|
||||||
|
- FileName 500 IsRequired · StoragePath 1000 IsRequired · ContentType 200 IsRequired (spec `:134-137`;
|
||||||
|
RỘNG hơn PE 255/500/100 — khuôn `ProposalAttachmentConfiguration.cs:15-17`) · Note 1000 · Purpose `HasConversion<int>()`
|
||||||
|
- FK **Cascade** Plan; `ContractSigningPlanDossierItemId` chỉ `HasIndex` (KHÔNG FK — tránh MULTIPLE CASCADE PATHS)
|
||||||
|
- `HasQueryFilter(!IsDeleted)` — AuditableEntity
|
||||||
|
2. `Configurations/ContractSigningPlanChangelogConfiguration.cs`
|
||||||
|
- Summary **1000** (spec, PE để 500) · ContextNote 2000 · UserName 200 · FieldChangesJson `nvarchar(max)`
|
||||||
|
- IX `(PlanId, CreatedAt)` + `(PlanId, EntityType)` (index twin C1)
|
||||||
|
- BaseEntity ⇒ **KHÔNG** HasQueryFilter (parity PE Changelog)
|
||||||
|
3. `Configurations/ContractSigningPlanApprovalConfiguration.cs`
|
||||||
|
- Comment 1000 · From/ToPhase/Decision `HasConversion<int>()`
|
||||||
|
- IX `(PlanId, ApprovedAt)` (twin PE `:168`) + IX `ApprovalWorkflowLevelId`
|
||||||
|
- `ApprovalWorkflowLevelId` loose-Guid KHÔNG FK (nếu Restrict → admin xoá Level nổ 500, vì 3 site dọn dẹp
|
||||||
|
chỉ biết họ `*LevelOpinions`)
|
||||||
|
- BaseEntity ⇒ KHÔNG HasQueryFilter
|
||||||
|
|
||||||
|
⚠️ Cả 7 bảng con đều FK Cascade 1-hop từ Plan ⇒ 0 multiple-cascade-path.
|
||||||
|
|
||||||
|
## MỤC 2 — DbSets ×7 ✅
|
||||||
|
|
||||||
|
- `Application/Common/Interfaces/IApplicationDbContext.cs:3` +`using SolutionErp.Domain.ContractSigningPlans;`
|
||||||
|
· `:144-153` block 7 DbSet + chú thích "mã KHKK qua `WorkflowAppCodeSequences` (:136) DÙNG CHUNG, KHÔNG bảng sequence riêng".
|
||||||
|
- `Infrastructure/Persistence/ApplicationDbContext.cs:5` +using · `:129-136` 7 `public DbSet<...> => Set<...>()`.
|
||||||
|
- Config tự nạp qua `ApplyConfigurationsFromAssembly` (`ApplicationDbContext.cs` cuối `OnModelCreating`) — 0 dòng đăng ký tay.
|
||||||
|
|
||||||
|
## MỤC 4 (làm sớm, trước build) — MenuKeys ✅
|
||||||
|
|
||||||
|
`Domain/Identity/MenuKeys.cs:179` — thêm ĐÚNG 1 dòng `KeHoachKyKet,` vào `All` (const sẵn `:41`, KHÔNG key mới).
|
||||||
|
⇒ `Program.cs` foreach `All × Actions` tự sinh 4 policy `KeHoachKyKet.{Read,Create,Update,Delete}`.
|
||||||
|
|
||||||
|
## Build sau mục 1+2+4
|
||||||
|
|
||||||
|
`dotnet build SolutionErp.slnx` → **Build succeeded. 0 Warning(s) / 0 Error(s)** (56.77s, 6 project).
|
||||||
|
|
||||||
|
## MỤC 3 — Mig 69 `AddContractSigningPlans` ✅
|
||||||
|
|
||||||
|
Lệnh: `dotnet ef migrations add AddContractSigningPlans --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api --output-dir Persistence/Migrations`
|
||||||
|
|
||||||
|
**3-file rule (gotcha #17) — `git status` chứng:**
|
||||||
|
- `?? 20260729122015_AddContractSigningPlans.cs` (22.059 B)
|
||||||
|
- `?? 20260729122015_AddContractSigningPlans.Designer.cs` (264.515 B)
|
||||||
|
- ` M ApplicationDbContextModelSnapshot.cs`
|
||||||
|
|
||||||
|
**Nội dung đo (grep, KHÔNG đọc-mắt):**
|
||||||
|
- `grep -c CreateTable` = **7** · Down = **7 DropTable** (`:350-368`) · **0** `AddColumn/DropColumn/AlterColumn/Sql/RenameColumn` ⇒ 0 ALTER bảng cũ.
|
||||||
|
- UNIQUE filtered Lines `:301-306`: `(ContractSigningPlanId, SupplierId)` `unique: true, filter: "[IsDeleted] = 0"` ✅ gotcha #57
|
||||||
|
- UNIQUE LevelOpinions `:287-291`: `(ContractSigningPlanId, ApprovalWorkflowLevelId)` `unique: true` (KHÔNG filter — đúng parity twin)
|
||||||
|
- UNIQUE MaKeHoach `:325-330`: filter `[MaKeHoach] IS NOT NULL`
|
||||||
|
- FK: Plan→ApprovalWorkflows **Restrict** `:47` · LevelOpinions→ApprovalWorkflowLevels **Restrict** `:201` · 6 con→Plan **Cascade** (`:76,108,139,171,207,238`)
|
||||||
|
- maxLength khớp spec `:134-137` 100%: MaKeHoach 50 · GhiChu/ContextNote 2000 · Name 500 · Note 1000 · TvgsName 200 · Summary 1000 · SignedByFullName 200 NOT NULL · FileName 500 / StoragePath 1000 / ContentType 200 · Comment(LevelOpinion) 2000 / Comment(Approval) 1000 · HoSoLink 1000.
|
||||||
|
Chỉ `FieldChangesJson` = `nvarchar(max)` `:124` (cố ý, JSON tự do).
|
||||||
|
|
||||||
|
**Apply 2 DB:**
|
||||||
|
- `migrations list --connection …SolutionErp_Dev` TRƯỚC apply: chỉ **1 Pending** = Mig 69 ⇒ **0 drift** (khác S133 phải catch-up).
|
||||||
|
- Dev: `Applying migration '20260729122015_AddContractSigningPlans'. Done.`
|
||||||
|
- Design (default factory): `Applying migration '20260729122015_AddContractSigningPlans'. Done.`
|
||||||
|
- `sqlcmd` Dev: `sys.tables WHERE is_ms_shipped=0` = **96** (89→96, +7) · `LIKE 'ContractSigningPlan%'` = **7**.
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
# sub-test-specialist-0 — W1 KHKK Mig 69: schema-invariant test + codegen format test
|
||||||
|
|
||||||
|
> Ghi TỪNG MỤC trong lúc làm (chống #53). Run: `2026-07-29-S161-khkk-w1-schema`.
|
||||||
|
> Vai: test-specialist (WRITE độc quyền `tests/**`). KHÔNG sửa production, KHÔNG commit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §0 — Tiền đề đọc từ ĐĨA (trước khi viết 1 dòng test)
|
||||||
|
|
||||||
|
Spec đọc: `.claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w1-schema-designer-29-07-2026.md`
|
||||||
|
- §③-B dòng 35: test PIN tên `ContractSigningPlanSchemaTests.BayBang_MoiBang_CoAuditFields_VaQueryFilter`, sàn `N ≥ 2`, số-sau ≥ số-trước + 2.
|
||||||
|
- §③-B dòng 36: test PIN tên `SigningPlanCodeGenerator_Format_KhkkYearSeqD3` — regex `^KHKK/\d{4}/\d{3}$` + 2 lần gọi seq tăng.
|
||||||
|
|
||||||
|
### 7 entity — base class ĐO THẬT trên đĩa (KHÔNG đoán)
|
||||||
|
|
||||||
|
| # | Entity | File | Base | Query filter (config) |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | `ContractSigningPlan` | `Domain/ContractSigningPlans/ContractSigningPlan.cs:16` | `AuditableEntity` | ✅ `ContractSigningPlanConfiguration.cs:47` |
|
||||||
|
| 2 | `ContractSigningPlanLine` | `ContractSigningPlanLine.cs:14` | `AuditableEntity` | ✅ `ContractSigningPlanLineConfiguration.cs:36` |
|
||||||
|
| 3 | `ContractSigningPlanDossierItem` | `ContractSigningPlanDossierItem.cs:31` | `AuditableEntity` | ✅ `...DossierItemConfiguration.cs:29` |
|
||||||
|
| 4 | `ContractSigningPlanAttachment` | `ContractSigningPlanAttachment.cs:24` | `AuditableEntity` | ✅ `...AttachmentConfiguration.cs:39` |
|
||||||
|
| 5 | `ContractSigningPlanLevelOpinion` | `ContractSigningPlanLevelOpinion.cs:24` | `AuditableEntity` | ❌ **CỐ Ý KHÔNG có** |
|
||||||
|
| 6 | `ContractSigningPlanChangelog` | `ContractSigningPlanChangelog.cs:26` | `BaseEntity` | ❌ (đúng — no `IsDeleted`) |
|
||||||
|
| 7 | `ContractSigningPlanApproval` | `ContractSigningPlanApproval.cs:19` | `BaseEntity` | ❌ (đúng — no `IsDeleted`) |
|
||||||
|
|
||||||
|
🔴 **LỆCH so mô-tả trong TASK-prompt** (prompt liệt `LevelOpinion = AuditableEntity có IsDeleted` ⇒ ngụ ý phải có query filter). ĐĨA nói khác: `ContractSigningPlanLevelOpinion` LÀ `AuditableEntity` **nhưng CỐ Ý KHÔNG HasQueryFilter**, có lý do viết sẵn 2 chỗ:
|
||||||
|
- entity `ContractSigningPlanLevelOpinion.cs:20-23`: *"CỐ Ý KHÔNG có HasQueryFilter (parity 7 twin còn lại): site 'dọn chữ ký MỒ CÔI' (ApprovalWorkflowV2AdminFeatures ExecuteDeleteAsync) phải THẤY được row đã soft-delete, nếu bị filter che thì row mồ côi sống sót và FK Restrict lại nổ 500."*
|
||||||
|
- config `ContractSigningPlanLevelOpinionConfiguration.cs:12-16`: cùng nội dung.
|
||||||
|
|
||||||
|
⇒ Áp luật MEMORY "spec drift detection BEFORE write (S34)": **test theo CODE**, không theo prompt. Nhưng KHÔNG bỏ qua — assert LevelOpinion **KHÔNG có filter** như một invariant CÓ CHỦ Ý (nếu ai đó thêm filter sau này ⇒ test ĐỎ ⇒ buộc đọc lại lý do). Đây là assert có RĂNG, không phải né.
|
||||||
|
|
||||||
|
### Codegen
|
||||||
|
`src/Backend/SolutionErp.Infrastructure/Services/ContractSigningPlanCodeGenerator.cs`
|
||||||
|
- ctor `(IApplicationDbContext db, IDateTime dateTime)` — `:12`
|
||||||
|
- `GenerateAsync(CancellationToken ct = default)` — KHÔNG nhận entity (khác PE nhận `PurchaseEvaluation`)
|
||||||
|
- prefix `$"KHKK/{year}"`, return `$"{prefix}/{seq.LastSeq:D3}"` — `:20`, `:45`
|
||||||
|
- `BeginTransactionAsync(IsolationLevel.Serializable, ct)` — `:24-25`
|
||||||
|
- sequence sống ở `db.WorkflowAppCodeSequences` (bảng DÙNG CHUNG Office), PK `Prefix`
|
||||||
|
|
||||||
|
### Tiền lệ SQLite + Serializable — ĐÃ CÓ, không cần chế mới
|
||||||
|
`tests/SolutionErp.Infrastructure.Tests/Common/SqliteDbFixture.cs:36-42` ghi rõ:
|
||||||
|
> *"SQLite hỗ trợ transactions thật (BEGIN/COMMIT/ROLLBACK), tuy nhiên IsolationLevel enum value bị provider mapping gracefully (no exception, just default behavior)"*
|
||||||
|
|
||||||
|
Và `PurchaseEvaluationCodeGeneratorTests.cs:17` gọi thẳng `new PurchaseEvaluationCodeGenerator(fix.Db, dt)` — generator PE cũng `Serializable`, test cũ chạy XANH nhiều session ⇒ **dùng y khuôn, KHÔNG đụng production**.
|
||||||
|
|
||||||
|
`FixedDateTime` stub: `SqliteDbFixture.cs:71`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §1 — Test đã viết
|
||||||
|
|
||||||
|
File MỚI: `tests/SolutionErp.Infrastructure.Tests/Application/ContractSigningPlanSchemaTests.cs`
|
||||||
|
(đặt cạnh `EmployeeSatelliteTests.cs` — cùng lớp "EF-model assertion", khuôn `EmployeeSatelliteTests.cs:248-261` `db.Model.FindEntityType(...)`).
|
||||||
|
|
||||||
|
(chi tiết điền sau khi chạy — xem §2/§3)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## §2 — Số đo
|
||||||
|
|
||||||
|
(điền sau)
|
||||||
|
|
||||||
|
## §3 — Verdict
|
||||||
|
|
||||||
|
(điền sau)
|
||||||
Reference in New Issue
Block a user