Files
solution-erp/.claude/agent-memory/reviewer/archive/2026-06.md
pqhuy1987 7875b39861
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m23s
[CLAUDE] Docs: H-9+H-10+checklist FINALIZE double-check + G1 curate (anh: hoan chinh toan bo)
FINALIZE review wf_73de399d-753 (3 reviewer, R1/R2 no-StructuredOutput->self-gate, R3 thorough): audit 21 checklist item A1-A9/B1-B4/C1-C8 on-disk = 0 code-defect, adoption SOUND, 3 deferred-gap. Closed: G1 curate wf_f32987b8-03f (reviewer 36.7->24.8KB + investigator 29.8->23.2KB <25600 cap, archive +N -0 0-byte-loss, +reviewer-gist gen:2, budget.json re-measure) + G2 (2 stale user-memory claims) + G3 (feedback_harness10_run_trace.md new) + minor (gitignore check-ignore exit-trap corrected). Race root-cause fixed structurally. State unchanged (Mig 53/88 tables/306 test).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 10:06:28 +07:00

32 KiB
Raw Blame History

Reviewer Agent - Archive 2026-06 (S69 curate)

Verbose Recent-activity entries moved from MEMORY.md during S69 Harness-9 curate (L1 over-cap ~43.5KB -> under 28KB). FROZEN / additive-only. Entries are BYTE-EXACT copies from MEMORY.md L1 (newest-first there); ordered here chronological earliest-first. Foundation (role + bug patterns #42/#43/#44/#47 + 6-category checklist + Smart Friend guard + review essentials) + 6 newest activity entries + S49/S43/S35/S33 tail + Smart-Friend-cumulative + archive-pointers KEPT in MEMORY.md. Span: S51 -> S57 (9 entries). See _INDEX.md for the cross-archive table.


Archive entries (chronological - earliest session first)

  • 2026-06-08 (S51 P11-C Vehicle+Driver + gotcha #57 pre-commit — PASS, 1 MAJOR caught) [em main proxy — reviewer return truncated gotcha #53]: Reviewed Mig 44 (Vehicle/Driver catalog) + Mig 45 (filter 3 HRM unique) + FE KIND_CONFIG +2 + 5 tests (186 PASS). Independent build+test re-verify GREEN. CAUGHT 1 MAJOR (Cat 3 cross-stack contract): Driver FE↔BE required-field mismatch — FE render phoneNumber/licenseNumber/licenseClass OPTIONAL nhưng BE validator NotEmpty() + EF .IsRequired() NOT NULL → empty submit = 400/500. Root = inconsistent em-main brief (BE "mirror Vehicle"=required vs FE spec quên required). Fix: FE +required:true (align BE all-required như Vehicle). Cats khác clean (Mig diff clean, Authorize Roles=Admin writes, gotcha #57 grep-complete 3 HRM, DbInitializer idempotent + #51 infra-gated, SHA256 mirror, no copy-paste Driver↔Vehicle). Learned: parallel fan-out (BE∥FE file-disjoint) → bất kỳ inconsistency trong SHARED em-main contract chỉ lộ lúc integration; green tests ≠ correct contract (no test chạm empty-optional path). reviewer = the net. surprise: transient mid-deploy bundle hash (cicd lesson) + reviewer self-truncate trước khi ghi MEMORY → em main proxy. Verdict PASS post-fix. Tag [s51, p11-c, gotcha57, contract-mismatch-catch].

  • 2026-06-08 (S52 P11-E AttendanceReport + P11-F MaTicket codegen pre-commit — PASS, 0 blocker): Migration-free (no schema). Independent re-verify: build 0-err · 191 PASS (58 Dom + 133 Infra, +5: 3 ItTicketCodeGen + 2 AttendanceReport) · fe-admin tsc --noEmit exit 0. Cat3 gotcha #44 attack DISARMED: [Authorize(Roles="Admin")] ×2 report endpoints — verified AppRoles.Admin = "Admin" literal (AppRoles.cs:5) == attribute string == FE user?.roles.includes('Admin'); "QTV" (DbInit:1454) = display-code NOT role-name; pattern proven (Catalogs/HrmConfigs identical). Cat3 camelCase contract MATCH field-for-field BE record PascalCase→FE interface (year/month/rows/grandTotal*/userId/fullName/ot*) — ASP.NET default camelCase, no Program.cs override. BE handler correct: .Year/.Month in IQueryable (EF-translatable DateTime), .DayOfWeek+holidaySet only AFTER .ToListAsync() (in-memory) — IQueryable-translation attack handled; holiday-check BEFORE weekend BEFORE weekday (test 2026-06-01 Mon-but-holiday proves override); DateOnly.FromDateTime correct (Holiday.Date=DateOnly); OtPolicy fallback 1.5/2.0/3.0; IsDeleted via AuditableEntity all 3 entities. Exporter mirrors ContractExcelExporter, ClosedXML 0.105.0, RenderResult(Content,FileName,ContentType) ctor order correct, DI registered. MaTicket codegen: e untracked at codegen time → inner SaveChanges persists ONLY sequence row, no double-insert; gen-on-Create (kanban no-workflow) vs Leave/OT gen-on-Submit — semantically correct; git-show confirms MaTicket was ALWAYS null pre-P11-F (closes gap). 1 MINOR (informational, defer): sequence-gap-on-failure — codegen commits seq in own Serializable tx BEFORE Add(e)+SaveChanges; ticket-insert fail → burned IT/2026/NNN gap. NOT new defect = identical to existing Leave/OT pattern (project-wide accepted trade-off, cosmetic). MyAttendancePage MIRROR divergence intentional+documented (fe-user untouched, §3.9 OK). 0 mock markers. Learned: when spec NAMES an attack vector (gotcha #44 role-string), verify the LITERAL const value not just attribute presence — "QTV" display-code was the decoy; role-name match is the real check. surprise: Bash tool = bash not PowerShell (Select-String fails exit 127 → use grep). Verdict PASS — safe to commit. Tag [s52, p11ef, attendance-report, mat-codegen, gotcha44-disarmed].

  • 2026-06-08 (S52-late Task C ItTicket admin reassign + Task D AttendanceReport menu-key pre-commit — PASS, 0 blocker): Migration-FREE (menu = idempotent DbInitializer seed). 5 prod files: MenuKeys.cs (const+All[]), DbInitializer.cs (1 seed tuple), fe-admin {menuKeys.ts, Layout.tsx staticMap, ItTicketsPage.tsx}. Independent re-verify GREEN: dotnet build SolutionErp.slnx 0-warn/0-err · npm run build fe-admin tsc-b+vite OK (1945 modules, only pre-existing CSS @import + >500KB + ineffective-dynamic-import warns). menuKeyMatchOk: "Off_AttendanceReport" byte-identical 4 places (MenuKeys.cs:125 const == menuKeys.ts:68 == seed parent key == Layout staticMap:87); seed leaf parent=MenuKeys.Off order=8 icon=FileBarChart (verified valid lucide alias FileChartColumn as FileBarChart — getIcon resolves via Icons[name]); App.tsx route /attendance/report → AttendanceReportPage PRE-EXISTING committed S52 (6a66429, no diff, 170-LOC real page not stub) — Layout maps to REAL route. types/menu.ts correctly NOT mirrored (key:string not typed union). admin auto-perm via SeedAdminPermissionsAsync iterating MenuKeys.All (DbInit:1917, idempotent Contains:1919); new-leaf-on-existing-DB confirmed (upsert loop:1845-1862 TryGetValue-miss→Add). reassignCorrect: FE PUT /it-tickets/{id}/assign body {assignedToUserId} MATCHES BE record AssignItTicketBody(Guid AssignedToUserId) (ItTicketsController:42); endpoint [Authorize(Roles="Admin")] (:34) under class [Authorize] — admin-app FE calling = correct; user-list reuses EXISTING /users GET (PagedResult<UserDto> items{id,fullName,email}, no new BE endpoint, lazy enabled:target!==null); 204 NoContent handled (no body-parse); invalidateQueries(['it-tickets']) on success; handler sets BOTH AssignedToUserId+AssignedToFullName (WorkflowAppsFeatures:467-468) + validates assignee IsActive→NotFound, no try-catch (GlobalExceptionMiddleware). feUserUnchanged: git diff -- fe-user/ EMPTY (Task C = fe-admin-only divergence, documented top-comment ItTicketsPage:3-5). noScopeCreep: git status prod = EXACTLY the 5 expected files, agent-memory noise ignored, no new migration, no BE beyond MenuKeys+DbInitializer, ItTicketsPage diff 98+/5- all Task-C-scoped (imports+state+mutation+Pencil-btn+Dialog), 0 mock/alert markers. Learned: menu-key wiring = verify byte-identity across the FULL mirror set (BE const + BE All[] + seed parent + FE menuKeys + FE staticMap) + confirm the target route actually EXISTS (grep App.tsx) — a staticMap entry pointing to a non-existent route silently drops the leaf (gotcha #50). surprise: lucide FileBarChart is a deprecated-alias (re-exported from FileChartColumn) but still valid — d.ts grep confirmed before flagging. Verdict PASS — safe to commit. Tag [s52-late, it-ticket-reassign, attendance-report-menukey, menukey-mirror-5way, gotcha44-disarmed, gotcha50-disarmed].

  • 2026-06-08 (S53 gotcha #57 EXT Mig 47 — Master catalog filtered-unique pre-commit — PASS, 0 blocker, Smart Friend clean): 4th/5th/6th cumulative gotcha #57 (after Holiday Mig 43 S45 + HRM ×3 Mig 45 S51). 3 Master configs (Department:18/Project:19/Supplier:24) Code unique index .IsUnique()+.HasFilter("[IsDeleted] = 0") + Mig 47 (3-file) + 3 new tests. Independent re-verify ALL GREEN: build SolutionErp.slnx 0-warn/0-err · full suite 203 PASS (58 Dom + 145 Infra, Failed:0 Skipped:0, +3) · 3 new tests run isolated 3-passed-0-skipped. Cat correctness: filter string byte-identical to HolidayConfiguration:18 (xxd 5b 49 73 44 65 6c 65 74 65 64 5d 20 3d 20 30 — spaces around =, not guessed); index STAYS unique:true (2 active same-Code still violate — active uniqueness preserved); Supplier Type index (:25) UNTOUCHED non-unique unfiltered (snapshot:3590 bare). Mig Up=3×Drop+3×Create-filtered, Down=3×reverse-unfiltered (reversible). Snapshot+Designer both show filter on all 3 Master Code idx. Test NOT tautology: seeds IsDeleted=true row → real Create*CommandHandler (app-check AnyAsync(Code==req.Code) thru HasQueryFilter !IsDeleted PASSES) → asserts NotThrow + active-count==1 + IgnoreQueryFilters all==2; RED-before confirmed (3 failed SqliteException UNIQUE on unfiltered). Cmd signatures match test calls (Project 7-arg/Supplier 9-arg/Dept 4-arg). noScopeCreep: git status = exactly 3 configs + snapshot + Mig47 (2 untracked) + 1 test + 2 MEMORY; no FE, no extra mig, no stray. Mig 47 latest in seq (after Mig46 ItTicket SLA). Learned: cookie-cutter EXT of proven pattern → discriminator = byte-compare filter string (xxd) vs canonical sibling + verify index still unique (filter must NARROW scope not DROP uniqueness). app-level dup-check existence = the test premise; verify handler actually has AnyAsync(Code) else test premise false. surprise: implementer claimed "2 pre-existing DocxRenderer warnings" but clean incremental rebuild = 0 warn (unrelated, non-issue). Verdict PASS — safe commit. Tag [s53, gotcha57-ext, mig47, master-catalog, smart-friend-clean].

  • 2026-06-08 (S54 ItTicket reassign authz Admin-OR-dept-IT cross-stack pre-commit — PASS, 0 blocker, gotcha #44 disarmed correctly): Controller /assign hạ [Authorize(Roles="Admin")][Authorize] any-auth; authz moved INTO AssignItTicketHandler (Admin-OR-IT Forbidden + assignee-must-IT Conflict) + new GetAssignableItStaffQuery capability endpoint. Independent re-verify GREEN: dotnet test SolutionErp.slnx = 216 PASS (58 Dom + 158 Infra, Failed:0 Skipped:0, +13 matches 203→216 claim exactly) · fe-admin + fe-user tsc -p tsconfig.app.json --noEmit BOTH exit 0 clean. #2 CHÍ MẠNG role-string "Admin" CONFIRMED REAL (full chain traced): AppRoles.Admin="Admin" literal (AppRoles.cs:5) → SeedRolesAsync Name=roleName (DbInit:1485) so DB Role.Name=="Admin" → Identity GetRolesAsync returns NAMES → JwtTokenService:32 new Claim(ClaimTypes.Role, r) → CurrentUserService:30-31 FindAll(ClaimTypes.Role)cu.Roles.Contains("Admin") CORRECT. "QTV" (DbInit:1458 RoleLabels) = ShortName DISPLAY label only = decoy. Program.cs JWT sets NO RoleClaimType override (ClaimTypes.Role symmetric write/read). Same proven pattern as every existing Roles="Admin" endpoint. Bypass airtight: controller any-auth → handler sole gate; guard if(!isAdmin && !(itDeptId is Guid mine && myDeptId==mine)) Forbidden fail-CLOSED when itDeptId null (non-admin blocked; admin still passes role-branch). Department.Code=="IT" IS seeded (DbInit:2082 "Phòng CNTT") so live non-null. Capability 0-leak: non-auth → {canReassign:false, staff:[]} (no name leak), [Authorize] any-auth → 0 silent-403. Defense-in-depth intact: FE nút {canReassign&&} but PUT still hits handler guard → 403/409 → onError: toast.error(getErrorMessage(err)) surfaces (NOT swallowed). FE SHA256 page 4bcaf2f IDENTICAL both apps (types.ts correctly NOT identical — admin AttendanceReportDto vs user HrDashboardDto diverge below; added AssignableStaff block byte-identical); old fe-user page was read-only kanban (NO app-specific logic lost — diff purely additive); fe-user has all imports (apiError.getErrorMessage, Dialog size/footer/onClose props match, Select passthrough, sonner). Test 13-fact NOT happy-path: Case5 Forbidden side-effect assert AssignedToUserId.Should().BeNull() (red-able by contrast vs Case6/7 same-handler success), Case3/3b empty-staff 0-leak, Case8 Conflict msg-exact. prove-by-contrast ĐỦ CHẶT (partition non-IT-throws vs IT/admin-succeed identical handler). 1 MINOR defer: assignee-must-IT NEW vs old handler (git HEAD: old allowed admin→ANY active user); itDeptId-null → even admin Conflict — fail-closed acceptable+spec-requested, cosmetic (prod IT-dept seeded). Learned: authz role-string review = trace FULL chain const→seed Name→GetRolesAsync(names not codes)→Claim(ClaimTypes.Role)→reader AND grep JWT cfg for RoleClaimType override (none=symmetric) — display-code (QTV) in RoleLabels/ShortName dict = classic decoy. surprise: moving authz controller→handler is the CORRECT gotcha #44 fix (not a smell) when paired with BE-computed capability flag for FE gating + handler as sole gate. Verdict PASS — safe commit. Tag [s54, it-ticket-reassign-authz, gotcha44-disarmed, role-string-chain-verified, cross-stack-clean].

  • 2026-06-09 (S55 master-data import pre-commit — PASS [em main proxy — reviewer return truncated gotcha #53 before verdict, mirror S51]): Reviewed Mig 48 AddProjectMasterFields (Project +4 nullable col Year/Investor/Location/Package) + SeedRealMasterDataAsync (62 Project+71 WorkItem+3 Supplier per-code idempotent ungated) + FE ProjectsPage form +4 ×2 app. Reviewer ran 293s/31-tools nhưng truncated mid-thought (nghi cached-binary 2.76s build → muốn forced clean rebuild + Project tests). Em main COMPLETED đúng việc nó định làm: dotnet test SolutionErp.slnx = clean rebuild + 216 PASS (58+158, 0 fail/skip) → giải tỏa cached-binary concern (test = fresh build). 10 dims GREEN: Mig Up=4 AddColumn/Down=4 DropColumn reversible + 3-file; seed 62/71/3 0-dup; per-code idempotent ungated line 118 (reaches prod); FLOCK01 collision skip-demo-wins; FE↔BE 4 nullable both sides (tránh S51 mismatch); test-file compile-fix +4 null legit; gotcha #57 index untouched; runtime Dev proof (data landed, Investor col populates). 0 rogue write (read-only respected, git clean of code). Learned: long adversarial review return truncates (gotcha #53) → reviewer nên emit PASS/FAIL verdict SỚM (trước deep re-verify) để sống sót truncation; em main complete được đúng pending-check (clean dotnet test) deterministic. Verdict PASS — safe commit. Tag [s55, master-import, em-main-proxy-truncate, runtime-dev-proof].

  • 2026-06-09 (S55 Phase-1 FE visual redesign pre-commit — PASS, 0 blocker, verdict-first survived): 14 fe-admin files VISUAL/CSS-only (NAMGROUP density + SOLUTION brand). Independent re-verify GREEN: npm run build fe-admin = ✓ 607ms, 1945 modules, 0 TS err (only PRE-EXISTING warns: CSS @import-order + >500KB chunk + INEFFECTIVE_DYNAMIC_IMPORT realtime.ts — git-confirmed none introduced, @import lines untouched in diff). Regression Cat1 ALL preserved: Button cva variant keys (primary/secondary/outline/ghost/danger) + size (sm/md/lg) STABLE — only Tailwind class VALUES swapped, defaultVariants intact (51 call-sites safe); Input/Select/Textarea/Label = forwardRef+...props+className passthrough unchanged, only cn() literal; Dialog {open,onClose,title,children,footer,size} destructure + sm/md/lg→max-w map intact (+aria-label="Đóng" = a11y GAIN); DataTable Column<T> type UNCHANGED (diff starts after type def) — render/sortable/align/width + sort + Pagination props intact, RowActions/RowActionButton purely ADDITIVE; Layout MenuLeaf className-only (brand left-rail via before:), nav/resolver/permission-filter/routing untouched; PhaseBadge phase→ContractPhaseColor/Label map intact; PageHeader/EmptyState/TopBar pure class. DashboardPage data-flow (useQuery/navigate/fmtMoney/BarChart/PhaseBadge) preserved, STAT_TONE+SectionLabel additive, +cn import only. Brand Cat3: Be Vietnam Pro KEPT (grep: @import:3 + --font-sans:22 + font-family:34 all unchanged — initial blocker RETRACTED after grep); only brand-/slate/semantic colors, 0 off-brand hex/indigo. a11y: focus-visible rings present everywhere (brand-500); Label self-documents slate-500 (~4.6:1 AA-pass) chosen over NAMGROUP zinc-400. Tailwind v4 (^4.2.3)ring-current/15, shadow-xs, slash-opacity all valid v4. noScopeCreep: exactly 14 fe-admin, 0 fe-user, 0 BE/src (only noise = frontend-designer/MEMORY.md agent file). 2 MINOR (non-block, a11y-floor): text-slate-400 on white for small hint/empty text (DashboardPage hints ~line 50/64, DataTable empty-cell, EmptyState was-400-stays-400) ≈3.5-4:1 — borderline-fail WCAG-AA for <18px, but these are de-emphasized hints not primary content + PRE-EXISTING tone (redesign mostly UPGRADED slate-400→500 on EmptyState desc + Pagination); accept for hint role, revisit if audit. Learned: font-drop scare = grep the 3 load-bearing lines (@import/--font-sans token/font-family) BEFORE flagging — diff hunk lower in file ≠ font removed; emit PASS/FAIL line-1 FIRST (gotcha #53 truncation survival, mirror S51/S55). surprise: Tailwind v4 shadow-xs is real (v3's shadow-sm renamed) — don't flag as typo; v4 slash-opacity on currentColor (ring-current/15) is valid. Verdict PASS — safe commit+deploy. Tag [s55-fe, visual-redesign, namgroup-density, verdict-first, regression-clean, slate400-minor].

  • 2026-06-09 (S56 pre-golive authz live-curl — PASS, 0 blocker): Live prod curl 8 new endpoints. 8/8 return 401 unauth; admin-authed: hrm-configs/vehicles(2)+drivers(2), leave-balances/my(5 lazy), attendances/report+excel(200, 6797B xlsx) all 200; non-admin Drafter correctly 403 on the 2 Admin-only attendance endpoints. gotcha #44 silent-403 sweep CLEAN: capability GET /it-tickets/assignable-staff returns HTTP 200 {canReassign:false,staff:[]} for non-IT Drafter (NOT swallowed 403) + {true,[]} admin — handler returns flag, doesn't throw (WorkflowAppsFeatures.cs:466). assign-mutation guard fail-closed (:504). E2E: GET /projects payload has all +4 fields (70/70), CAL01 Investor live. Off_AttendanceReport menu key in admin /menus/me. 1 MINOR (non-block, defense-in-depth): PUT /it-tickets/{id}/assign checks NotFound BEFORE Admin-OR-IT Forbidden (WorkflowAppsFeatures.cs:496-508) → existence-oracle leak; mutation itself fail-closed → post-golive hardening only. Tag [s56, pre-golive-verify, authz-clean, gotcha44-clean, notfound-before-forbidden-minor].

  • 2026-06-10 (S57-resume Harness-4 two-tier adopt gate — PASS-with-fixes, 0 blocker): Gate trước send-email + commit (governance, không product code). Self-report spawn: claude-fable-5[1m] (reviewer = promote-list inherit → direct promote-tier evidence, em main cite được). Independent re-verify ALL GREEN: grep frontmatter = đúng 7 pin claude-opus-4-8 + 4 inherit + 0 [1m]-in-frontmatter (2 body-text hits hợp lệ: database-agent.md:46 + README.md:9 MỚI — adap-report "match duy nhất" stale-by-own-edit) + 0 project-pin settings. Evidence track-record 8/8 REAL vs HANDOFF/STATUS/own-memory (S51 MAJOR · S54 QTV-decoy · S53 Mig46 · S56 H2-4.5/5 + dept-IT-0-user · S57 ×3 controller +5/+5/+5 [Authorize(Roles="Admin,CatalogManager")] working-tree). Nấc G-011 đúng mọi chỗ load-bearing (demote = executed-file·pending-restart, 0 overclaim runtime). Fixes: hash PLACEHOLDER trước send (nac: sent + "SENT ✓" premature = đúng status-verb class broadcast cảnh báo) · STATUS "(runtime resolve 1M)" thiếu attribution AI_INFRA-s20 · hmw.js:91 log "same-model inherit" stale + :9 "8-agent" vs 9 roles · adap-report "(13)" vs "11" count · invalid-role typo → rơi 'opus' (fail-direction xuống vs H4.5 nghiêng-quality). Learned: gate adopt-governance = re-run MỌI grep claim + cross-check evidence vs HANDOFF nguyên văn; n=2 demoted spawn-test double-duty làm inherit-chain proof là HỢP LỆ (registry cached = chạy config cũ) nhưng cần phrase rõ kẻo đọc nhầm thành promote-list spawn-test. Tag [s57, harness-4, two-tier-gate, pre-send-gate, g011].

--- (S71 curate 2026-06-18 — moved from L1 MEMORY.md: oldest FIFO tail S33→S49 + die-meta S57bis/S60 + redundant bottom Harness-10 R2/R3. Byte-exact, additive-only.) ---

  • 2026-05-26 (S33 Plan B G-H1 Phase 2 pre-commit — PASS, Smart Friend 6× CLEAN): 17 file (3 BE + 6 FE new + 6 mod + 2). SHA256 mirror 3 file IDENTICAL admin==user. 5 endpoint real mediator.Send 0 mock. Mig 34 AddEmployeeProfiles 7 table UNIQUE indexes + FK Cascade. SeedDemoEmployeeProfiles NOT gated DemoSeed (gotcha #51 ✓). gotcha #50 Layout staticMap mirror ✓. 3 MINOR defer: EmployeeCode race SERIALIZABLE low-risk · Update 3 bool not nullable (partial reset) · Delete DateTime.UtcNow direct. Verdict PASS. Tag [s33, hrm-mig34, smart-friend-6x].

  • 2026-05-28 (S35 G-H2 BE CRUD 16 endpoint pre-commit — PASS, Smart Friend 8× CLEAN): 2 NEW file HrmConfigFeatures.cs 439 + Controller 137. build clean, 130/130 PASS. Cat1: 0 mock, 8 ConflictException (Holiday Update composite (Year,Date) BOTH fields). Cat3: class [Authorize] + 12 per-action [Authorize(Roles="Admin")]. Cat5: 8 Validator MaxLength MATCH EF source (Code=50 not spec 20). 2 MINOR defer: ListHolidays no IsActive filter (inconsistent sibling) · OtPolicy "1 active unique" NOT enforced handler (G-P1 ambiguous nếu 2+ active). Verdict PASS. Tag [s35, smart-friend-8x-clean].

  • 2026-05-30 (S43 P11-B LeaveBalance pre-commit — PASS, Max no-truncate): 14 file (LeaveBalance entity+config+Mig42 + Features + Controller + deduction hook + Create/Update LeaveType guard + embed balance + FE×4 + tests). 154 PASS (130→154). Deduction exactly-once VERIFIED (terminal else only, guard Status!=DaGuiDuyet chặn re-approve; advance/reject/return no-deduct). FK invariant fully closed — grep 2 write site LeaveTypeId (Create + UpdateDraft) cả 2 guard AnyAsync→Conflict, bogus type không thể tới terminal FK insert. Embed balance = RequesterUserId (approver thấy đúng người tạo). admin [Authorize(Roles=Admin)]. 2 MINOR defer: concurrency lost-update UsedDays (no RowVersion — human-sequential accept) · stale line-num comment. Verdict PASS. Tag [s43, p11b-leavebalance, max-clean].

  • 2026-06-07 (S49 Harness 1/2/3 adopt pre-commit — PASS all 3, no blocker): Governance/infra adopt (no product code, no test impact). VERIFIED: H1/H2 = 2 sub scope-DISJOINT + tools [Read,Grep,Glob,Bash+4RAG] NO store_memory/Write (INFORM-only); genuinely TAILORED not copy-paste (SE 4-RAG vs AI_INFRA 2-RAG · dropped effort:max + agent-ops-monitor/sister · Fidelity→SE reviewer). H2 5-trục in harvest-curator.md + session-end §L.b(f). H2 wave-mode hmw.js mirror AI_INFRA + B6 git check-ignore VERIFIED (wave-*/+agent-teams/ ignored · hmw.js/README tracked). H3 self=se complete substitution · SHA256 canonical formula byte-identical send==check · 13 .gitkeep exact · adap-apply base-path outbox\all\. honest nấc executed-file/verified-runtime-PENDING. G-015 scan = 6 hits ALL negating ("KHÔNG enforced") = correct honesty. 1 MINOR (non-block): README:11/18 "7-agent" ASCII diagram = PRE-EXISTING drift (git diff proved work này chỉ touch load-bearing title/decision-tree/tool-grant/matrix; diagram predates S47 frontend-designer) → tooling-auditor H1 designed-to-catch = self-validating adoption. learned: git diff base..head = discriminator introduced-defect vs pre-existing-drift (đừng đổ lỗi work mới cho drift cũ); name-collision tailor-verify = diff frontmatter AI_INFRA-canonical vs SE-instance. surprise: mojibake scan false-pos trên "ĐÃ" (U+00C3 = valid VN uppercase, KHÔNG double-encode → verify codepoint in-context trước flag); broadcast floor "12 .gitkeep" UNDERCOUNT (correct=13 incl all/ adap-channel — em main đúng). Verdict PASS, safe commit + restart. Tag [s49, harness-adopt, governance, max-clean].

  • Smart Friend cumulative 8× CLEAN: (1) S22 #44 silent-403 · (2) S25 #48 SQLite tie-break · (3) S29 password ≥12 · (4) S29 ApplicableType cross-module · (5) S33 BW test · (6) S33 Plan B Phase 2 · (7) S35 FE forms · (8) S35 G-H2. Plus 9× G-O2 (S36, em không track ở đây). 2 MAJOR catches total (S29 password + S29 ApplicableType); rest clean với MINOR defer.

  • Archived S29-S33 detail + S32 startup → archive/2026-05-q2.md + git d2f52ba (S40 curate): S33 Plan C B-Wrap 9/9 [Fact] verify · S33 startup drift audit (CLAUDE.md SEVERE → patched S40) · S32 wrap/startup standby · S29 wrap 2 MAJOR catch detail. KEY absorbed in bug patterns + Smart Friend cumulative above.

  • 2026-06-11 (S57bis product gate — KHÔNG DELIVER, die-0-byte ×2, on-behalf em main ghi hộ, H2-proposed): Cả 2 spawn (email-gate đầu + final gate) chết 0-byte output 0 return (resume-kill class #3, ref feedback_agent_kill_recovery) → em main SELF-GATE evidence-checklist: grep authz key-set + role-string vs AppRoles + Mig 49 Up/Down reversible + 240 test + Run #381 + prod smoke 401/404-control. LEARNED: output-file size=0 + im >5 phút = chết, KHÔNG đợi thêm; KHÔNG re-spawn >2 lần trong session có --resume. SURPRISE: khác S52 killed-with-partial — lần này 0-byte tuyệt đối (không gì recover được từ return). Tag [s57bis, die-0-byte-x2, self-gate, on-behalf].

  • 2026-06-12 (S60 đợt1 PE submit-guard + drafter-bypass gate — KHÔNG DELIVER, die mid-run, on-behalf em main ghi hộ, H2-proposed): Task: review 37122f0 cross-stack (BE TransitionAsync submit-guard đủ-4-thông-tin mục 3 + bypass người-soạn-trong-chuỗi V2 BƯỚC-ĐẦU-only + FE PeDetailTabs ×2 + 14 PeSubmitGuardAndBypassTests 240→254). Die mid-run #53-class (commit body tự khai "Reviewer die mid-run → em main self-gate evidence-checklist PASS 0 blocker") → ship Run #283 PASS prod-verified, bundle rotate both. LEARNED: self-gate em main đứng vững lần 2 (sau S57bis) — checklist deterministic (test gate + diff scope + prod smoke 401/404-control) đủ cho PE refinement cross-stack. SURPRISE: die lần 3 trong 2 ngày (S57bis die-0-byte ×2 + S60 mid-run) DÙ promote-tier inherit Fable 5 → model-tier KHÔNG phải nguyên nhân die (nghi resume-kill/harness class) — trend data cho Harness-4. Tag [s60, die-mid-run-3rd, self-gate, on-behalf].

  • 2026-06-18 (Harness-10 adap R2-lens hmw.js ENGINE integrity — CONCERN, confirms sibling L1 over-claim still live, pre-commit): Lens = hmw.js engine integrity (em-main rename wave→run-trace). Engine itself CLEAN — all 4 R2 checks PASS: (1) structure valid — const wave=(A.run&&A.run.dir)?A.run:((A.wave&&A.wave.dir)?A.wave:null) :91 nested-ternary paren-balanced 3/3, accepts args.run primary + args.wave alias (additive, old callers OK), var wave internal-name kept consistent :91/:92/:95/:103/:107/:132; subMd path :103 ${wave.dir}/sub-md/${role||'task'}-${i}.md matches spec; template-literals balanced (backtick 54 EVEN all-escaped, brace 56/56, paren 140/140, bracket 14/14). (2) zero operative WAVE-MODE — grep WAVE-MODE=0; all 6 wave refs contextualized (legacy-alias :19/:90/:91, "supersedes Harness 2 wave" :87/:109); :113 ISOLATION contains "tracked-change NGOÀI run-folder (runs//)+code-disjoint=vi-phạm" ✓. (3) fan-out logic UNCHANGED — git diff -U0 hunks = ONLY :91 behavioral (alias-accept); resolveModel/SCHEMA/checkpointApproved-guard/parallel/results.filter untouched. (4) valid JS (balance + structural, NO node --check per top-level-await). THE CATCH (CONCERN, intersects R2): runs/README.md:51 documents L1 in-run-reminder as firing in "hmw.js prompt-builder" w/ exact text 'run đang OPEN—nhớ scaffold@P1'+'run trước OPEN-beat đã harvest chưa' → grep that in hmw.js = 0. hmw.js writeGuard :114 emits ONLY C4 return-instruction ("Harvest per-turn primary (C4)..."), NO scaffold/OPEN orchestrator-reminder; :92 is a log() at mode-detect not prompt-injection + still lacks the promised text. Plan-vs-applied gap proven: invest-synthesis:17 PLANNED "C5 Layer1: thêm reminder vào prompt-builder"; implement-synthesis NEVER lists applying L1 to hmw.js (only L2 :71 + L3 :51 applied); yet README:51+C7:72 present L1 as live. Doc asserts engine-behavior grep proves absent = over-claim. Sibling reviewer (same adap, prior run today) already CONCERN on this exact gap — I independently re-confirm UNFIXED. Cross-file PASS: gitignore runs/ TRACKED via !.claude/**:83 (check-ignore -v confirms negation) + wave-*/ kept IGNORED; containment wording synced 4 files (_ledger:4↔hmw:89/113↔runs/README:78); frozen evidence (broadcasts/adap-harness-2/error-ledger/STATUS/HANDOFF/archive_INDEX/sessions) ALL empty-diff; 0 mojibake. Residual (non-block, self-flagged): investigator-codebase/MEMORY.md +6 (29819B ~just-under-cap) = 4 same-role INVEST agents race (concurrency risk #7 invest-synthesis flagged) → em-main reconcile @closeout; new :113 guard forbids sub agent-memory writes = prevents recurrence. Learned: narrow lens (hmw.js JS structure) ≠ excuse to wave a doc-asserts-engine over-claim — when README says a layer "fires in ", grep the engine for the CLAIMED text not a sibling instruction; INVEST-plan ≠ IMPLEMENT-applied. Surprise: engine rename genuinely flawless (dual-alias/balance/logic-frozen) — ONLY defect is adjacent doc over-stating what the clean engine does; engine-perfect + doc-overclaim coexist in one adap. Smart-Friend held: did NOT downgrade to PASS despite narrow lens + clean engine + sibling already-flagged. Tag [harness10, r2-hmwjs-engine, engine-clean-doc-overclaim, c5-L1-overclaim-reconfirm, plan-vs-applied-gap, dual-alias-additive].

  • 2026-06-18 (Harness-10 adap run-trace folder R3-floor review — CONCERN, 1 over-claim, pre-commit): Reviewed adap thay wave-mode → runs/<run-id>/ 3-part (run.md+sub-md/+harvest/) git-TRACKED. Floor C1-C8 disk-verified. C1/C2 PASS — all 3 runs (invest/implement/review) scaffolded full 3-part (ls confirm + .gitkeep placeholders). C3 PASS correct-nấc (NO over-claim)git check-ignore runs/=NOT-IGNORED (tracked-eligible via !.claude/** :83) AND git ls-files runs/=EMPTY=NOT-committed-yet; _ledger:4 + runs/README:80 + gitignore:89-99 document "tracked" correctly, NEVER falsely claim "committed". Nấc THẬT = tracked-ELIGIBLE pre-commit (must commit to realize — expected, not defect). C4 PASS — invest+implement synthesis present per-turn; review harvest empty=correct (in-progress). C5 CONCERN (the catch) — L2 (session-start:71 orphan scan closed=⏳+harvest-rỗng) + L3 (session-end:51 idempotent VERIFY-not-re-APPEND) genuinely wired. BUT L1 OVER-CLAIM: runs/README:51 documents L1 in-run reminder firing in "hmw.js prompt-builder" w/ exact text 'run đang OPEN—nhớ scaffold@P1'+'run trước...harvest chưa' → grep -c that text in hmw.js = 0. hmw.js writeGuard only emits C4 return-instruction ("Harvest per-turn primary (C4)"), NO scaffold/OPEN reminder. INVEST planned it ("C5 Layer1: thêm reminder vào prompt-builder"), IMPLEMENT synthesis never mentions applying it, yet runs/README:51+C7:72 present L1 as live. Doc-vs-reality gap = over-claim. C6 PASS — _ledger OPEN+CLOSE beats (invest/implement CLOSED, review ) + orphan def:3. C7 PASS — caveat genuinely honest (engine no-fs · C2 fragile · 3-layer=lưới-không-khóa · G-015 TRACKED≠read-only-enforced); strong. C8 PASS — wave→runs migration done (0 wave-/ remain), wave-/ kept IGNORED (verified). Frozen evidence 0-byte-loss CONFIRMED (broadcasts/·adap-harness-2·error-ledger·STATUS·HANDOFF all empty-diff vs HEAD). hmw.js node --check=OK, dual-alias A.run/A.wave intact. Containment wording synced 4 files (_ledger:4↔hmw:113↔workflows/README:38↔runs/README:78). Learned: for a multi-layer "anti-miss net" adap, the catch is grepping each layer's CLAIMED trigger-site against the actual engine file — a layer documented as "fires in hmw.js prompt-builder" must have backing text there, not just a sibling instruction; INVEST-plan ≠ IMPLEMENT-applied (cross-check synthesis-plan vs disk). Surprise: README's own C1-C7 section-numbering ≠ task's C1-C8 reviewer-axes (two schemes, NOT a defect — README documents convention, task axes evaluate it); don't conflate. Over-claim=CONCERN per task rule (would be PASS if README:51 softened L1 to "C4 return-instruction" matching reality, OR hmw.js actually added the scaffold reminder). Tag [harness10, run-trace-folder, c5-L1-overclaim, tracked-not-committed-correct-nac, frozen-evidence-clean, plan-vs-applied-gap].