wal: flush 20260801T1228

This commit is contained in:
pqhuy1987
2026-08-01 12:28:55 +07:00
parent e7a4a4a58d
commit b827fd393b
10 changed files with 252 additions and 136 deletions

View File

@ -31,15 +31,24 @@ chain:
Vite-8-minify-backtick làm regex-marker FAIL-OAN ×2 → luật grep -F, vai đã ghi MEMORY —
sub-cicd-verify-k6.md). ✅ CLARIFY-2 CHỐT @S167 (anh: "Admin (Site) để nguyên"): giữ nguyên cả 2 —
Hrm/Off/Personal tạm 0 lối menu 2 app (route/quyền còn nguyên; bật lại = màn Menu eOffice, 0 code)
[!] K7 — 2 lane ĐANG nền @S167 (spec-cum3 ② vá 1/3/4/6/16): BE = grant Contracts.Create
[câu III default Drafter+Procurement+Admin, comment chờ-ratify] + hội-2-khóa endpoint + guard 2-cờ +
Line.ContractId-ghi-luôn + DTO expose + nạp Code/SLA/pin (sub-implbe-k7.md) ⟂ FE = nút gate hội-2-khóa
+ dialog khuôn-sẵn + cây GĐ3/GĐ4 TẬP lines[].contractId pe.contractId ×2 app (sub-implfe-k7.md).
Cửa chết → ĐỌC 2 FILE ĐÓ trước, đừng spawn lại. CÒN SAU LANE: test-lane 8+2-authz+idempotency →
gate-K7 → commit → cicd
[!] K7 — BE DONE / FE+test ĐANG nền @S167. 🔴 BE-lane BÁC tiền-đề lead "bridge đã tồn tại" (4 phép đo —
W6 chỉ có ĐƯỜNG-ỐNG; lead nhập nhằng 2 khái niệm) → DỰNG bridge theo invest §K7.1 pin-sẵn + 5 vá:
seeder SeedContractCreateAccessAsync :2757 (Drafter/Procurement/Admin upgrade-only — lỗ thật: trước
S167 0-role có Contracts.Create) · POST {id}/create-contract hội-2-khóa AND :230-238 · guard 4-vế
throw-tách :132-148 · Line.ContractId write-site ĐẦU-TIÊN :237-238 + list-DTO +ContractIds · vá-6
codegen/SLA/pin (spec THẮNG invest chỗ WorkflowDefinitionId). Build 0/0 · runtime 34/35 (1 fail
= AuthorizePolicyRegressionTests:398 đòi-prefix, bridge CỐ Ý Contracts.Create #85 → test-lane thêm
ngoại-lệ CreateContract). 4 file uncommitted (3 M + 1 mới CreateContractFromSigningPlanFeatures.cs)
— sub-implbe-k7.md §0-§6 trọn. FE-lane resumed giữa vá-4b (fe-user 2 file M + KhkkDetailPage đang
dựng nút — sub-implfe-k7.md) ⟂ test-lane spawn @sau-BE (8-case + 2-authz + idempotency + :398
ngoại-lệ — sub-test-k7.md). Cửa chết → ĐỌC 3 SUB-FILE trước, đừng spawn lại. CÒN: gate-K7 → commit
→ cicd
[ ] K8-prep form-14-người fail-closed + gói SOLUTION-PE-{n} + QĐ9 đo-2-nhánh + ZZTEST + rollback-theo-ID
[ ] closeout-nợ: 🆕 slot(57) anh chốt "AUTO" @S167 ⇒ em chọn SPLIT _INDEX (không nâng cap) + wire
auto-rotate khi chạm ngưỡng — LÀM SAU khi cicd-K6 trả (tránh đua file archive cicd-monitor) ·
[ ] closeout-nợ: slot(57) ĐÓNG @S167 (anh "auto"): SPLIT _INDEX 21.468→8.756B (42,7% cap) +
_INDEX-2026-H1.md 13.906B tầng-lạnh · vá kèm 3-bệnh-sẵn (mega-line #423 · 29-entry lạc-section ·
needle-quote test-specialist) · 3 script cùng-class → `_INDEX*.md` (gate-2-chỗ chống-haystack-dương-giả
+ measure-trục-l2_index + shard-probe-loại-trừ) · luật AUTO-rotate @header-_INDEX + split_rule_S167
@budget.json · CHỨNG: A7 427/427-PASS-lần-đầu-sạch + probe l2idx-0-over + fault-inject-2-chiều ·
🆕 G-1 RATIFIED @S167 (anh: "Đồng ý. Cứ theo khuôn PE") ⇒ grep đóng mọi comment/ghi-chú "chờ ratify"
SAU khi lane FE-K7 trả (tránh đua fe-*) · diary vai (C2, gồm ctx-verifier S167 lead-seed) · tally #53
CHỐT derive-from-body (S166 nháp 8 lượt + cicd-K5K4C + gate-K6-garble = 10-cận-dưới / 0 mất công) · nhãn D MIND · STATUS row S163-S167 · spec-cụm1 vá-3 đính-chính

View File

@ -0,0 +1,104 @@
# CI/CD Monitor — Archive INDEX — 2026-H1 (records ≤ 2026-06) — SPLIT @S167
> File TÁCH từ `_INDEX.md` @S167 (owner "auto") — VERBATIM từng dòng, anchor substring giữ nguyên 100%.
> Tầng LẠNH: chỉ mở khi cần record ≤ 2026-06. Gate A7 vẫn verify pointer trong file này (đọc `_INDEX*.md`).
> Legend/pointer-style: xem header `_INDEX.md` (không chép lại — 1 nguồn).
## 2026-06 (file: `archive/2026-06.md`)
<!-- ===== S80 (2026-06-20) curate batch — moved 3 huge run-entries L1->L2 ===== -->
- 2026-06-19 · S78 #330 cross-stack NO-MIG enum ApprovalAttachment=5 (attach-on-… · PASS bundle-BOTH-rotate js+css… · `2026-06.md` · substring:"Run #330 (run_number 330, id=444)"
- 2026-06-19 · S76 #318 full-stack Mig56 ProInitial/ProAdjust VERIFIED-APPLIED-PROD · PASS backfill-4rows-0violation… · `2026-06.md` · substring:"Run #318 (run_number 318, id=432)"
- 2026-06-19 · S83 #325 FE-only tiny budget-subitem indent/dash · PASS bundle-BOTH-js-rotate css… · `2026-06.md` · substring:"Run #325 (id=439)"
- 2026-06-17 · FE-only re-skin Văn phòng số 10-page PURO · PASS bundle-BOTH-rotate Wt54PH… · `2026-06.md` · substring:"Run #306 (run_number 306, id420) sha=`c556f6c`"
- 2026-06-17 · FE-both-app Văn phòng số foundation + index.css + BE menu-seed · PASS bundle-BOTH-rotate Bl2o_k… · `2026-06.md` · substring:"Run #305 (run_number 305, id419) sha=`a8bbdae`"
- 2026-06-16 · FE-both-app 1-line CSS-precedence fix (name text-white!) · PASS bundle-BOTH-rotate CNUv1j… · `2026-06.md` · substring:"Run #304 (run_number 304, id418) sha=`37752eb`"
- 2026-06-16 · FE-both-app Hồ sơ NS banner text-polish · PASS bundle-BOTH-rotate D532XZ… · `2026-06.md` · substring:"Run #303 sha=`6983609` PASS"
- 2026-06-16 · FE-both-app PE Link-hồ-sơ file:// render · PASS bundle-BOTH-rotate CcrZqf… · `2026-06.md` · substring:"Run #302 (run_number 302, id416) sha=`536dd6b`"
- 2026-06-16 · TESTS-ONLY BE +23 test (286) · PASS bundle-BOTH-frozen xkSz9B… · `2026-06.md` · substring:"Run #299 (id413) sha=`bcd619d`"
- 2026-06-16 · FE-Admin MIRROR Hồ sơ NS from fe-user · PASS bundle-asymmetric-NGƯỢC a… · `2026-06.md` · substring:"Run #298 (run_number 298, id412) sha=`292d64d`"
- 2026-06-16 · FE-User Hồ sơ NS cosmetic brand800 · PASS bundle-asymmetric user-ro… · `2026-06.md` · substring:"Run #297 (run_number 297, id411) sha=`ab4e681`"
- 2026-06-16 · FE-User Hồ sơ NS 2-col layout · PASS bundle-asymmetric user-ro… · `2026-06.md` · substring:"Run #295 (run_number 295, id409) sha=`456c7a7`"
- 2026-06-16 · CROSS-STACK PE HoSoLink Mig 52 + FE-User 3-panel + rename Dự trù→… · PASS Mig52-applied + bundle-bo… · `2026-06.md` · substring:"Run #293 (run_number 293, id407) sha=`5a0aaa4`"
- 2026-06-13 · CROSS-STACK PE PeWorkItemBudgets vượt-ngân-sách soft-warn (Mig 50… · PASS · `2026-06.md` · substring:"Run #286 (run_number 286, id400)"
- 2026-06-12 · CROSS-STACK PE guard 4-thông-tin mục 3 · PASS · `2026-06.md` · substring:"Run #283 (run_number 283) sha=`37122f0`"
- 2026-06-11 · S59-CLOSE final đóng sổ · PASS · `2026-06.md` · substring:"Run #280 (run_number 280) sha=`69997da`"
- 2026-06-11 · S59-đợt6 CROSS-STACK BE · PASS · `2026-06.md` · substring:"Run #278 (run_number 278) sha=`9c330d2`"
- 2026-06-11 · S59-đợt5 FE-only ×2 · PASS · `2026-06.md` · substring:"Run #277 (run_number 277) sha=`faed59f`"
- 2026-06-11 · S59-đợt4 rename WorkItems 71 idempotent-seed · PASS rename-via-prod-SQL targe… · `2026-06.md` · substring:"Run #276 (run_number 276) sha=`c869d26`"
- 2026-06-11 · S59-đợt3 BE-only DbInitializer · PASS · `2026-06.md` · substring:"Run #275 (run_number 275) sha=`bbd1554`"
- 2026-06-11 · S59 FE×2 PE-list tree regroup · PASS · `2026-06.md` · substring:"Run #273 (run_number 273) sha=`56882ac`"
- 2026-06-11 · S59-đợt2 FE×2 PE-list tree · PASS · `2026-06.md` · substring:"Run #274 (run_number 274) sha=`0eafcd3`"
- 2026-06-11 · SUPERSEDE-CHAIN (benign cancel→shipped) · CANCELLED-benign→PASS-via-3eba… · `2026-06.md` · substring:"Run #385#386 SUPERSEDE-CHAIN sha=`ea793a4`"
- 2026-06-11 · S58 FE-USER visual redesign · PASS asymmetric fe-user-only · `2026-06.md` · substring:"Run #384 (run_number 270) sha=`e959f72`"
- 2026-06-16 · TEST-GATE COMPILE BREAK (CS7036 ParentId 5th positional, call-sit… · **[FAIL]** ~64s deploy-gated p… · `2026-06.md` · substring:"Run #291 (run_number 291, id405) sha=`8c8179c`"
- 2026-06-11 · S58 FIX #381 lock NO-OP (lock-noop→pw-11to12) · PASS dump-Users-set-before-sco… · `2026-06.md` · substring:"Run #382 (run_number 268) sha=`5998163`"
- 2026-06-11 · S57bis PE gắn WorkItemId loose-Guid (Mig 49) · PASS+1PARTIAL · `2026-06.md` · substring:"Run #381 (run_number 267) sha=`dd117b7`"
- 2026-06-09 · S56 GOLIVE-HARDEN BE fixes · PASS · `2026-06.md` · substring:"Run #379 (run_number 265) sha=`a20cde8`"
- 2026-06-09 · S56 pre-golive re-verify prod truth · **[audit]** no-deploy read-only · `2026-06.md` · substring:"S56 pre-golive verify — NO deploy"
- 2026-06-09 · S55 Phase-1 FE-Admin visual redesign · PASS asymmetric fe-admin-only… · `2026-06.md` · substring:"Run #378 (run_number 264) sha=`7feb53e`"
- 2026-06-09 · S55 HMW-P4 real master-data seed (Mig 48, 62 dự án+71 hạng mục+3… · PASS ungated-seed sqlcmd-COUNT… · `2026-06.md` · substring:"Run #377 (run_number 263) sha=`69cb393`"
- 2026-06-08 · S54 IT-staff self-reassign ticket · PASS · `2026-06.md` · substring:"Run #376 (run_number 262) sha=`ca4b602`"
- 2026-06-08 · S50 HMW-Wave2 P11-C Vehicle+Driver · PASS Discovery#3 mixed-docs+ts… · `2026-06.md` · substring:"Run #371 (run_number 257) sha=`30a99aa`"
- 2026-06-03 · S48 FE-only login subtitle a11y · PASS · `2026-06.md` · substring:"Run #369 (run_number 255) sha=`350b2bf`"
- 2026-06-01 · S45 Mig 43 filter Holiday UNIQUE · PASS · `2026-06.md` · substring:"Run #368 (run_number 254) sha=`0c5a014`"
- 2026-05-30 · S42 P11-B LeaveBalance business · PASS · `2026-06.md` · substring:"Run #367 (run_number 253) sha=`82d7fcf`"
- 2026-05-30 · S42 P11-A workflow-picker 2-bug + SetWorkflow · PASS · `2026-06.md` · substring:"Run #365 sha=`75df04e`"
- 2026-05-30 · S42 P11-A wire ApproveV2+LevelOpinions · PASS (mem #250 ≠ real Gitea id… · `2026-06.md` · substring:"Run #364 (mem #250) sha=`e7b66cd`"
- 2026-05-28 · S38 SKELETON 5-plan combo Mig 39+40 dual · PASS · `2026-06.md` · substring:"Run #247 sha=`e54a22d`"
- 2026-05-?? · S37 Proposal Mig 37+38 (/api/proposals 200 + QT-DX-V2-001 AppType=4) · PASS [archived] · `2026-06.md` · substring:"Archived Run #246 (S37 Proposal Mig 37+38"
- 2026-06-11 · ⚠️ VỊ-TRÍ-LẠC entry (mem run id ≠ real Gitea — FIFO slot between… · note · `2026-06.md` · substring:"VỊ TRÍ LẠC — entry MỚI 2026-06-11"
- 2026-05-22 · S29 gotcha #51 catch (SeedSampleContractWorkflowV2 nested in demo… · PASS [archived] · `2026-06.md` · substring:"Archived Run #232 (S29 gotcha #51 catch"
## 2026-05 late (file: `archive/2026-05-q4.md`)
- 2026-05-27 · BE+FE×2 Danh bạ nội bộ /api/directory (G-O1) · PASS bundle-both-rotate, menu-… · `2026-05-q4.md` · substring:"Run #238 (S34 Plan 2 G-O1 Danh bạ nội bộ"
- 2026-05-26 · BE Hrm CQRS /api/employees + FE×2 + menu (G-H1 Phase2) · PASS bundle-both-rotate, Emplo… · `2026-05-q4.md` · substring:"Run #237 (S33 Plan B G-H1 Phase 2 Task 4+5+6"
- 2026-05-26 · BE Mig 34 EmployeeProfile + Plan C BW1-BW7 +9 test (62 Infra) · PASS gotcha#51 INFRASTRUCTURE-… · `2026-05-q4.md` · substring:"Run #350 (S33 Plan B G-H1 Mig 34 EmployeeProfile"
- 2026-05-26 · S33 startup health-check · **[audit]** HEALTHY, last-5-ru… · `2026-05-q4.md` · substring:"S33 startup health-check — em main spawn read-only verify, VERDICT=HEALTHY"
- 2026-05-26 · S32 wrap curate + Phase9→10 · **[meta]** no-run docs-only skip · `2026-05-q4.md` · substring:"S32 wrap — em main proxy curate + Phase 9 stabilize done"
- 2026-05-26 · S32 startup verify (foundation freshness + 3-endpoint smoke) · **[audit]** no-CI-poll, RAG-he… · `2026-05-q4.md` · substring:"S32 startup verify — no CI poll"
- 2026-05-21 · S26 Plan AG PE-List tree-view UI iteration (#222-#227 cumulative) · PASS hybrid-verify spawn-1×-pe… · `2026-05-q4.md` · substring:"Run #222-#227 cumulative — Plan AG series PE List tree view"
## 2026-05 mid (file: `archive/2026-05-runs.md`)
### Run-records (20)
- 2026-05-19 · S25 t7 Plan AF FE userMap fallback resolve historical · PASS bundle-rotate C8TvDy7r/Bv… · `2026-05-runs.md` · substring:"Run #221 id=335 sha=`506cada`"
- 2026-05-19 · S25 t6 Plan AE Changelog UserName 9-sites batch · PASS BE-only bundle-frozen, pr… · `2026-05-runs.md` · substring:"Run #220 id=334 sha=`9ea62be`"
- 2026-05-19 · S25 t5 Plan AD Lịch-sử-duyệt redesign next-target-hint · PASS FE-only bundle-rotate, pa… · `2026-05-runs.md` · substring:"Run #219 id=333 sha=`0aaf2df`"
- 2026-05-19 · S25 t4 Plan AC2 FE merge recover historical Reject · PASS bundle-rotate, synthetic-… · `2026-05-runs.md` · substring:"Run #218 id=332 sha=`25837b6`"
- 2026-05-15 · S24 t1 Plan AA wrap fix sidebar · PASS last-deploy-before-AB, ba… · `2026-05-runs.md` · substring:"Run #214 id=328 sha=`ee0902a`"
- 2026-05-15 · S24 t1 Plan AA IsUserSelectable filter + WfView menu + sidebar (4… · PASS bundle-rotate, Order-shif… · `2026-05-runs.md` · substring:"Run #210 id=324 sha=`ac2c859`"
- 2026-05-15 · S23 t11 Plan U FE sidebar truncate · PASS long-label ellipsis+title… · `2026-05-runs.md` · substring:"Run #209 sha=`86d8806`"
- 2026-05-15 · S23 t10 Plan T5+T6 docs final (DemoSeed wipe ~720 rows + force re… · PASS flag-proven-end-to-end · `2026-05-runs.md` · substring:"Run #208 sha=`7b7b28f`"
- 2026-05-15 · S23 t10 Plan T DemoSeed disable (flag in appsettings, 5 demo-seed… · PASS · `2026-05-runs.md` · substring:"Run #207 sha=`0b97840`"
- 2026-05-15 · S23 t7 Plan Q FE banner mx-5 fix · PASS bundle-rotate QZIPWD-g/Da… · `2026-05-runs.md` · substring:"Run #204 sha=`108268a`"
- 2026-05-15 · S23 t6 Plan P HOTFIX Controller TransitionPeBody +3 fields · PASS Discovery#4 ASP.NET10-rec… · `2026-05-runs.md` · substring:"Run #203 id=317 sha=`1727bd5`"
- 2026-05-15 · S23 t5 Plan O HOTFIX cascade 4 lookup-sites (point 9) · PASS 409-mode-not-403-actor pr… · `2026-05-runs.md` · substring:"Run #202 id=316 sha=`a1c8386`"
- 2026-05-15 · S23 t4 Plan N HOTFIX per-NV lookup discrimination :765 · PASS 7/7-vs-1/7-per-actor, bug… · `2026-05-runs.md` · substring:"Run #201 id=315 sha=`fb3c22c`"
- 2026-05-15 · S23 t3 Plan M Service F1 OneLevel/OneStep edge-case Bước1 reset · PASS Discovery#3-anomaly docs-… · `2026-05-runs.md` · substring:"Run #200 id=314 sha=`f4055a1`"
- 2026-05-14/15 · S23 t1 K10 hotfix AwLevelDto +AllowApproverSkipToFinal · PASS 8-surface-point-checklist… · `2026-05-runs.md` · substring:"Run #195 id=309 sha=`0062fcb`"
- 2026-05-14 · S23 t1 Plan K Mig 31 per-Approver-slot refactor · **[PARTIAL]** Mig+schema OK bu… · `2026-05-runs.md` · substring:"Run #194 id=308 sha=`098baa6`"
- 2026-05-13 · S22-chốt cumulative verify · PASS Discovery#3 push-range-ev… · `2026-05-runs.md` · substring:"Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits) VERDICT=PASS"
- 2026-05-13 · S22 Plan D Users-toggle + Plan C 14-test + Plan E strict-V2-scope · PASS 103 test, Discovery#1 rat… · `2026-05-runs.md` · substring:"Run #188 id=302 sha=a74e671"
- 2026-05-13 · S21 t5 Mig 29 refactor Allow*-per-NV + Designer 5-checkbox · PASS Mig29 applied, Discovery… · `2026-05-runs.md` · substring:"Run #187 id=301 sha=c0af9e0"
- 2026-05-13 · S21 t3+t4 gotcha#45 Trả-lại + F1/F2/F3 advanced-options + Mig 28 · PASS baseline, Discovery API-t… · `2026-05-runs.md` · substring:"Run #186 id=300 sha=eea86fd"
### Curate-note meta-headers (6) — [meta]
- 2026-05-19 · curate-note S25 t5 Plan AD #219 · **[meta]** · `2026-05-runs.md` · substring:"added S25 t5 Plan AD Run #219 entry"
- 2026-05-19 · curate-note S25 t3 Plan AC #217 (Discovery#5 sqlcmd 4-backslash \… · **[meta]** · `2026-05-runs.md` · substring:"added S25 t3 Plan AC Run #217 entry"
- 2026-05-19 · curate-note S25 t1 Plan AB #215 (gotcha#48 SQLite tie-break FAIL) · **[meta]** · `2026-05-runs.md` · substring:"added S25 t1 Plan AB Run #215 entry"
- 2026-05-15 · curate-note S24 t1 Plan AA #210 · **[meta]** · `2026-05-runs.md` · substring:"added S24 t1 Plan AA Run #210 entry"
- 2026-05-15 · curate-note S23 t6 Plan P #203 (Discovery#4 numeric-enum) · **[meta]** · `2026-05-runs.md` · substring:"added S23 t6 Plan P HOTFIX Run #203 entry"
- 2026-05-15 · curate-note S23 t5 Plan O #202 (4-site discrimination, Transition… · **[meta]** · `2026-05-runs.md` · substring:"added S23 t5 Plan O HOTFIX Run #202 entry"
## 2026-05 early (file: `archive/2026-05-q3.md`)
- 2026-05-19 · ★ Run #215 FAIL → #216 PASS pair — **gotcha #48 SQLite tie-break*… · FAIL→PASS · `2026-05-q3.md` · substring:"Run #215 FAIL → Run #216 PASS (gotcha #48 SQLite tie-break catch+fix pair)"
- 2026-05-13 · Verify S22 chốt cuối cumulative (Discovery#3 first-surfaced, 33 u… · PASS · `2026-05-q3.md` · substring:"Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits VERDICT=PASS"
- 2026-05-12 · Setup baseline (agent init, 44 gotchas + 5-stage + 3 skills) · init · `2026-05-q3.md` · substring:"2026-05-12 — Setup baseline"
## 2026-05 early (file: `archive/2026-05-q2.md`)
- 2026-05-22 · Run #231 Plan B Contract V2 wire kick-off · **[PARTIAL]** PASS-deploy + se… · `2026-05-q2.md` · substring:"Run #231 (id=345) Plan B Contract V2 wire kick-off VERDICT=PARTIAL"

View File

@ -1,6 +1,8 @@
# CI/CD Monitor — Archive INDEX (table of contents, NO content)
> 🗜️ **gist-of-index @S152 (D1 queue):** desc-verdict nén ~45c (desc đầy-đủ cũ = git-history file này); **toàn bộ anchor substring giữ NGUYÊN-VĂN 100%** — KHÔNG split (gate chỉ đọc `_INDEX.md`).
> 🗜️ **gist-of-index @S152 (D1 queue):** desc-verdict nén ~45c (desc đầy-đủ cũ = git-history file này); **toàn bộ anchor substring giữ NGUYÊN-VĂN 100%**.
> 🔄 **SPLIT @S167 (owner "auto" 2026-08-01):** records ≤ 2026-06 dời VERBATIM sang `_INDEX-2026-H1.md` (cùng thư mục — tầng lạnh, mở khi cần record cổ). Gate A7 (`memory-archive-gate.ps1`) đọc **MỌI `_INDEX*.md`** nên pointer phần cũ VẪN được canh; probe cap (`nhip-no-probe.ps1`) chỉ đo file CHÍNH này. **LUẬT ROTATE (auto, không hỏi lại):** khi probe in `l2idx N over` → dời TRỌN section tháng CŨ NHẤT của file này sang `_INDEX-<period>.md` tương ứng (tạo mới nếu chưa có), VERBATIM từng dòng, KHÔNG bao giờ drop marker.
> **Purpose:** L2 archive is "dark-matter" (not in RAG). This index is the map: 1 line per archived record so a future spawn can locate + open the right verbatim block on-demand without reading 220KB cold.
> **Pointer style = SUBSTRING (Ctrl-F) primary.** Each line ends `→ <file> · substring:"<unique-string>"`. The string is grep-verified `count==1` inside its target file (76/76 unique at build time). Open the file, Ctrl-F the string → lands on the record start. Fallback if a future edit shifts text: search the bare `Run #NNN` + nearest date.
@ -8,7 +10,7 @@
> **Archives are FROZEN / additive-only.** Records are never edited in place; this index + the `.gist.md` files are the only additive layers.
> **SORTED by DATE (newest → oldest).** Labels: `[meta]` = curate-note (not a rich run-record) · `[stub→git]` = FIFO-trim pointer-to-git, thin · `[audit]` = read-only verify, no deploy · `[FAIL]`/`[PARTIAL]` = non-PASS verdict.
>
> **Files indexed:** `2026-07.md` (**4** records — re-dem DIA @S159) · `2026-06.md` (39 records, no headings) · `2026-05-runs.md` (20 run-records + 6 meta-headers) · `2026-05-q4.md` (7) · `2026-05-q3.md` (3) · `2026-05-q2.md` (1). Total **80 records**.
> **Files indexed HERE (2026-07+):** `2026-07.md`. Records ≤ 2026-06 (`2026-06.md` · `2026-05-runs.md` · `2026-05-q4.md` · `2026-05-q3.md` · `2026-05-q2.md`) → xem `_INDEX-2026-H1.md`. Đếm record = đếm dòng `^- ` từng file index (đừng tin số chép tay — bài Errata @S159).
> 🔴 **Errata @S159:** ban cu khai `2026-07.md`=2 / Total 78; dia co **4** (#407 @S155, #416 @S157). Nang hon: **#407 mo-coi** — co trong kho, 0 con-tro => vo hinh voi nguoi tra `_INDEX`; da them. Bai: **dem-lech la trieu-chung, ban-ghi-mo-coi la thiet hai.** Sweep lai: 0 mo-coi.
> Even-older verbatim (S29 #232 ← pre-S38) also lives in git `d2f52ba`. Gist companions: `2026-06.gist.md` + `2026-05.gist.md`.
@ -20,103 +22,7 @@
- 2026-07-01 · S96+S97 FINAL-SESSION-REVIEW 11-commit day #478-#484 ALL-HEALTHY… · CLEAN, bundle rotated-post-#48… · `2026-07.md` · substring:"S96+S97 FINAL-SESSION-REVIEW (2026-07-01 end"
- 2026-07-01 · S97 #484 DATA-FIX Mig 61 backfill EndedByLevelFinalize từ Changel… · PASS backfill-flip A/005+A/008… · `2026-07.md` · substring:"S97 #484 (id=484, run_number 370)"
## 2026-06 (file: `archive/2026-06.md`)
<!-- ===== S80 (2026-06-20) curate batch — moved 3 huge run-entries L1->L2 ===== -->
- 2026-06-19 · S78 #330 cross-stack NO-MIG enum ApprovalAttachment=5 (attach-on-… · PASS bundle-BOTH-rotate js+css… · `2026-06.md` · substring:"Run #330 (run_number 330, id=444)"
- 2026-06-19 · S76 #318 full-stack Mig56 ProInitial/ProAdjust VERIFIED-APPLIED-PROD · PASS backfill-4rows-0violation… · `2026-06.md` · substring:"Run #318 (run_number 318, id=432)"
- 2026-06-19 · S83 #325 FE-only tiny budget-subitem indent/dash · PASS bundle-BOTH-js-rotate css… · `2026-06.md` · substring:"Run #325 (id=439)"
- 2026-06-17 · FE-only re-skin Văn phòng số 10-page PURO · PASS bundle-BOTH-rotate Wt54PH… · `2026-06.md` · substring:"Run #306 (run_number 306, id420) sha=`c556f6c`"
- 2026-06-17 · FE-both-app Văn phòng số foundation + index.css + BE menu-seed · PASS bundle-BOTH-rotate Bl2o_k… · `2026-06.md` · substring:"Run #305 (run_number 305, id419) sha=`a8bbdae`"
- 2026-06-16 · FE-both-app 1-line CSS-precedence fix (name text-white!) · PASS bundle-BOTH-rotate CNUv1j… · `2026-06.md` · substring:"Run #304 (run_number 304, id418) sha=`37752eb`"
- 2026-06-16 · FE-both-app Hồ sơ NS banner text-polish · PASS bundle-BOTH-rotate D532XZ… · `2026-06.md` · substring:"Run #303 sha=`6983609` PASS"
- 2026-06-16 · FE-both-app PE Link-hồ-sơ file:// render · PASS bundle-BOTH-rotate CcrZqf… · `2026-06.md` · substring:"Run #302 (run_number 302, id416) sha=`536dd6b`"
- 2026-06-16 · TESTS-ONLY BE +23 test (286) · PASS bundle-BOTH-frozen xkSz9B… · `2026-06.md` · substring:"Run #299 (id413) sha=`bcd619d`"
- 2026-06-16 · FE-Admin MIRROR Hồ sơ NS from fe-user · PASS bundle-asymmetric-NGƯỢC a… · `2026-06.md` · substring:"Run #298 (run_number 298, id412) sha=`292d64d`"
- 2026-06-16 · FE-User Hồ sơ NS cosmetic brand800 · PASS bundle-asymmetric user-ro… · `2026-06.md` · substring:"Run #297 (run_number 297, id411) sha=`ab4e681`"
- 2026-06-16 · FE-User Hồ sơ NS 2-col layout · PASS bundle-asymmetric user-ro… · `2026-06.md` · substring:"Run #295 (run_number 295, id409) sha=`456c7a7`"
- 2026-06-16 · CROSS-STACK PE HoSoLink Mig 52 + FE-User 3-panel + rename Dự trù→… · PASS Mig52-applied + bundle-bo… · `2026-06.md` · substring:"Run #293 (run_number 293, id407) sha=`5a0aaa4`"
- 2026-06-13 · CROSS-STACK PE PeWorkItemBudgets vượt-ngân-sách soft-warn (Mig 50… · PASS · `2026-06.md` · substring:"Run #286 (run_number 286, id400)"
- 2026-06-12 · CROSS-STACK PE guard 4-thông-tin mục 3 · PASS · `2026-06.md` · substring:"Run #283 (run_number 283) sha=`37122f0`"
- 2026-06-11 · S59-CLOSE final đóng sổ · PASS · `2026-06.md` · substring:"Run #280 (run_number 280) sha=`69997da`"
- 2026-06-11 · S59-đợt6 CROSS-STACK BE · PASS · `2026-06.md` · substring:"Run #278 (run_number 278) sha=`9c330d2`"
- 2026-06-11 · S59-đợt5 FE-only ×2 · PASS · `2026-06.md` · substring:"Run #277 (run_number 277) sha=`faed59f`"
- 2026-06-11 · S59-đợt4 rename WorkItems 71 idempotent-seed · PASS rename-via-prod-SQL targe… · `2026-06.md` · substring:"Run #276 (run_number 276) sha=`c869d26`"
- 2026-06-11 · S59-đợt3 BE-only DbInitializer · PASS · `2026-06.md` · substring:"Run #275 (run_number 275) sha=`bbd1554`"
- 2026-06-11 · S59 FE×2 PE-list tree regroup · PASS · `2026-06.md` · substring:"Run #273 (run_number 273) sha=`56882ac`"
- 2026-06-11 · S59-đợt2 FE×2 PE-list tree · PASS · `2026-06.md` · substring:"Run #274 (run_number 274) sha=`0eafcd3`"
- 2026-06-11 · SUPERSEDE-CHAIN (benign cancel→shipped) · CANCELLED-benign→PASS-via-3eba… · `2026-06.md` · substring:"Run #385#386 SUPERSEDE-CHAIN sha=`ea793a4`"
- 2026-06-11 · S58 FE-USER visual redesign · PASS asymmetric fe-user-only · `2026-06.md` · substring:"Run #384 (run_number 270) sha=`e959f72`"
- 2026-06-16 · TEST-GATE COMPILE BREAK (CS7036 ParentId 5th positional, call-sit… · **[FAIL]** ~64s deploy-gated p… · `2026-06.md` · substring:"Run #291 (run_number 291, id405) sha=`8c8179c`"
- 2026-06-11 · S58 FIX #381 lock NO-OP (lock-noop→pw-11to12) · PASS dump-Users-set-before-sco… · `2026-06.md` · substring:"Run #382 (run_number 268) sha=`5998163`"
- 2026-06-11 · S57bis PE gắn WorkItemId loose-Guid (Mig 49) · PASS+1PARTIAL · `2026-06.md` · substring:"Run #381 (run_number 267) sha=`dd117b7`"
- 2026-06-09 · S56 GOLIVE-HARDEN BE fixes · PASS · `2026-06.md` · substring:"Run #379 (run_number 265) sha=`a20cde8`"
- 2026-06-09 · S56 pre-golive re-verify prod truth · **[audit]** no-deploy read-only · `2026-06.md` · substring:"S56 pre-golive verify — NO deploy"
- 2026-06-09 · S55 Phase-1 FE-Admin visual redesign · PASS asymmetric fe-admin-only… · `2026-06.md` · substring:"Run #378 (run_number 264) sha=`7feb53e`"
- 2026-06-09 · S55 HMW-P4 real master-data seed (Mig 48, 62 dự án+71 hạng mục+3… · PASS ungated-seed sqlcmd-COUNT… · `2026-06.md` · substring:"Run #377 (run_number 263) sha=`69cb393`"
- 2026-06-08 · S54 IT-staff self-reassign ticket · PASS · `2026-06.md` · substring:"Run #376 (run_number 262) sha=`ca4b602`"
- 2026-06-08 · S50 HMW-Wave2 P11-C Vehicle+Driver · PASS Discovery#3 mixed-docs+ts… · `2026-06.md` · substring:"Run #371 (run_number 257) sha=`30a99aa`"
- 2026-06-03 · S48 FE-only login subtitle a11y · PASS · `2026-06.md` · substring:"Run #369 (run_number 255) sha=`350b2bf`"
- 2026-06-01 · S45 Mig 43 filter Holiday UNIQUE · PASS · `2026-06.md` · substring:"Run #368 (run_number 254) sha=`0c5a014`"
- 2026-05-30 · S42 P11-B LeaveBalance business · PASS · `2026-06.md` · substring:"Run #367 (run_number 253) sha=`82d7fcf`"
- 2026-05-30 · S42 P11-A workflow-picker 2-bug + SetWorkflow · PASS · `2026-06.md` · substring:"Run #365 sha=`75df04e`"
- 2026-05-30 · S42 P11-A wire ApproveV2+LevelOpinions · PASS (mem #250 ≠ real Gitea id… · `2026-06.md` · substring:"Run #364 (mem #250) sha=`e7b66cd`"
- 2026-05-28 · S38 SKELETON 5-plan combo Mig 39+40 dual · PASS · `2026-06.md` · substring:"Run #247 sha=`e54a22d`"
- 2026-05-?? · S37 Proposal Mig 37+38 (/api/proposals 200 + QT-DX-V2-001 AppType=4) · PASS [archived] · `2026-06.md` · substring:"Archived Run #246 (S37 Proposal Mig 37+38"
- 2026-06-11 · ⚠️ VỊ-TRÍ-LẠC entry (mem run id ≠ real Gitea — FIFO slot between… · note · `2026-06.md` · substring:"VỊ TRÍ LẠC — entry MỚI 2026-06-11"
- 2026-05-22 · S29 gotcha #51 catch (SeedSampleContractWorkflowV2 nested in demo… · PASS [archived] · `2026-06.md` · substring:"Archived Run #232 (S29 gotcha #51 catch"
## 2026-05 late (file: `archive/2026-05-q4.md`)
- 2026-05-27 · BE+FE×2 Danh bạ nội bộ /api/directory (G-O1) · PASS bundle-both-rotate, menu-… · `2026-05-q4.md` · substring:"Run #238 (S34 Plan 2 G-O1 Danh bạ nội bộ"
- 2026-05-26 · BE Hrm CQRS /api/employees + FE×2 + menu (G-H1 Phase2) · PASS bundle-both-rotate, Emplo… · `2026-05-q4.md` · substring:"Run #237 (S33 Plan B G-H1 Phase 2 Task 4+5+6"
- 2026-05-26 · BE Mig 34 EmployeeProfile + Plan C BW1-BW7 +9 test (62 Infra) · PASS gotcha#51 INFRASTRUCTURE-… · `2026-05-q4.md` · substring:"Run #350 (S33 Plan B G-H1 Mig 34 EmployeeProfile"
- 2026-05-26 · S33 startup health-check · **[audit]** HEALTHY, last-5-ru… · `2026-05-q4.md` · substring:"S33 startup health-check — em main spawn read-only verify, VERDICT=HEALTHY"
- 2026-05-26 · S32 wrap curate + Phase9→10 · **[meta]** no-run docs-only skip · `2026-05-q4.md` · substring:"S32 wrap — em main proxy curate + Phase 9 stabilize done"
- 2026-05-26 · S32 startup verify (foundation freshness + 3-endpoint smoke) · **[audit]** no-CI-poll, RAG-he… · `2026-05-q4.md` · substring:"S32 startup verify — no CI poll"
- 2026-05-21 · S26 Plan AG PE-List tree-view UI iteration (#222-#227 cumulative) · PASS hybrid-verify spawn-1×-pe… · `2026-05-q4.md` · substring:"Run #222-#227 cumulative — Plan AG series PE List tree view"
## 2026-05 mid (file: `archive/2026-05-runs.md`)
### Run-records (20)
- 2026-05-19 · S25 t7 Plan AF FE userMap fallback resolve historical · PASS bundle-rotate C8TvDy7r/Bv… · `2026-05-runs.md` · substring:"Run #221 id=335 sha=`506cada`"
- 2026-05-19 · S25 t6 Plan AE Changelog UserName 9-sites batch · PASS BE-only bundle-frozen, pr… · `2026-05-runs.md` · substring:"Run #220 id=334 sha=`9ea62be`"
- 2026-05-19 · S25 t5 Plan AD Lịch-sử-duyệt redesign next-target-hint · PASS FE-only bundle-rotate, pa… · `2026-05-runs.md` · substring:"Run #219 id=333 sha=`0aaf2df`"
- 2026-05-19 · S25 t4 Plan AC2 FE merge recover historical Reject · PASS bundle-rotate, synthetic-… · `2026-05-runs.md` · substring:"Run #218 id=332 sha=`25837b6`"
- 2026-05-15 · S24 t1 Plan AA wrap fix sidebar · PASS last-deploy-before-AB, ba… · `2026-05-runs.md` · substring:"Run #214 id=328 sha=`ee0902a`"
- 2026-05-15 · S24 t1 Plan AA IsUserSelectable filter + WfView menu + sidebar (4… · PASS bundle-rotate, Order-shif… · `2026-05-runs.md` · substring:"Run #210 id=324 sha=`ac2c859`"
- 2026-05-15 · S23 t11 Plan U FE sidebar truncate · PASS long-label ellipsis+title… · `2026-05-runs.md` · substring:"Run #209 sha=`86d8806`"
- 2026-05-15 · S23 t10 Plan T5+T6 docs final (DemoSeed wipe ~720 rows + force re… · PASS flag-proven-end-to-end · `2026-05-runs.md` · substring:"Run #208 sha=`7b7b28f`"
- 2026-05-15 · S23 t10 Plan T DemoSeed disable (flag in appsettings, 5 demo-seed… · PASS · `2026-05-runs.md` · substring:"Run #207 sha=`0b97840`"
- 2026-05-15 · S23 t7 Plan Q FE banner mx-5 fix · PASS bundle-rotate QZIPWD-g/Da… · `2026-05-runs.md` · substring:"Run #204 sha=`108268a`"
- 2026-05-15 · S23 t6 Plan P HOTFIX Controller TransitionPeBody +3 fields · PASS Discovery#4 ASP.NET10-rec… · `2026-05-runs.md` · substring:"Run #203 id=317 sha=`1727bd5`"
- 2026-05-15 · S23 t5 Plan O HOTFIX cascade 4 lookup-sites (point 9) · PASS 409-mode-not-403-actor pr… · `2026-05-runs.md` · substring:"Run #202 id=316 sha=`a1c8386`"
- 2026-05-15 · S23 t4 Plan N HOTFIX per-NV lookup discrimination :765 · PASS 7/7-vs-1/7-per-actor, bug… · `2026-05-runs.md` · substring:"Run #201 id=315 sha=`fb3c22c`"
- 2026-05-15 · S23 t3 Plan M Service F1 OneLevel/OneStep edge-case Bước1 reset · PASS Discovery#3-anomaly docs-… · `2026-05-runs.md` · substring:"Run #200 id=314 sha=`f4055a1`"
- 2026-05-14/15 · S23 t1 K10 hotfix AwLevelDto +AllowApproverSkipToFinal · PASS 8-surface-point-checklist… · `2026-05-runs.md` · substring:"Run #195 id=309 sha=`0062fcb`"
- 2026-05-14 · S23 t1 Plan K Mig 31 per-Approver-slot refactor · **[PARTIAL]** Mig+schema OK bu… · `2026-05-runs.md` · substring:"Run #194 id=308 sha=`098baa6`"
- 2026-05-13 · S22-chốt cumulative verify · PASS Discovery#3 push-range-ev… · `2026-05-runs.md` · substring:"Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits) VERDICT=PASS"
- 2026-05-13 · S22 Plan D Users-toggle + Plan C 14-test + Plan E strict-V2-scope · PASS 103 test, Discovery#1 rat… · `2026-05-runs.md` · substring:"Run #188 id=302 sha=a74e671"
- 2026-05-13 · S21 t5 Mig 29 refactor Allow*-per-NV + Designer 5-checkbox · PASS Mig29 applied, Discovery… · `2026-05-runs.md` · substring:"Run #187 id=301 sha=c0af9e0"
- 2026-05-13 · S21 t3+t4 gotcha#45 Trả-lại + F1/F2/F3 advanced-options + Mig 28 · PASS baseline, Discovery API-t… · `2026-05-runs.md` · substring:"Run #186 id=300 sha=eea86fd"
### Curate-note meta-headers (6) — [meta]
- 2026-05-19 · curate-note S25 t5 Plan AD #219 · **[meta]** · `2026-05-runs.md` · substring:"added S25 t5 Plan AD Run #219 entry"
- 2026-05-19 · curate-note S25 t3 Plan AC #217 (Discovery#5 sqlcmd 4-backslash \… · **[meta]** · `2026-05-runs.md` · substring:"added S25 t3 Plan AC Run #217 entry"
- 2026-05-19 · curate-note S25 t1 Plan AB #215 (gotcha#48 SQLite tie-break FAIL) · **[meta]** · `2026-05-runs.md` · substring:"added S25 t1 Plan AB Run #215 entry"
- 2026-05-15 · curate-note S24 t1 Plan AA #210 · **[meta]** · `2026-05-runs.md` · substring:"added S24 t1 Plan AA Run #210 entry"
- 2026-05-15 · curate-note S23 t6 Plan P #203 (Discovery#4 numeric-enum) · **[meta]** · `2026-05-runs.md` · substring:"added S23 t6 Plan P HOTFIX Run #203 entry"
- 2026-05-15 · curate-note S23 t5 Plan O #202 (4-site discrimination, Transition… · **[meta]** · `2026-05-runs.md` · substring:"added S23 t5 Plan O HOTFIX Run #202 entry"
## 2026-05 early (file: `archive/2026-05-q3.md`)
- 2026-05-19 · ★ Run #215 FAIL → #216 PASS pair — **gotcha #48 SQLite tie-break*… · FAIL→PASS · `2026-05-q3.md` · substring:"Run #215 FAIL → Run #216 PASS (gotcha #48 SQLite tie-break catch+fix pair)"
- 2026-05-13 · Verify S22 chốt cuối cumulative (Discovery#3 first-surfaced, 33 u… · PASS · `2026-05-q3.md` · substring:"Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits VERDICT=PASS"
- 2026-05-12 · Setup baseline (agent init, 44 gotchas + 5-stage + 3 skills) · init · `2026-05-q3.md` · substring:"2026-05-12 — Setup baseline"
## 2026-05 early (file: `archive/2026-05-q2.md`)
- 2026-05-22 · Run #231 Plan B Contract V2 wire kick-off · **[PARTIAL]** PASS-deploy + se… · `2026-05-q2.md` · substring:"Run #231 (id=345) Plan B Contract V2 wire kick-off VERDICT=PARTIAL"
<!-- ===== các entry 2026-07 dưới đây RELOCATE @S167 từ cuối file (từng bị append lạc vào section 2026-05-q2) — thứ tự ngày TĂNG dần như cũ, VERBATIM ===== -->
- 2026-07-06 · S103 #487 `f0874dd` GOVERNANCE/SCRIPTS-ONLY GO — GOVERNANCE-PASS… · PASS · `2026-07.md` · substring:"S103 #487 (rn 373) `f0874dd` GO ~4m"
- 2026-07-02 · S100 #486 `5ee32c0` GOVERNANCE-ONLY GO — bundle FROZEN #69-REFINE… · PASS · `2026-07.md` · substring:"S100 #486 (rn 372) `5ee32c0` GO 5m17s"
- 2026-07-10 · S107 #489 `21387cd` GOVERNANCE-ONLY (+office-document 12th sub) G… · PASS · `2026-07.md` · substring:"S107 #489 (rn 375, id 489)"
@ -133,7 +39,6 @@
- 2026-07-13 · S115 #385 `81b59f0` GOVERNANCE/TOOLING-ONLY (hmw.js+memory-archiv… · PASS · `2026-07.md` · substring:"S115 #385 (rn 385, id 499)"
- 2026-07-13 · S116 #386 `88368fd` PE nhap-gia-AM + submit-guard all-zero GO — j… · PASS · `2026-07.md` · substring:"S116 #386 (rn 386, id 500)"
- 2026-07-14 · S117 #387 `316a82f` PE endsBeforeCeo-pointer-aware + duyet-theo-k… · PASS · `2026-07.md` · substring:"S117 #387 (rn 387, id 501)"
- 2026-07-14 · S118 #389 `c808b9a` SECURITY-AUTHZ ReportsController→Reports.Read… · PASS · `2026-07.md` · substring:"S118 #389 (rn 389, id 503)"
- 2026-07-16 · S126 #394 `e9124fc` GOVERNANCE-TOOLING GO — gate 509 exact, bundl… · PASS · `2026-07.md` · substring:"S126 (2026-07-16) run 508/#394"
- 2026-07-17 · S133 #398 `d4fbced` PE budget-freeze + Mig67 AddPeApprovedBudgetS… · PASS · `2026-07.md` · substring:"S133 (07-17) verify d4fbced"
@ -141,7 +46,8 @@
- 2026-07-23 · S155 #407 `4510cea` App chuan-hoa ma du-an normalize + PE attach-gate FE both-apps… · PASS 5/5 · `2026-07.md` · substring:"Run #407 `4510cea` (2026-07-23)"
- 2026-07-27 · S155 #416 `b1bae77` Workflow duyet-TAI-CHO + co F6 AllowApproverDelete… · PASS · `2026-07.md` · substring:"Run #416 `b1bae77` (2026-07-27)"
- 2026-07-28 · S157 #419 `a52a91e` PE canh-bao amber o Dia-diem khi du-an thieu Location… · PASS 9/9 · `2026-07.md` · substring:"Run #419 `a52a91e` (2026-07-28)"
- 2026-07-29 · S159 #423 `1a47a61` dot-2 tab strip 4GD + menu 4-GD — PARTIAL 8/9, bat regression revoker an 447/494 row · `2026-07.md` · substring:"Run #423 `1a47a61` (2026-07-29"- 2026-07-30 · S162 #432 `bfc7b79` cay-4-folder-GD FE-ONLY — PASS 5/5, LUAT cam HEAD~1 (neo SHA X^..X) + dem-tron-ho 1 regex · `2026-07.md` · substring:"07-30 verify `bfc7b79` S162"
- 2026-07-29 · S159 #423 `1a47a61` dot-2 tab strip 4GD + menu 4-GD — PARTIAL 8/9, bat regression revoker an 447/494 row · `2026-07.md` · substring:"Run #423 `1a47a61` (2026-07-29"
- 2026-07-30 · S162 #432 `bfc7b79` cay-4-folder-GD FE-ONLY — PASS 5/5, LUAT cam HEAD~1 (neo SHA X^..X) + dem-tron-ho 1 regex · `2026-07.md` · substring:"07-30 verify `bfc7b79` S162"
- 2026-07-31 · S164 #434 `50e6d8c` K1 SP-002 danh-muc loai-HD + Mig 70 — PASS 6/6, tam-giac 3 nguon doc-lap cho seed 86 + bai "0-hit la duong-gia toi khi soi format" · `2026-07.md` · substring:"07-31 verify `50e6d8c` S164 K1"
- 2026-07-31 · S164 #435 `0779f2d` K2 KHKK mang hang-muc + nhom duyet N1-8 + Mig 71 — PARTIAL 5/6, bai CHAN-LY-RONG (acceptance 0-row hai phia) + liet-ke-tron-ho index + wire-proof bind-400 · `2026-07.md` · substring:"07-31 verify `0779f2d` S164 K2"
- 2026-07-31 · S164 #436 `15349e8` K3 8 workflow nhom KHKK-N1-8 (0-mig) — PASS 6/6, du-doan-truoc-khi-do + FROZEN-la-he-qua + marker bien-local 0-bit · `2026-07.md` · substring:"S166 (08-01) re-verify `15349e8`"

View File

@ -1,5 +1,7 @@
# Implementer-Backend Agent — Persistent Memory
- **S167 (08-01) lane K7 — cầu KHKK→HĐ BE + 5 vá `[artifact sub-implbe-k7.md; return-1 garble #53 → lead SendMessage-resume, xong solo]`:** Bài lớn nhất = **BÁC TIỀN ĐỀ ĐỀ BÀI bằng 4 phép đo trước khi gõ**: lead nói "bridge ĐÃ TỒN TẠI (W6-S161), mày chỉ vá quanh nó" — đĩa nói KHÔNG (`grep create-contract` 1 hit duy nhất = bridge PE cũ · 0 file · 0 endpoint · 0 write-site `Line.ContractId`). Cái tồn tại @W6**đường-ống HĐ V2**, không phải cầu ⇒ lead nhập nhằng "đường ống đã vá"≠"bridge có". **Phép thử rẻ phân biệt:** vá-6 ("nạp Project.Code/Supplier.Code theo khuôn bridge-cũ") là **no-op nếu áp lên bridge cũ** (nó ĐÃ có 2 dòng đó) ⇒ vá chỉ có nghĩa với vật CHƯA có ⇒ suy ngược ra vật thiếu. Xử: DỰNG bridge theo spec invest §K7.1 đã pin sẵn (0 quyết-định-mới của tôi) + nhúng 5 vá, KHAI RÕ chệch-khuôn + trỏ dòng spec — lead nhận. Khi **spec vá ⊥ nền invest** (`WorkflowDefinitionId` null vs pin) → **vá THẮNG** (spec `:4` viết luật đó). Cột đã có từ mig cũ ⇒ **0-mig**. `??=` giữ CHIỀU: cầu chạy sau không cướp ô của cầu trước. Thêm field vào projection dùng-chung-3-endpoint → **chạy test filter rẻ ngay** (collection-subquery SQLite dịch được: 34/35). 1 fail = reflection-authz test bắt mọi action phải cùng key module, mà vá-1 cố ý gate key MODULE KHÁC (`Contracts.Create`, #85) ⇒ **verified-fail bàn giao test-lane, KHÔNG tự sửa** (S112 khuôn). Tag `[s167, k7-bridge-khkk-hd, bac-tien-de-4-phep-do, va-noop-suy-nguoc-vat-thieu, spec-thang-nen, 0-mig, verified-fail-handoff]`
- **S166 (08-01) lane K4a — 49 row menu KHKK 8-nhóm, DONE B0-B5 `[LEAD SEED ON-BEHALF TẠI-CỬA — mày #53 sau B5 ("Now the site-4 revoker comment" trong khi comment ĐÃ land — return tụt sau đĩa 1 nhịp); B6 + END lead đóng; nguồn: sub-implbe-k4a.md + git diff]`:** Nghề mới ăn tiền: **BỘ-SINH thay 49 const tay**`KhkkGroupNumbers[7] × (KhkkGroup + 6 KhkkLeafActions)``KhkkGroupMenuKeys` làm NGUỒN CHUNG 3 phía (spread `.. ` vào `All` · vòng seed tree.Add · site-2 `.Concat`) ⇒ khớp **by-construction, 0 mirror tay 147 chuỗi** (đúng loại drift nổ FK Permission T6-K1); chệch-khuôn-so-brief KHAI RÕ + trỏ đề xuất gốc invest `:9` ⇒ lead chấp nhận không mất lượt. Anchor re-ground TRƯỚC khi sửa (số spec trượt vì DbInitializer phình sau K2/K3): dict labelBackfill `:2141-2183` · upsert THẬT `:2162-2179` (vá 2 comment stale "1893" bằng mỏ-neo GREP `existingItems.TryGetValue` thay số-dòng-trần — số dòng sẽ trượt tiếp, mỏ neo thì không). Vá-10 sửa LÝ-DO comment (group-key KHÔNG cần CanRead row — HasAccess đệ-quy theo con `:96`; invest doc viết sai lý-do, kết luận giữ-3-site vẫn đúng). labelBackfill `Khkk_G1` đổi-nhãn-không-nhân-row + fail-fast KeyNotFound khi thiếu nhãn (thà nổ lúc seed còn hơn FK nổ về sau). Suite **614/0 SAU diff** (idempotent/revoke/permission-seed giữ xanh). Tag `[s166, k4a-lane, bo-sinh-by-construction-3-phia, mo-neo-grep-thay-so-dong, fail-fast-luc-seed, return-tut-sau-dia-1-nhip, seed-on-behalf-tai-cua]`
- **S161 (07-29) ARC W1+W2+W3đ1 KHKK — 3 lượt/3 wave, chi tiết = sub-md run-folder `runs/2026-07-29-S161-khkk-{w1-schema,w2-crud,w3-duyet}/` (tổng ~47KB ghi-từng-mục; cả 3 lượt return #53 nhưng 0 mất):** **W1** Mig 69 7-bảng (UNIQUE filtered #57 · cascade-1-hop · apply 2 DB 0-drift · sys.tables 96) + seeder `SeedKeHoachKyKetAccessAsync` UPGRADE-if-exists+CanDelete + CodeGen `KHKK/{YYYY}/{Seq:D3}` WorkflowAppCodeSequences + 3 site AWV2Admin — ship `a8027c0` cicd 6/6. **W2** mega-file CRUD 15-endpoint policy-15/15 + 4 quyết D1-D4 khai-lead-duyệt; 5 bẫy né ghi sổ: codegen-TRƯỚC-Add (S88) · SUM so `w.Id` KHÔNG `w.SupplierId` · `Remove` trước `Add(changelog)` (T26) · subquery-Any-2-tầng vỡ-SQL-lúc-chạy · giao-1-grep-cùng-lớp-ra-3 (S122) — ship `6cbc6ad` cicd 6/6 (reviewer 12F: D1 "FE sẽ khớp" = giả-định-không-phải-phép-đo → 6 điểm đứt, lead vá). **W3đ1** skeleton test-before: switch-throw từng nhánh (đỏ-THẬT không đỏ-compile) + **rào-FK-547-bằng-VẮNG-MẶT-dep** (không inject IChangelogService) + **§6 tự đối-chứng chéo hợp-đồng FE 5/5 TRƯỚC bàn giao** (bài W2 → nghi thức) + §7 bàn-giao ctor-CUỐI. Tag `[s161, khkk-w1-w2-w3d1, mig69, upgrade-if-exists, rao-vang-mat-dep, doi-chung-cheo, gia-dinh-vs-phep-do]`
@ -82,19 +84,13 @@ UI `disabled={!canX}` + BE helper `EnsureCanXAsync(id, userId)` throw 403 (NOT i
## 📅 Recent activity (FIFO — older → archive/git)
- **2026-07-13 (S116 PE cho nhập giá ÂM — submit-guard 1-line BE, owner anh Kiệt PROD-UAT-live, NO mig/FE/test, spec deterministic exact-line → ACCEPT Case 1):** Giá âm ô "Số tiền báo giá hạng mục" (form.thanhTien→Quote.ThanhTien) = phát-sinh-giảm/hoàn-tiền NCC = giá-trị THẬT (KHÔNG lỗi). Rule "có giá là được": ≥1 quote-selected khác 0 (âm/dương) → gửi được; CHỈ all-zero (chưa báo giá) mới chặn. **THAY DUY NHẤT** `PurchaseEvaluationWorkflowService.cs:206` submit-guard `selectedThanhTien.Sum() <= 0``.All(x => x == 0)`. Guard `Count==0` (chưa chọn NCC) ở `if` phía trên GIỮ RIÊNG → `else if` chỉ chạy khi list non-empty → `.All(==0)` = "mọi quote chọn đúng bằng 0". Message giữ "Đơn vị được chọn chưa có giá chào thầu". **KHÔNG đụng** (owner R1/R3/R-CEO): validator ≥0 khác (budget/price PeFeatures/PeWorkItemBudget/PeSuggestedPrice) GIỮ · clamp `CreateContractFromEvaluationFeatures.cs:88-100` GIỮ (Contract.GiaTri cho âm R1) · CEO-threshold winnerQuoteTotal NET GIỮ · KHÔNG thêm validator quote. DB nhận âm sẵn (Mig 65, decimal(18,2) 0 CHECK, 0 validator). Build `SolutionErp.Api` **0 warn/0 err** (Api ref Infrastructure → file compiled). ⚠️ Comment `:193-195` ("tổng ≤0"/"D5 giữ >0"/"winner phải có giá") giờ STALE vs all-zero-logic — KHÔNG sửa (owner "THAY DUY NHẤT :206"), flag owner quyết. LESSON: domain "âm là giá-trị-thật" → presence-check dùng `.All(==0)` KHÔNG `Sum()<=0`/`>=0` (sum-guard nhầm âm-lớn với chưa-nhập). Tag `[s116, pe-negative-quote, submit-guard-1line, all-zero-not-sum, co-gia-la-duoc, no-mig, stale-comment-flagged]`.
- **2026-07-12 (S113 Supplier import v2 BE — spec `wf_e7896ca6` fable-clone-ensemble, owner anh Kiệt, Mig 64, D1/D2/D3 pre-chốt → ACCEPT Case 1+2; ⚠️ return-1 garbled #53 → coordinator SendMessage-resume, xong solo):** IsPublic publish-gate + dedup MST-primary. **Mig 64 `AddSupplierPublishState`** (Supplier +`bool IsPublic` NOT NULL default false + `Sql("UPDATE Suppliers SET IsPublic=1")` backfill 22 prod + DropIndex→CreateIndex đổi Code-unique filter `[IsDeleted]=0 AND [Code]<>''` cho draft-row Code="" coexist; no new table 89). **Service** `SupplierExcelImportService`: (a) re-bake ExpectedHeaderTokens BYTE-EXACT raw-`\n` form = single-source cho validator(NormalizeHeader collapse \n→space)+BuildTemplate (spec §② 30 token, c7 trailing-space); (b) dedup **MST-primary + Code-backstop**`BuildMstIndex`(NormalizeMst=Trim+strip-inner-ws `\s+`→"" OrdinalIgnoreCase, blank→skip) precedence existing-MST→existing-Code→batch-MST→batch-Code, `countedUpdates HashSet<Supplier>` tránh double-count, blank-MST KHÔNG vào batchByMst (2 blank=2 insert); (c) BỎ hard-error blank-Code (=draft), GIỮ Name+all-or-nothing; (d) New `IsPublic=!blank(Code)`, update-path KHÔNG đụng IsPublic; +MstMissing(soft-warn) +DraftCount; (e) `BuildTemplate()` ClosedXML sheet "Sheet1" 30 token ROW4 WrapText+FreezeRows. **PublishSupplierCommand**(Id,MaNcc?,Publish): set Code+unique-CI-check + gate Publish→Code-non-empty ConflictException, KHÔNG UpdateSupplierCommand (#73 clobber). **API THẬT:** GET `/api/suppliers/import/template`(xlsx "Mau-Database-NCC.xlsx") · POST `/api/suppliers/{id}/publish` body`{maNcc?,publish}` · GET `/api/suppliers?published={t/f}` filter · SupplierDto +`bool IsPublic` append-CUỐI (sửa 2 projection List+Get). **D3 authz:** import preview/confirm/template/publish `[Roles=Admin,CatalogManager]``[Policy="Suppliers.Update"]` (khớp FE PermissionGuard). DbInit +IsPublic=true 4 real+18 sample. Build slnx **0/0**, apply BOTH DB (Dev catch-up+Design). KHÔNG commit/FE/test. LESSON: S112 CI-dedup-at-service mở rộng → dual-key MST-primary; blank-key KHÔNG index. Tag `[s113, supplier-import-v2, mig64, ispublic-publish-gate, dedup-mst-primary-code-backstop, blank-code-draft, buildtemplate-single-source, publish-cmd-no-#73]`.
- **2026-07-12 (S112 PE sign-off close-review implement — `wf_7df56b89-7bb` GO-WITH-ADJ, owner anh Kiệt PROD-UAT-live, 4-region/1 file `PurchaseEvaluationWorkflowService.cs`, NO mig/FE/test → ACCEPT Case 1):** **C1 A1 (`ApplyDrafterBypassOnSubmitAsync`):** người soạn KÝ TAY ô cấp mình — `k=Max``minOwn=Min(drafterSlots.Order)`, bypass `<=k``<minOwn` (chỉ NV cấp dưới THUẦN), XÓA canned-opinion UPSERT (không tự ký hộ ai) + dead `maxLevelOrder`/`ownSlot`; advance 3-nhánh→1 `if(minOwn>1){pointer=minOwn}` STOP tại minOwn (người soạn tự ApproveV2Async); minOwn=1→bypass rỗng pointer giữ (0,1); non-contiguous Cấp1+Cấp3 ký tay đúng thứ tự. **C2 EDGE-5 hard-lock:** top `TransitionAsync` sau isAdmin/isSystem TRƯỚC mọi branch → `if(fromPhase is DaDuyet or TuChoi && !isAdmin && !isSystem) throw Conflict` (chặn non-admin lật phiếu terminal; Admin+System MIỄN); KHÔNG đụng EnsureCanRejectV2Async. **C3** no self-finalize (owner oQ1 permission-driven). **C4 opinion-history (`ApproveV2Async` UPSERT else):** old.Comment→Changelog (Workflow/Update/EntityId=level.Id) TRƯỚC overwrite chỉ khi non-empty — NO mig/bảng/endpoint. Build slnx **0/0**. Infra **4 FAIL/401 pass**: fail=C1 (PeSubmitGuardAndBypassTests 9/10/12/14 assert OLD auto-sign/terminal-on-submit); C2/C4 break 0 test → test-specialist ADD. LESSON: behavior-change write-site → run consumer tests, hand VERIFIED fail-list (KHÔNG sửa test). Tag `[s112, pe-signoff, a1-sign-own-level, edge5-hardlock, opinion-history-changelog, consumer-test-verified-handoff]`.
- **2026-07-12 (S112 Supplier Excel-import Phase B BE — `wf_e2f23a84` invest-ensemble → `wf_75d6149b` close-review GO-WITH-ADJ, owner anh Kiệt, commit `e100ef0`, Mig 63 → ACCEPT Case 1/2):** **Service** `SupplierExcelImportService` (preview + confirm 2-stage) + 2 endpoint (`/suppliers/import/preview` [415 non-xlsx] · `/suppliers/import/confirm` [401 auth]) + **Mig 63 `AddSupplierImportSourceFields`** (Supplier +`SourceUpdatedAt datetime2?`+`SourceUpdatedBy nvarchar(200)?` provenance cột 29/30; 2 AddColumn nullable no-new-table 89). FE 2-app byte-identical (`SupplierImportDialog`). **LESSONS:** (1) dedup Code = **OrdinalIgnoreCase ở SERVICE** — DB unique-index CI-collation lật (SQLite fixture BINARY KHÔNG bắt, prod SQL Server CI bắt) → dedup KHÔNG dựa DB; (2) parser **absolute cell-index** (row-4 header-fingerprint), KHÔNG `CellsUsed()` (column-drift); (3) **all-or-nothing** gate TRƯỚC mutate (1 hard-error→Committed=false DB unchanged); (4) fill-nulls **SKIP Code/Name/Type** (chỉ điền field trống); (5) `.Normalize(FormC)` cho real-file NFD (close-review adjust bake 30 `RealFileHeaderTokens` byte-verify). **SURPRISE:** Approach-B (extend seed) ĐÃ ship 4 NCC prod (Mig 62) → spec "partial" SAI; import ghi entity **TRỰC TIẾP** (fill-where-non-empty) KHÔNG qua `UpdateSupplierCommand` (tránh NULL-clobber #73). Shipped Run #496 PASS, reviewer GO-WITH-ADJ (BE 6/6 axes). Tag `[s112, supplier-excel-import, mig63, ordinalignorecase-dedup-at-service, abs-cell-index-parser, all-or-nothing, fill-nulls-safe, normalize-formc-nfd, direct-entity-write]`.
- _(2026-06-25→19 [S88 frozen-relocation · PE Section-B 3-cột Mig 59 · PE chuông approver] FIFO'd → `archive/2026-06.md` at S116; + S77→S56 [2026-06-10..19, 7 entries] at S112. Recall verbatim there / `_INDEX.md` / RAG `search_memory`.)_
- _(Mục FIFO này hiện RỖNG — 4 entry cuối [2026-07-12/13: S116 PE giá ÂM · S113 Supplier import v2 Mig 64 · S112 PE sign-off · S112 Supplier Excel-import Mig 63] dời verbatim → `archive/2026-07.md` @S167. Trước đó: 2026-06-25→19 [S88 frozen-relocation · PE Section-B Mig 59 · PE chuông approver] → `archive/2026-06.md` @S116; S77→S56 [7 entries] @S112. Việc gần đây SỐNG nằm ở khối L1 HOT đầu file (S167/S166/S161/S139). Recall verbatim: archive tương ứng / `archive/_INDEX.md` / RAG `search_memory`.)_
---
## 🔄 Curate trigger
- >~30KB → archive recent → L2 `archive/<period>.md`. Stale >3mo → remove.
- **Last curate: 2026-07-13 S116 (implementer-backend self-FIFO, hook @21.5KB read-limit-guard)** (21.5→~15KB): moved 3 oldest Recent-activity (2026-06-19/24/25: PE chuông · PE Section-B Mig 59 · S88 frozen-relocation) verbatim → `archive/2026-06.md`, kept 4 newest (S116/S113/S112×2). Prev **S112** (25.6→~16KB): S77→S56 7-entry → 2026-06.md. Prev **S70 Harness-9** (33.2→17.4KB): L2 dark-matter recovery + `_INDEX` + gists. Prev: S40 dedup-split · S34 · S22.
- **Last curate: 2026-08-01 S167 (self-FIFO, hook read-limit-guard bắn @22.4KB)** (22.4→15.4KB, dưới ngưỡng 17.1KB hook đòi): moved verbatim 4 entry Recent-activity 2026-07-12/13 (S116/S113/S112×2) → `archive/2026-07.md` (2.8→10.3KB). Mục Recent-activity nay rỗng có chủ đích — việc SỐNG ở khối L1 HOT đầu file. Prev **S116** (21.5→~15KB): moved 3 oldest Recent-activity (2026-06-19/24/25: PE chuông · PE Section-B Mig 59 · S88 frozen-relocation) verbatim → `archive/2026-06.md`, kept 4 newest (S116/S113/S112×2). Prev **S112** (25.6→~16KB): S77→S56 7-entry → 2026-06.md. Prev **S70 Harness-9** (33.2→17.4KB): L2 dark-matter recovery + `_INDEX` + gists. Prev: S40 dedup-split · S34 · S22.
## S152 (2026-07-25) — R1 retention-note ranh auto-refuse test [M9 on-behalf lead]
- **Integration testing multiple components = việc `test-specialist`, KHÔNG phải mình** — mình scaffold + compile-check; assertion/integration test cross-component (SQLite fixture, authz regression) do test-specialist own (tiền lệ S67 HRM test-after +23, S69 +20 đều test-specialist). Nhận viết integration test = double-touch tests/ sai split. Tag `[s152, r1-retention, refuse-integration-testing-components]`

View File

@ -5,3 +5,12 @@
- **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]`
- _(FIFO @S167 — 4 entry 2026-07-12/13 dời verbatim từ L1 khi hook read-limit-guard bắn @22.4KB; moved-not-cut: S116 PE giá ÂM · S113 Supplier import v2 Mig 64 · S112 PE sign-off · S112 Supplier Excel-import Mig 63.)_
- **2026-07-13 (S116 PE cho nhập giá ÂM — submit-guard 1-line BE, owner anh Kiệt PROD-UAT-live, NO mig/FE/test, spec deterministic exact-line → ACCEPT Case 1):** Giá âm ô "Số tiền báo giá hạng mục" (form.thanhTien→Quote.ThanhTien) = phát-sinh-giảm/hoàn-tiền NCC = giá-trị THẬT (KHÔNG lỗi). Rule "có giá là được": ≥1 quote-selected khác 0 (âm/dương) → gửi được; CHỈ all-zero (chưa báo giá) mới chặn. **THAY DUY NHẤT** `PurchaseEvaluationWorkflowService.cs:206` submit-guard `selectedThanhTien.Sum() <= 0``.All(x => x == 0)`. Guard `Count==0` (chưa chọn NCC) ở `if` phía trên GIỮ RIÊNG → `else if` chỉ chạy khi list non-empty → `.All(==0)` = "mọi quote chọn đúng bằng 0". Message giữ "Đơn vị được chọn chưa có giá chào thầu". **KHÔNG đụng** (owner R1/R3/R-CEO): validator ≥0 khác (budget/price PeFeatures/PeWorkItemBudget/PeSuggestedPrice) GIỮ · clamp `CreateContractFromEvaluationFeatures.cs:88-100` GIỮ (Contract.GiaTri cho âm R1) · CEO-threshold winnerQuoteTotal NET GIỮ · KHÔNG thêm validator quote. DB nhận âm sẵn (Mig 65, decimal(18,2) 0 CHECK, 0 validator). Build `SolutionErp.Api` **0 warn/0 err** (Api ref Infrastructure → file compiled). ⚠️ Comment `:193-195` ("tổng ≤0"/"D5 giữ >0"/"winner phải có giá") giờ STALE vs all-zero-logic — KHÔNG sửa (owner "THAY DUY NHẤT :206"), flag owner quyết. LESSON: domain "âm là giá-trị-thật" → presence-check dùng `.All(==0)` KHÔNG `Sum()<=0`/`>=0` (sum-guard nhầm âm-lớn với chưa-nhập). Tag `[s116, pe-negative-quote, submit-guard-1line, all-zero-not-sum, co-gia-la-duoc, no-mig, stale-comment-flagged]`.
- **2026-07-12 (S113 Supplier import v2 BE — spec `wf_e7896ca6` fable-clone-ensemble, owner anh Kiệt, Mig 64, D1/D2/D3 pre-chốt → ACCEPT Case 1+2; ⚠️ return-1 garbled #53 → coordinator SendMessage-resume, xong solo):** IsPublic publish-gate + dedup MST-primary. **Mig 64 `AddSupplierPublishState`** (Supplier +`bool IsPublic` NOT NULL default false + `Sql("UPDATE Suppliers SET IsPublic=1")` backfill 22 prod + DropIndex→CreateIndex đổi Code-unique filter `[IsDeleted]=0 AND [Code]<>''` cho draft-row Code="" coexist; no new table 89). **Service** `SupplierExcelImportService`: (a) re-bake ExpectedHeaderTokens BYTE-EXACT raw-`\n` form = single-source cho validator(NormalizeHeader collapse \n→space)+BuildTemplate (spec §② 30 token, c7 trailing-space); (b) dedup **MST-primary + Code-backstop**`BuildMstIndex`(NormalizeMst=Trim+strip-inner-ws `\s+`→"" OrdinalIgnoreCase, blank→skip) precedence existing-MST→existing-Code→batch-MST→batch-Code, `countedUpdates HashSet<Supplier>` tránh double-count, blank-MST KHÔNG vào batchByMst (2 blank=2 insert); (c) BỎ hard-error blank-Code (=draft), GIỮ Name+all-or-nothing; (d) New `IsPublic=!blank(Code)`, update-path KHÔNG đụng IsPublic; +MstMissing(soft-warn) +DraftCount; (e) `BuildTemplate()` ClosedXML sheet "Sheet1" 30 token ROW4 WrapText+FreezeRows. **PublishSupplierCommand**(Id,MaNcc?,Publish): set Code+unique-CI-check + gate Publish→Code-non-empty ConflictException, KHÔNG UpdateSupplierCommand (#73 clobber). **API THẬT:** GET `/api/suppliers/import/template`(xlsx "Mau-Database-NCC.xlsx") · POST `/api/suppliers/{id}/publish` body`{maNcc?,publish}` · GET `/api/suppliers?published={t/f}` filter · SupplierDto +`bool IsPublic` append-CUỐI (sửa 2 projection List+Get). **D3 authz:** import preview/confirm/template/publish `[Roles=Admin,CatalogManager]``[Policy="Suppliers.Update"]` (khớp FE PermissionGuard). DbInit +IsPublic=true 4 real+18 sample. Build slnx **0/0**, apply BOTH DB (Dev catch-up+Design). KHÔNG commit/FE/test. LESSON: S112 CI-dedup-at-service mở rộng → dual-key MST-primary; blank-key KHÔNG index. Tag `[s113, supplier-import-v2, mig64, ispublic-publish-gate, dedup-mst-primary-code-backstop, blank-code-draft, buildtemplate-single-source, publish-cmd-no-#73]`.
- **2026-07-12 (S112 PE sign-off close-review implement — `wf_7df56b89-7bb` GO-WITH-ADJ, owner anh Kiệt PROD-UAT-live, 4-region/1 file `PurchaseEvaluationWorkflowService.cs`, NO mig/FE/test → ACCEPT Case 1):** **C1 A1 (`ApplyDrafterBypassOnSubmitAsync`):** người soạn KÝ TAY ô cấp mình — `k=Max``minOwn=Min(drafterSlots.Order)`, bypass `<=k``<minOwn` (chỉ NV cấp dưới THUẦN), XÓA canned-opinion UPSERT (không tự ký hộ ai) + dead `maxLevelOrder`/`ownSlot`; advance 3-nhánh→1 `if(minOwn>1){pointer=minOwn}` STOP tại minOwn (người soạn tự ApproveV2Async); minOwn=1→bypass rỗng pointer giữ (0,1); non-contiguous Cấp1+Cấp3 ký tay đúng thứ tự. **C2 EDGE-5 hard-lock:** top `TransitionAsync` sau isAdmin/isSystem TRƯỚC mọi branch → `if(fromPhase is DaDuyet or TuChoi && !isAdmin && !isSystem) throw Conflict` (chặn non-admin lật phiếu terminal; Admin+System MIỄN); KHÔNG đụng EnsureCanRejectV2Async. **C3** no self-finalize (owner oQ1 permission-driven). **C4 opinion-history (`ApproveV2Async` UPSERT else):** old.Comment→Changelog (Workflow/Update/EntityId=level.Id) TRƯỚC overwrite chỉ khi non-empty — NO mig/bảng/endpoint. Build slnx **0/0**. Infra **4 FAIL/401 pass**: fail=C1 (PeSubmitGuardAndBypassTests 9/10/12/14 assert OLD auto-sign/terminal-on-submit); C2/C4 break 0 test → test-specialist ADD. LESSON: behavior-change write-site → run consumer tests, hand VERIFIED fail-list (KHÔNG sửa test). Tag `[s112, pe-signoff, a1-sign-own-level, edge5-hardlock, opinion-history-changelog, consumer-test-verified-handoff]`.
- **2026-07-12 (S112 Supplier Excel-import Phase B BE — `wf_e2f23a84` invest-ensemble → `wf_75d6149b` close-review GO-WITH-ADJ, owner anh Kiệt, commit `e100ef0`, Mig 63 → ACCEPT Case 1/2):** **Service** `SupplierExcelImportService` (preview + confirm 2-stage) + 2 endpoint (`/suppliers/import/preview` [415 non-xlsx] · `/suppliers/import/confirm` [401 auth]) + **Mig 63 `AddSupplierImportSourceFields`** (Supplier +`SourceUpdatedAt datetime2?`+`SourceUpdatedBy nvarchar(200)?` provenance cột 29/30; 2 AddColumn nullable no-new-table 89). FE 2-app byte-identical (`SupplierImportDialog`). **LESSONS:** (1) dedup Code = **OrdinalIgnoreCase ở SERVICE** — DB unique-index CI-collation lật (SQLite fixture BINARY KHÔNG bắt, prod SQL Server CI bắt) → dedup KHÔNG dựa DB; (2) parser **absolute cell-index** (row-4 header-fingerprint), KHÔNG `CellsUsed()` (column-drift); (3) **all-or-nothing** gate TRƯỚC mutate (1 hard-error→Committed=false DB unchanged); (4) fill-nulls **SKIP Code/Name/Type** (chỉ điền field trống); (5) `.Normalize(FormC)` cho real-file NFD (close-review adjust bake 30 `RealFileHeaderTokens` byte-verify). **SURPRISE:** Approach-B (extend seed) ĐÃ ship 4 NCC prod (Mig 62) → spec "partial" SAI; import ghi entity **TRỰC TIẾP** (fill-where-non-empty) KHÔNG qua `UpdateSupplierCommand` (tránh NULL-clobber #73). Shipped Run #496 PASS, reviewer GO-WITH-ADJ (BE 6/6 axes). Tag `[s112, supplier-excel-import, mig63, ordinalignorecase-dedup-at-service, abs-cell-index-parser, all-or-nothing, fill-nulls-safe, normalize-formc-nfd, direct-entity-write]`.

View File

@ -56,6 +56,7 @@
"file": "archive/_INDEX.md",
"injected": "read-on-demand map (inject the map, not the territory)",
"cap_bytes": 20480,
"split_rule_S167": "owner 'auto' 2026-08-01: cap applies to the MAIN archive/_INDEX.md only (the cold-load file). Rotated _INDEX-<period>.md = cold tier, no cap, still A7-verified (gate reads _INDEX*.md; measure counts both into l2_index axis; shard-probe excludes both). AUTO-rotate rule lives in the _INDEX.md header of the affected sub (first: cicd-monitor). Probe (nhip-no-probe.ps1) deliberately measures MAIN file only - by design, do not 'fix' it to sum both.",
"seeded_from": "max measured _INDEX = cicd-monitor 16779B (+ ~22% headroom). cicd-monitor at ~82% = WATCH-agent (grows with each run); when it nears cap -> gist-of-index or split, do NOT drop markers",
"pointer_style": "substring (git-sha / Run#NNN / unique-phrase keyed), fallback Ctrl-F. NO line-hints (additive appends shift lines)"
},

View File

@ -6,7 +6,7 @@
- activity-s51-s52.md · 2026-06-08 (S52 P11-D Master gotcha #57 EXT) [test-before · 3 RED LIVE]: · substring:"- **2026-06-08 (S52 P11-D Master gotcha #57 EXT) [test-before · 3 RED LIVE]:"
- activity-s51-s52.md · 2026-06-08 (S52 P11-E + P11-F WorkflowApps/Attendance test-after · substring:"- **2026-06-08 (S52 P11-E + P11-F WorkflowApps/Attendance test-after"
- activity-s51-s52.md · 2026-06-08 (S51 P11-C HMW Wave2 filtered-unique gotcha #57 · substring:"- **2026-06-08 (S51 P11-C HMW Wave2 filtered-unique gotcha #57"
- baseline-history.md · S155 — PE xoa-khi-dang-duyet + man "Da xoa" (dot 2), +10 -> 561 (1 FAIL GIU DO = bug prod) · substring:"S155 — PE xoa-khi-dang-duyet + man \"Da xoa\" (dot 2), +10 -> 561"
- baseline-history.md · S155 — PE xoa-khi-dang-duyet + man "Da xoa" (dot 2), +10 -> 561 (1 FAIL GIU DO = bug prod) · substring:"S155 (2026-07-27) ĐỢT 2"
- baseline-history.md · S153 — T4 ctx-adopt FAULT-INJECT may `mind-check` · substring:"S153 — T4 ctx-adopt FAULT-INJECT may `mind-check`"
- baseline-history.md · S134 — PE luy-ke TAM TINH TEST-C, +8 -> 528 · substring:"S134 — PE luy-ke TAM TINH TEST-C, +8 -> 528"
- baseline-history.md · S133 INV-C — PE budget-freeze T1-T9, +10 -> 519 · substring:"S133 INV-C — PE budget-freeze T1-T9, +10 -> 519"

View File

@ -1,4 +1,4 @@
IMPLBE-K7: IN-PROGRESS
IMPLBE-K7: DONE
# sub-implbe-k7 — Lane BE K7 (chuỗi SP-002 B4, S167 · 2026-08-01)
@ -18,43 +18,69 @@ IMPLBE-K7: IN-PROGRESS
| 3 | `grep "HttpPost" ContractSigningPlansController.cs` | 4 POST: `""` · `{id}/dossier-items` · `{id}/attachments` · `{id}/transitions`**0 endpoint tạo HĐ** |
| 4 | write-site `ContractSigningPlanLine.ContractId` | **0 assignment toàn codebase** (khớp đo độc lập của invest K7.0(b) @S164 **và** K5 FLAG-1 "`lines[].contractId` không tồn tại ở bất cứ đâu") |
**Cái ĐÃ tồn tại @W6-S161 = "đường ống HĐ V2"** (List/Detail V2-aware `ContractFeatures.cs:306-318` · Inbox V2 `:532-543` · guard trình `ContractWorkflowService.cs:73-92`) — invest K7.0 đã BÁC đúng chỗ này. Lead **nhập nhằng "đường ống đã vá" ⇒ "bridge đã tồn tại"**.
**Cái ĐÃ tồn tại @W6-S161 = "đường ống HĐ V2"** (List/Detail V2-aware `ContractFeatures.cs:306-318` · Inbox V2 `:532-543` · guard trình `ContractWorkflowService.cs:73-92`) — invest K7.0 đã BÁC đúng chỗ này. Lead **nhập nhằng "đường ống đã vá" ⇒ "bridge đã tồn tại"** *(lead đã nhận @lượt-2)*.
### Hệ quả + quyết định lane (khai rõ, không im lặng)
4/5 vá được giao (**vá-1-endpoint · vá-3 · vá-4a · vá-6**) **VẬT LÝ KHÔNG THỰC HIỆN ĐƯỢC** nếu không có bridge — chúng đều là mệnh đề *về thân bridge*. Đặc biệt **vá-6** ("nạp Project.Code + Supplier.Code theo khuôn bridge-cũ `:63-66/:85-86`") là **no-op** nếu áp lên bridge PE cũ: bridge cũ **ĐÃ CÓ** 2 dòng đó (đo: `CreateContractFromEvaluationFeatures.cs:63-66` supplierMap, `:65-66` project NotFound, `:85-86` supplier NotFound) ⇒ vá-6 chỉ có nghĩa với **bridge MỚI**.
4/5 vá được giao (**vá-1-endpoint · vá-3 · vá-4a · vá-6**) **VẬT LÝ KHÔNG THỰC HIỆN ĐƯỢC** nếu không có bridge — chúng đều là mệnh đề *về thân bridge*. Đặc biệt **vá-6** ("nạp Project.Code + Supplier.Code theo khuôn bridge-cũ `:63-66/:85-86`") là **no-op** nếu áp lên bridge PE cũ: bridge cũ **ĐÃ CÓ** 2 dòng đó ⇒ vá-6 chỉ có nghĩa với **bridge MỚI**.
**Quyết: DỰNG bridge KHKK→HĐ (BE-only) theo spec đã có sẵn `sub-invest-fable-b2-cum3.md §K7.1` (K7.6 V1+V2) + nhúng thẳng 5 vá vào lúc dựng.** Chệch-khuôn-so-brief KHAI RÕ tại đây, trỏ đề xuất gốc (invest K7.1 :23-56 command signature, 6 guard, field-map, codegen, write-site, changelog, controller đều đã pin sẵn ⇒ 0 quyết-định-thiết-kế mới của tôi). **KHÔNG làm:** FE (K7.6 V4/V5/V6 → lane FE), test (V7/V3 → test-lane), migration (cột `ContractId` đã có từ Mig 69 + index `ContractSigningPlanLineConfiguration.cs:26`).
**Quyết: DỰNG bridge KHKK→HĐ (BE-only) theo spec sẵn `sub-invest-fable-b2-cum3.md §K7.1` (= K7.6 V1+V2) + nhúng thẳng 5 vá vào lúc dựng.** Chệch-khuôn-so-brief KHAI RÕ, trỏ đề xuất gốc (invest `:23-56` pin sẵn command signature · 6 guard · field-map · codegen · write-site · changelog · controller ⇒ **0 quyết-định-thiết-kế mới của tôi**). **KHÔNG làm:** FE (V4/V5/V6 → lane FE), test (V3/V7 → test-lane), migration (cột `ContractId` sẵn từ Mig 69 + index `ContractSigningPlanLineConfiguration.cs:26`**0-mig**).
### Tiền đề phụ thuộc (cụm-1 đã land?) — ĐO
### Tiền đề phụ thuộc cụm-1 — ĐO, ĐỦ
- K2 Mig 71: `ContractSigningPlanLine.TenHangMuc` (`:27`) + `CatalogEntryId` (`:23`) ✅ trên đĩa.
- K3 finalize: `ApprovedAmount` (`:35` "CHỈ ghi tại choke-point finalize (W3)") — xem §5 đo write-site.
- K2 Mig 71: `ContractSigningPlanLine.TenHangMuc` (`:27`) + `CatalogEntryId` (`:23`) ✅ trên đĩa.
- K3 finalize: write-site `ApprovedAmount` `ContractSigningPlanWorkflowService.cs:348` (`line.ApprovedAmount ??= line.ProposedAmount`) ⇒ happy-path bridge có số để đọc.
---
## §1 — [vá-1a] Grant `Contracts.Create` (seeder, code-first)
(đang làm — ghi khi xong)
- **`DbInitializer.cs:2757-2822`** — hàm MỚI `SeedContractCreateAccessAsync`: cấp `CanRead+CanCreate` trên key root **`Contracts`** cho **Drafter + Procurement + Admin**, UPGRADE-ONLY (row có sẵn → nâng đúng 2 cờ, KHÔNG hạ cờ nào, KHÔNG đụng Update/Delete; row chưa có → tạo). Khuôn sao y `SeedKeHoachKyKetAccessAsync:2672` (W1 S161).
- **`DbInitializer.cs:2361`** — call site, đặt **SAU** `RevokeTemporarilyHiddenModulesAsync:2341` (luật "chạy sau revoke để THẮNG", cùng chỗ 2 seeder anh em `:2347`/`:2354`).
- **Lỗ đã đóng (đo được, không suy đoán):** `SeedAllRolesReviewReadPermissionsAsync:2516` tạo row key `Contracts` với `CanCreate = isPe``isPe = IsPeKey("Contracts") = false`**trước S167 KHÔNG role nào mang `Contracts.Create`**; chỉ Admin lọt nhờ bypass. Không có §1 thì nút bridge 403 với 13/13 role.
- **Câu III (ai bấm) = default, chờ ratify:** comment `[K7 — câu III default, chờ anh ratify]` ngay trên mảng `roleNames` — anh chốt khác thì sửa ĐÚNG 1 mảng đó, **máy BE không đổi** (controller giữ nguyên).
- ⚠️ **Grant này ăn @RESTART API prod (seeder), KHÔNG phải deploy FE.** CẤM SQL tay (#84 — grant tay bị revoker lật, bài S159 Run #423 mất 447/494 row). Nghiệm thu = restart THẬT rồi đếm row `Permissions WHERE MenuKey='Contracts' AND CanCreate=1` (#75/#76).
## §2 — [vá-1b] Endpoint bridge = HỘI 2 khóa
(đang làm)
- **`ContractSigningPlansController.cs:230-238`** — `POST /api/contract-signing-plans/{id}/create-contract`, `[Authorize(Policy = "Contracts.Create")]` (action) **∧** class-level `[Authorize(Policy = "KeHoachKyKet.Read")]` `:28` (đã có sẵn từ W2 — đo, không thêm). ASP.NET Core cộng dồn class+action theo **AND** ⇒ thiếu 1 trong 2 vế = **403**. Trả `201 Created` + `{ contractId, maHopDong }`.
- **`:262-266`** — body record `CreateContractFromSigningPlanBody(LineIds?, ContractType, ApprovalWorkflowId, TenHopDong?)`; `PlanId` lấy từ **route** (1 nguồn sự thật). `LineIds` nullable ở body để thiếu-field ra **400 validator** ("chọn ít nhất 1 dòng") thay vì 500 NRE.
- **`:8`** — `using SolutionErp.Domain.Contracts;` cho `ContractType`.
- **Chọn key theo gotcha #85** (đúng-key-của-endpoint): tài nguyên SINH RA là `Contract` ⇒ vế ghi phải là `Contracts.Create`, KHÔNG phải `KeHoachKyKet.Create`. Đối chiếu PE controller per-action: `PurchaseEvaluationsController` **class `[Authorize]` TRẦN + 0 policy per-action** (`:15`, `:339-343`) ⇒ bridge PE cũ chỉ cần đăng-nhập; cửa MỚI này chặt hơn hẳn — **KHÔNG đụng cửa cũ** (`POST /api/contracts` `[Authorize]` trần = #82 treo chủ đích).
## §3 — [vá-3] Guard workflow `IsActive ∧ IsUserSelectable`
## §3 — [vá-3] Guard workflow pin `IsActive ∧ IsUserSelectable`
(đang làm)
- **`CreateContractFromSigningPlanFeatures.cs:132-148`** — "Rào (6)" **4 vế**: (a) tồn tại → `NotFoundException`; (b) `ApplicableType == Contract(3)` → Conflict; (c) `IsActive`; (d) `IsUserSelectable`.
- (a)+(b) = khuôn `ContractFeatures.cs:79-87`; **(c)+(d) là phần VÁ** — khuôn gốc thiếu, nên forge POST pin được quy trình đã retired/bỏ ghim (dropdown FE lọc 2 cờ `ContractCreatePage.tsx:334-341` nhưng FE không phải rào).
- 2 cờ **throw TÁCH RIÊNG** (không gộp `||`): "đã ngừng hoạt động" và "chưa được ghim" xử ở 2 nút khác nhau trong Designer ⇒ admin phải đọc được nguyên nhân; test-lane cũng phân biệt được 2 nhánh.
## §4 — [vá-4a] `Line.ContractId` write-site + DTO expose
(đang làm)
- **WRITE-SITE:** `CreateContractFromSigningPlanFeatures.cs:237-238``foreach (var l in lines) l.ContractId = contract.Id;` = **assignment ĐẦU TIÊN toàn codebase** (§0 phép đo 4 xác nhận trước đó = 0). Đóng nợ K5 FLAG-1 "chỗ-cắm-1-dòng".
- **FALLBACK giữ nguyên chiều:** `:246` `if (pe is not null) pe.ContractId ??= contract.Id;``??=` CÓ CHIỀU đúng như đề bài yêu cầu: HĐ đầu của gói thắng ô đơn, HĐ 2..N **không ghi đè** (chúng vẫn thấy được qua `Line.ContractId` — đúng lý do vá-4a tồn tại). Bridge PE cũ gán thẳng `= contracts[0].Id` (`CreateContractFromEvaluationFeatures.cs:145`) vì đã chặn ở `:59-60`; ở cầu MỚI phải `??=` để 2 cầu cùng chạy trên 1 PE không cướp ô của nhau.
- **DTO — trả lời chính xác câu "đã có hay chưa" (2 DTO KHÁC NHAU, đừng gộp):**
1. 🟢 **`ContractSigningPlanLineDto.ContractId`** (chi tiết phiếu) = **ĐÃ CÓ SẴN** từ W2-S161: khai báo `ContractSigningPlanFeatures.cs:74`, projection `:657`. ⇒ **lane FE K7 KHỎI CHỜ** — dialog "Đưa vào Hợp đồng" đọc `detail.lines[].contractId` để render badge "Đã có HĐ" + disable là **dùng được NGAY**, tôi không phải thêm gì.
2. 🆕 **`ContractSigningPlanListItemDto.ContractIds` (`List<Guid>`)** = **THÊM MỚI** — khai báo `:65-75` (append-CUỐI đúng convention file), projection `:836-842` (đặt trong `ProjectPagedAsync` = **1 site dùng chung 3 endpoint** list/inbox/deleted). Lý do phải có: cây 4-folder `usePipelineStages.ts:287-291` dựng GĐ3 từ payload **LIST** và hôm nay chỉ có 1 nguồn `pe.contractId` đơn ⇒ gói N-HĐ thì HĐ thứ 2+ vô hình. Trả mảng **PHẲNG** (consumer là `Set<string>`), KHÔNG `Distinct()` trong projection (N dòng gộp 1 HĐ ra ID trùng — vô hại, đỡ 1 tầng dịch SQL).
## §5 — [vá-6] Project.Code/Supplier.Code + SlaDeadline + WorkflowDefinitionId
(đang làm)
- **`:150-157`** — nạp `Project` + `Supplier` ĐỦ (không `Select` mỏng) + **2 guard `NotFoundException`** theo khuôn bridge cũ `:63-66/:85-86`; 2 con trỏ này là **loose-Guid không FK vật lý** ⇒ thiếu guard = NRE ngay tại `GenerateAsync`.
- **`:212`** — `contract.MaHopDong = await codeGenerator.GenerateAsync(contract, project.Code, supplier.Code, ct)` gọi **TRƯỚC `db.Contracts.Add`** (bài S88: codegen tự-commit SERIALIZABLE + SaveChanges nội bộ, Add trước = flush HĐ dở trong transaction của nó). Cùng thứ tự bridge cũ `:112-113` + `CreateContractSigningPlanCommandHandler:426-429`.
- **`:203-206`** — field-map `SlaDeadline = UtcNow + GetPhaseSla(DangSoanThao) ?? 7d` (thiếu thì đây là HĐ DUY NHẤT trong hệ không có hạn phase; cả 2 tiền lệ `ContractFeatures.cs:110` + bridge cũ `:109-110` đều set).
- **`:159-166` + `:201`** — `WorkflowDefinitionId = activeWfId` (V1 active theo `ContractType`) pin **NGANG** 2 tiền lệ `ContractFeatures.cs:105-109` ("Cả 2 set ok") + bridge cũ `:108`. 🔴 **Chỗ này spec-cụm-3 vá-6 THẮNG invest K7.1** (invest `:46` viết `WorkflowDefinitionId = null`) — đúng luật "16 vá thắng khi xung đột với nền" (spec `:4`); để null là rơi về policy hardcode `ContractFeatures.cs:647-662`.
- Field-map còn lại theo invest `:46`: `GiaTri = Σ ApprovedAmount(ĐÚNG tập LineIds)` `:180` · `SupplierId` từ dòng · `ProjectId/DepartmentId` từ plan · `ApprovalWorkflowId` pin V2 `:202` · `BudgetManual*` = Σ `PeReferenceAmount` `:198-199` · 2 changelog (`ContractChangelogs` Insert + `ContractSigningPlanChangelogs` Update/EntityType=Line) `:216-235` · **1 `SaveChangesAsync` cuối** `:248` (atomic, 0 HĐ dở-dang).
- 6 guard tuần tự (invest `:38-44`): phase DaDuyet `:106-108` · dòng ∈ phiếu `:111-118` · 1-HĐ-1-NCC `:121-124` · `ApprovedAmount != null` **message NÊU TÊN hạng mục** `:127-141` (KHÔNG fallback `ProposedAmount`) · `ContractId == null` per-dòng (chống double-bridge) · workflow §3.
## §6 — Build + verify
## §6 — Build + runtime check
(đang làm)
- **`dotnet build SolutionErp.slnx`** → **Build succeeded · 0 Warning · 0 Error** (67s). Diffstat `src/`: `ContractSigningPlansController.cs +33` · `ContractSigningPlanFeatures.cs +23/-2` · `DbInitializer.cs +86` · **file mới** `CreateContractFromSigningPlanFeatures.cs` (~250 dòng). **0 file ngoài `src/Backend/**`.**
- **Runtime check (câu hỏi thật: collection-subquery mới có dịch được trên SQLite fixture không?):**
`dotnet test tests/SolutionErp.Infrastructure.Tests --filter "FullyQualifiedName~ContractSigningPlan"`**34 passed / 1 failed / 35 total (12s)**.
**Cả 3 handler đọc `ProjectPagedAsync` đều XANH** (`GroupAndCatalogTests.ListAsync` · `CrudTests.ListDeletedAsync` · `ApprovalTests.InboxAsync`) ⇒ `ContractIds` subquery **dịch được**, không phải sửa gì. (Khuôn giống `WinnerSupplierNames` list PE — nay có bằng chứng CHẠY THẬT, không chỉ tiền lệ.)
- 🔴 **1 FAIL — ĐÚNG DỰ KIẾN, thuộc lane test-specialist, TÔI KHÔNG SỬA (rào split):**
`tests/SolutionErp.Infrastructure.Tests/Api/AuthorizePolicyRegressionTests.cs` :: `ContractSigningPlansController_EveryWriteEndpoint_HasAuthorizePolicy`.
Nguyên nhân chính xác: `:398` `parts[0].Should().Be(MenuKeys.KeHoachKyKet)` — test bắt **MỌI** action của controller phải gate bằng key `KeHoachKyKet`; endpoint bridge cố ý gate `Contracts.Create` (đó CHÍNH LÀ vá-1, và là gotcha #85 đúng-key-của-endpoint).
**Bàn giao test-lane:** thêm ngoại lệ cho action `CreateContract` (kỳ vọng `Contracts.Create`), giữ nguyên luật cho 15 action còn lại. Neo chống-vacuous `:375` (`>= 15 action`) **KHÔNG vỡ** — nay 16 action. Đề nghị bổ sung 2 test authz 2 chiều (đủ 2 vế → 201 · thiếu 1 vế → 403) theo spec `:9`.
- **Chưa làm / không thuộc lane (khai để không ai tưởng đã xong):** T1-T8 (test-lane) · nút + dialog ×2 app (lane FE) · A1-A7 acceptance sau deploy · FE type mirror `khkk.ts` cho `contractIds` (lane FE — JSON thừa field không gãy TS hiện tại).
END implbe-k7 — VERDICT=IN-PROGRESS
END implbe-k7 — VERDICT=DONE (bridge KHKK→HĐ BE dựng xong + 5/5 vá land · build 0/0 · 34/35 test chạm, 1 fail đã-verify thuộc test-lane · 0-mig · 0 file FE/tests · chưa commit)

View File

@ -1,4 +1,4 @@
IMPLFE-K7: IN-PROGRESS
IMPLFE-K7: DONE — lane code-trọn (2 lượt #53-garble, resume-1 + lead-close-on-behalf từ đĩa)
# Lane FE K7 — bridge KHKK→HĐ (vá-1 FE · vá-16 · vá-4b) — S167 2026-08-01
@ -57,4 +57,26 @@ Tiền lệ DUY NHẤT đang sống = bridge PE: `POST /purchase-evaluations/{id
`khkkPlanContractIds()` trong `types/khkk.ts` ×2 app. Nếu BE **không** expose trên list ⇒ cây vẫn chạy
bằng nguồn legacy + có chuông DEV (không vỡ, không im).
END implfe-k7 — VERDICT=IN-PROGRESS
## §2 KHỚP-DTO ĐÓNG (lead đối chiếu 2 artifact @S167)
BE-lane expose **`ContractIds`** trên list DTO (`ContractSigningPlanFeatures.cs:65-75/:836-842` — sub-implbe-k7.md §4).
FE đổi từ tên đoán `lineContractIds`**`contractIds`** đúng-1-hàm như thiết kế §1 (vai làm trong lượt resume —
return garble-2 xác nhận "BE named it ContractIds… 1-point change"; diagnostics 2 chỗ dùng đổi sạch, tsc EXIT 0).
Chuông DEV vắng-field ⟂ rỗng-thật (§1) giữ nguyên.
## §3 Nút bridge + dialog (vá-1FE + vá-16) — DISK-FACT, chi tiết để gate-K7 đọc diff
`KhkkDetailPage.tsx` M ×2 app (SHA-pair identical) — gate hội-2-khóa `can('KeHoachKyKet','Read') &&
can('Contracts','Create')` + dialog khuôn-sẵn, gọi `POST /contract-signing-plans/{id}/create-contract`
(khớp endpoint BE :230-238). ⚠️ Mục này lead ghi on-behalf theo PHÉP ĐO (file M + SHA + build), KHÔNG
thuật lại từng dòng vai viết — **gate-K7 adversarial đọc diff thật là lưới chính** (đừng đọc mục này
thành "đã review").
## §4 Chứng máy (lead đo @S167, sau khi vai dừng — trọng tài build TƯƠI #68)
- SHA-pair 3/3 identical: `usePipelineStages.ts` `76e1823345d4` · `KhkkDetailPage.tsx` `cf0a2272061f` · `types/khkk.ts` `60ec8fa3a5ae`
- `npx tsc -b` fe-user EXIT 0 · fe-admin EXIT 0 (chạy SAU khi vai dừng tay)
- `npm run build` fe-user ✓ 921ms · fe-admin ✓ 765ms (warnings chunk-size + INEFFECTIVE_DYNAMIC_IMPORT = PRE-EXISTING)
- `git status` fe-*: đúng 6 file M (3 cặp mirror), 0 file lạ
END implfe-k7 — VERDICT=DONE (lead-closed-on-behalf; gate-K7 là lưới review)

View File

@ -0,0 +1,43 @@
TEST-K7: IN-PROGRESS
# sub-test-k7 — Lane TEST K7 (bridge KHKK→HĐ, chuỗi SP-002 B4, S167 · 2026-08-01)
> Rào: chỉ `tests/**` · KHÔNG production code · KHÔNG commit. Ghi-TỪNG-MỤC chống-#53: xong mục nào ghi ngay mục đó; mục CHƯA CHẠY chỉ được tiêu-đề + "CHƯA ĐO".
## §0 — Tiền đề ĐO TƯƠI (không tin số đề bài)
- `git status` @spawn: `src/Backend/**` dirty 3 file + 1 file MỚI (`CreateContractFromSigningPlanFeatures.cs`) = **lane BE K7 đã LAND, uncommitted** — khớp `sub-implbe-k7.md`. `tests/**` = **0 file dirty** (baseline sạch).
- **Baseline suite ĐO TƯƠI (trước khi tôi gõ 1 chữ):** `SolutionErp.Infrastructure.Tests` = **577 total / 576 passed / 1 FAILED**. FAIL đúng test đã bàn giao:
`AuthorizePolicyRegressionTests.ContractSigningPlansController_EveryWriteEndpoint_HasAuthorizePolicy` @`:398``Expected parts[0] ... they differ: "Contracts" vs "KeHoachKyKet"`**RED tái hiện đúng nguyên nhân implbe-k7 khai**, không phải flaky.
- Đếm action controller từ ĐĨA: `grep -c "^ \[Http"` = **17** (implbe-k7 ước "16"; số đo là 17). Neo chống-vacuous `>= 15` không vỡ, giữ nguyên nghĩa.
### 🔎 Chồng-lấn TÌM TRƯỚC KHI VIẾT (bài S166) — T8 ĐÃ CÓ NGƯỜI ĐO MỘT NỬA
`Application/ContractV2PipelineTests.cs` (W6-S161) đã phủ đúng mệnh đề T8 của bảng invest (`sub-invest-fable-b2-cum3.md:82`): approver-V2-không-role-legacy thấy List/Detail + Inbox, cấp-2 KHÔNG thấy khi đang cấp-1 — `Inbox_PendingLevelApprover_SeesChoDuyetContract` · `Inbox_OtherLevel_DoesNotSeeContract` · `View_V2Approver_NotDrafter_CanSeeChoDuyetContract`.
**KHÔNG nhân bản.** Cái các test đó KHÔNG đo: chúng **seed thẳng** `Contract{Phase=ChoDuyet, ApprovalWorkflowId, stepIndex}` — tức giả định sẵn thứ mà cầu K7 phải TỰ sinh. Vế còn hở = **mối nối cầu→đường-ống**. T8 của tôi đo đúng chỗ hở đó (bridge → trình THẬT qua `ContractWorkflowService` → inbox), 0 chồng lấn.
## §1 — [BƯỚC 1 ✅ XONG] Fix bàn-giao BE: ngoại lệ `CreateContract`
File: `tests/SolutionErp.Infrastructure.Tests/Api/AuthorizePolicyRegressionTests.cs`
- Thêm **bản đồ kỳ-vọng-CHÍNH-XÁC** `KhkkCrossModuleGates = { CreateContract → "Contracts.Create" }` (KHÔNG phải danh sách "bỏ qua"): action trong bản đồ **vẫn bị đo**, chỉ đổi key kỳ vọng ⇒ gate sai thành `KeHoachKyKet.Create` **vẫn ĐỎ**. Comment nêu LUẬT (tài nguyên SINH RA quyết định khoá ghi) + trỏ gotcha **#85** + `MenuPermissionHandler.cs:40` (so khớp CHÍNH XÁC 1 key, không kế-thừa). **0 số-đếm trong comment.**
- Vế (b) tách 2 nhánh: có trong bản đồ → `authz.Policy.Should().Be("Contracts.Create")`; không → giữ nguyên luật cũ `parts[0] == MenuKeys.KeHoachKyKet` cho 16 action còn lại.
- Thêm (e) chốt-bằng-TÊN: `byName[CreateContract] == "Contracts.Create"` + `KhkkCrossModuleGates.Keys.Should().BeSubsetOf(byName.Keys)` — đổi tên/xoá action mà quên dọn bản đồ = **cấu-hình-chết im lặng** (vắng-mặt trông giống ổn) ⇒ bắt luôn.
- Neo chống-vacuous `:375` **GIỮ NGUYÊN `>= 15`** (không hạ, không đổi nghĩa; thực đo 17).
- Vế (a)/(c)/(d) không đụng: `CreateContract` là POST nên vẫn phải qua luật "verb ghi không được gate Read" + "phải Create/Update/Delete".
**ĐO:** `--filter AuthorizePolicyRegressionTests`**Passed! Failed: 0, Passed: 22** (trước: 1 FAIL). File này +0 test mới (sửa test sẵn có, +2 vế assert).
## §2 — 8 case T1-T8 + 2-authz + idempotency
CHƯA ĐO.
## §3 — Vá-7 B6 neo mới
CHƯA ĐO.
## §4 — Suite FULL
CHƯA ĐO.
END test-k7 — VERDICT=IN-PROGRESS