Pipeline anh lệnh: /check-email + /adap-apply -> /fable-real invest (spec 9-task/24-checklist) -> hmw Opus-5-MAX 2 đợt + lead-solo T6-T8 -> checklist verify. Thư ① 9c909007 (model-default Opus 5 MAX): TRỌN — filing 2-tuyến + probe-sau-restart 2-nguồn claude-opus-5[1m] + thư hub d432f5eab5cd + caveat (e) đóng. Thư ② 0df10df4 (pause-tiep Ctx soft-memory, sàn 7-khoản): EXECUTED - máy mind-check: scripts/session_ctx.py +542 dòng (7 phép + 2 phụ, 4 mức, draft/closed/--root/--session PIN, exit 0/1/3) - template .claude/templates/session-mind-template.md + wire 4 lệnh (pause C-bis+2bis+§1-carve-out, tiep §2.6+§3-ter, session-start Phase 3.5, session-end §L.b(l)+6.3-bis) - memory-budget: mind_ctx_kb=32 + tiep_reload + ĐÓNG ghost-wire session_ctx_kb (H18 class-2 sống S146->S153) - fault-inject 18/18 + 2 fix hậu-T4 (FI 6/6): GAP-#9 closed-mode E-0-con-trỏ CỜ->TRƯỢT (chặn gradient thưởng xoá-con-trỏ-trung-thực, họ bẫy F-1 của chính thư hub) · secrets-sweep +--root parity - số ĐO THẬT pause +117ms thay ước lệch 2.2-5.4x OWNER 2 quyết trong-phiên: - (38) VETO: 1-vai -> hub-form 3-vai (ctx-curator @pause + carve-out pause §1 · ctx-verifier @tiep · ctx-audit @2-bookend) - RENAME theo chuẩn hub/sisters để audit chéo: ctx-pause-check->ctx-curator, ctx-reload->ctx-verifier (đo đĩa 3 nhà; hub≠sister => SE theo HUB-form, tiền lệ S149). Roster 20->23, VALID_ROLES 23. Gap còn lại: ring5-audit (V5 truth-floor) hub CÓ, SE+VIPIX chưa -> slot (41). Bookend 2 đầu (12 spawn) + trio auto 1 vòng: - @open: H1 7f · H2 4f · H24 5+3 FLAG · ring1 28Đ/4T · ring2 8/8Đ + M-1 MISS thật · trio eval-MIXED-14/refine-3A-7B-4N/audit-25Đ-3T (re-chạy 7 instrument, 24 số byte-exact) - @close: H1 6f · H2 8f (baseline S154 = 16/10, tự sửa bản ~23/11) · H24 4+2 FLAG · ring1 47Đ/5T/1KC/53 · ring2 6/6Đ + 21 phép phụ - lead xử 11 mục: 9 FLAG H24 + 3 RESIDUAL ring2 + F-r2 (plugin 3 hard-site) + M-1 cả 2 persona + M9 14 sổ diary + F-3/F-5/F-6 + nit Sàn-5 + BÁC F-4 (fan-out không vào _index) #53 x14-cận-dưới, 0 mất dữ liệu (WRITE-lane derive-from-body · Agent-resume · SendMessage-resume x6). Datum: trio return-only hết miễn nhiễm (3/3 CLEAN -> 1/3). 4-A suýt xảy ra thật (bản committed của 2 file H24 là bản cắt 24%/48%). completeness-gate: 5 vòng đủ · phép ĐẠT 4 / TRƯỢT 0 / vacuous 0. State: Mig 67 · 89 bảng · 532 test · gotcha 83 · Sub-agents 23 · counter 27 · bundle FROZEN · governance-only 0 prod-code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
22 KiB
Implementer-Backend Agent — Persistent Memory
-
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áymind-check— EXTENDscripts/session_ctx.py(+528 dòng, ADD-only:_TS_KEY_REmodule-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/--sessionPIN · exit {0,1,3}. 9 quyết-định thiết-kế có lý-do đo được, đắt nhất: D1 config đọc LAZY — chỉ đọcmemory-budget.jsonkhi 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:lineKHÔ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 personactx-audit11/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ềugrep -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 (đọclead-stale-auditor.md:51-54CHỈ để 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-openUNMAPPED không flag (no-name-guessing) · C11(a)$roleNameRxKHÔ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] -
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/$Hcase-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+PeBudgetSummaryDtoappend-cuối 5 field (2 construction site::946frozen-defaults 0/0/0/0/null ·:985live-fill) + D4 audit-note TRONGApplyBudgetSnapshotOnFinalizeAsync(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.csmới (Domain 11 props ApprovedBudget* + Config precision/maxlength + DTO appendBudgetFrozen=falsecuối positional-record + display-gate frozen/live 2-nhánh trong GetPurchaseEvaluationQuery + helperApplyBudgetSnapshotOnFinalizeAsyncgọ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) + backfillSql()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:TransitionAsyncKHÔNG SaveChanges nội bộ:537→ snapshot flush qua SaveChanges của caller (mirror ApprovedPrice pattern); khuôn backfill THẬT Mig 61/65 = plainSql()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). Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2
archive/on-demand · L3 RAGsearch_memoryjust-in-time. Keep entry ≤ 1.5K chars (gotcha #53). Full verbatim history pre-S40 → gitd2f52ba+archive/2026-05-q1..q4.md+archive/2026-06.md. 🗺️ Lookup map (Harness-9 S70):archive/_INDEX.md— 1 dòng/bản-ghi + con-trỏ substring (sha-keyed, Ctrl-F fallback); đọc verbatim +2026-0{5,6}.gist.md(nén 4-field) theo nhu cầu. Renamed S39: implementer → implementer-backend (.NET half). FE patterns →implementer-frontendMEMORY. Test patterns →test-specialistMEMORY.
🎯 Role baseline
WRITE specialist .NET backend SOLUTION_ERP (Domain+Application+Infrastructure+Api). Case 1+2+3+5 only. Tools: Read, Edit, Write, Bash, Skill, Grep, Glob + 5 RAG MCP. Skills: ef-core-migration + permission-matrix + contract-workflow + form-engine. Output: commits + verify report.
🚫 Split boundary (S39) + auto-refuse
- ✅ MINE:
src/Backend/SolutionErp.{Domain,Application,Infrastructure,Api}/** - ❌ NOT:
fe-*/**→implementer-frontend·tests/**→test-specialist· schema/UX/architecture decision → em main - REFUSE if ANY: 1 schema design (FK/nullable/discriminator) · 2 UX flow · 3 cross-stack >2 layer · 4 bug fix reasoning chain · 5 integration multi-component · 6 <30min trivial · 7 first-time no precedent · 8 spec ambiguity >20%
📋 BE Patterns proven (apply confidently)
Pattern 1: Per-chunk discipline A-E
A Domain+Mig (3-file) · B Application CQRS (Command/Query/Validator) · C Service (workflow logic) · D Api Controller · E commit. Build+test pass mỗi chunk. Commit [CLAUDE] <scope>: Chunk X — ... + Co-Authored-By Claude Opus 4.8 (1M context).
Pattern 2: EF migration 3-file rule (gotcha #17 — BẮT BUỘC commit đủ)
{TS}_{Name}.cs + .Designer.cs + ApplicationDbContextModelSnapshot.cs. Path src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/.
dotnet ef migrations add <Name> --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api
# Apply Dev (runtime): --connection "Server=(localdb)\MSSQLLocalDB;Database=SolutionErp_Dev;Trusted_Connection=True;TrustServerCertificate=true"
# Apply Design (ef default): không cần --connection
Apply BOTH DB per feedback_designtime_runtime_db.
Pattern 3: Audit reuse trước khi clone (feedback_audit_reuse_before_clone)
"Clone X→Y": grep discriminator (ApplicableType/Type/Kind) → check Service/Handler hardcode → check FE route dynamic → check menu key (BE const + FE menuKeys.ts thường thiếu) → default reuse 80%, chỉ thêm menu key + sample seed.
Pattern 4: Service hook vs CRUD endpoint cho derived state (feedback_service_hook_vs_endpoint)
State X derived của action Y → UPSERT trong handler Y, KHÔNG endpoint /X riêng. VD ApproveV2Async UPSERT LevelOpinion qua match ApproverUserId==actorUserId (fallback first khi Admin override). 0 endpoint mới.
Pattern 7: Per-NV admin opt-in flag (Mig 29/30/31)
ApprovalWorkflowLevel +1 bool DEFAULT 0 (opt-in). EF HasDefaultValue(false). DTO extend. FE Designer checkbox inline. Scope role-context → table mapping (Approver→Level table carry ApproverUserId FK, Drafter→User table direct, feedback_per_nv_permission_scope). Reusable F5/F6.
Pattern 8: Tách endpoint riêng cho narrow scope
1 action 2 scope theo role → tách endpoint (guard tự nhiên + audit). VD Drafter UpdatePeDraft (Section 1 rộng, phase Nháp/Trả lại) vs Approver AdjustBudget (Budget rows hẹp, phase Đang duyệt + per-NV flag). KHÔNG default expand Drafter scope cho Approver.
Pattern 9: Defense-in-depth FE+BE guard pair
UI disabled={!canX} + BE helper EnsureCanXAsync(id, userId) throw 403 (NOT inline handler) — tránh forge qua DevTools. Bất kỳ action sensitive (approve/reject/adjust).
Pattern 12-bis: Cross-module entity cookie-cutter mirror (S29 Plan B, proven 3×)
"Mirror entity X từ module A→B": 6 file MAX — (1) new entity Domain/<Mod>/<Entity>.cs rename FK+nav · (2) parent +nav collection · (3) IApplicationDbContext +DbSet · (4) ApplicationDbContext +Set<X>() · (5) new <Entity>Configuration.cs (separate file mirror PE, NOT inline) · (6) dotnet ef migrations add 3-file. AuditableEntity inherit. FK: parent Cascade + 3rd-party Restrict + User skip-nav (denorm <Type>ByFullName). Apply 2 DB. ⚠️ Catalog-mega variant (S35 HrmConfig): HRM entities KHÔNG có global HasQueryFilter(!IsDeleted) (vs Master) → list query MUST .Where(!IsDeleted) thủ công (verify Grep HasQueryFilter Configurations FIRST). Validator MaxLength MATCH EF config (verify source-of-truth, KHÔNG trust spec blind).
Pattern 12-ter: N≤7 satellite CRUD scaffold same parent (S34, feedback_within_module_n_satellite_scaffold)
"N satellite cùng parent" → 1 mega file <Parent>SatelliteFeatures.cs N region cookie-cutter (Create verify parent AnyAsync → Update FirstOrDefault !IsDeleted → Delete soft IsDeleted+DeletedAt+DeletedBy ICurrentUser) + 1 Controller extend (3 verb × N). Endpoint verify parentId==cmd.ParentId BadRequest mismatch. Per-action policy override class-level Read.
Patterns moved (split S39)
- FE patterns (5 mirror 2-app · 6 VND helpers · 13 read-only Designer · 14 Tailwind JIT palette · 15 rowSpan builder · 16-bis 4-place mirror) →
implementer-frontendMEMORY (seeded). - Test patterns (10 reflection authz · 11 test infra helper · 12 InternalsVisibleTo) →
test-specialistMEMORY (seeded).
⚠️ Anti-patterns (DO NOT)
- ❌ Skip MEMORY · 2. ❌
--no-verify· 3. ❌git add -A/git add .(specific files) · 4. ❌ Touch outside spec scope · 5. ❌ Push remote autonomous (em main pushes) · 6. ❌ ModifySolutionErp.slnxautonomous · 7. ❌ Lower bar match em main (Smart Friend) · 8. ❌ Proceed khi ambiguity >20% → REFUSE
🧠 SOLUTION_ERP BE conventions (S40)
- BE .NET 10: PascalCase entities + DTO records + command names. CQRS+MediatR+FluentValidation+AutoMapper. Repository qua
IApplicationDbContext.GlobalExceptionMiddleware→ ProblemDetails (NO try-catch controllers). - State S53: 47 mig (last
FilterMasterCatalogUniqueIndexesByIsDeletedMig 47, index-only) · 93 SQL tables · ~224 endpoints · 203 test (58 Domain + 145 Infra, test-specialist owns). Phase 9 UAT skip per chunk (feedback_uat_skip_verify). - Build:
dotnet build SolutionErp.slnxclean 0 err. Commit[CLAUDE] <scope>: <msg>+ Co-Authored-By Claude Opus 4.8 (1M context). - Pin (KHÔNG
*/latest): MediatR12.4.1(14 fail DI) · Swashbuckle6.9.0· Node CI20.x· LibreOffice25.8.6· @microsoft/signalr8.0.7.
📅 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:206submit-guardselectedThanhTien.Sum() <= 0→.All(x => x == 0). GuardCount==0(chưa chọn NCC) ởifphía trên GIỮ RIÊNG →else ifchỉ 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Ữ · clampCreateContractFromEvaluationFeatures.cs:88-100GIỮ (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). BuildSolutionErp.Api0 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ÔNGSum()<=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_e7896ca6fable-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 64AddSupplierPublishState(Supplier +bool IsPublicNOT 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). ServiceSupplierExcelImportService: (a) re-bake ExpectedHeaderTokens BYTE-EXACT raw-\nform = 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) NewIsPublic=!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}/publishbody{maNcc?,publish}· GET/api/suppliers?published={t/f}filter · SupplierDto +bool IsPublicappend-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-7bbGO-WITH-ADJ, owner anh Kiệt PROD-UAT-live, 4-region/1 filePurchaseEvaluationWorkflowService.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) + deadmaxLevelOrder/ownSlot; advance 3-nhánh→1if(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: topTransitionAsyncsau 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 (ApproveV2AsyncUPSERT 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_e2f23a84invest-ensemble →wf_75d6149bclose-review GO-WITH-ADJ, owner anh Kiệt, commite100ef0, Mig 63 → ACCEPT Case 1/2): ServiceSupplierExcelImportService(preview + confirm 2-stage) + 2 endpoint (/suppliers/import/preview[415 non-xlsx] ·/suppliers/import/confirm[401 auth]) + Mig 63AddSupplierImportSourceFields(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ÔNGCellsUsed()(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 30RealFileHeaderTokensbyte-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 quaUpdateSupplierCommand(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.mdat S116; + S77→S56 [2026-06-10..19, 7 entries] at S112. Recall verbatim there /_INDEX.md/ RAGsearch_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.
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]