# Session 53 — gotcha #57 EXT Master (Mig 47) + P11-D reassign-UI + P11-E menu-key + database-agent verified-runtime **Date:** 2026-06-08 · **Mode:** HMW-mode ON · **Theme:** "làm hết luôn đi" — full close of remaining Phase 11 follow-ups + governance + doc-drift, all prod-verified. **User flow:** `/session-start` → "Workflow làm nhanh" (Task B gotcha #57 EXT) → "làm hết luôn đi" (Task C + D + doc-drift E + `/session-end`). --- ## Outcome | Metric | Before (S52) | After (S53) | |---|---|---| | Migrations | 46 | **47** (Mig 47 `FilterMasterCatalogUniqueIndexesByIsDeleted`) | | Tests | 200 | **203** (+3 `MasterCatalogFilteredUniqueTests`) | | Menu keys | ~55 | **~56** (+`Off_AttendanceReport`) | | Sub-agents | 11 (database-agent executed-file) | 11 (database-agent **verified-runtime**) | | Bundle admin | `DYfjnpY0` | **`DfCfHUE9`** (rotated by C+D FE) | | Bundle user | `_3S0BPJ2` | `_3S0BPJ2` (unchanged — fe-user untouched) | | Tables | 92 | 92 (Mig 47 index-only) | **2 code commits, both Gitea-verified prod:** - `44b9e54` — Task B (Mig 47, gotcha #57 EXT Master) → Run #260 success - `dbf6648` — Task C + D (ItTicket reassign-UI + AttendanceReport menu-key) → Run #261 success --- ## Part 1 — Bootstrap (3 governance agents) - **🔵 database-agent → VERIFIED-RUNTIME** (first real spawn since S52 adopt). CLI restart confirmed (registry loaded it). Spawn-test: connected LocalDB `(localdb)\MSSQLLocalDB` Dev+Design, read `__EFMigrationsHistory`, introspected `ItTickets`, queried `sys.tables`. **Caught 2 real drifts** the rest of the toolchain missed: 1. **Mig 46 committed-but-unapplied-local** — the migration file + snapshot were on disk (3-file committed S52) and prod had it (CI-applied), but local `SolutionErp_Dev`/`_Design` were stuck at Mig 45 (S52 session-limit killed the local `database update`). 203 SQLite tests + green prod both **miss** this — local DB is the one surface nothing else verifies. → Closed as a bonus when Mig 47's `database update` applied 46+47 to both local instances. 2. table-count: raw `sys.tables` = 93 = 92 domain + `__EFMigrationsHistory` (docs' "92 domain" correct). - **🟫 tooling-auditor (H1)** re-report: top-5 doc-drift (ef-core skill 43, roster 10→11, CLAUDE.md root 45, docs/CLAUDE.md 56→57/91→92). Patched at session-end (Part 4). - **⬜ harvest-curator (H2)** re-report: 🟢 clean. S52 proxy-append (Wave-2 killed-mid implementer-backend + test-specialist diaries) **verified present, 0 orphan**. 11 diaries byte>0. 1 cosmetic flagged (`s??`→`s52` placeholder). ## Part 2 — Task B: gotcha #57 EXT Master (Mig 47) **Workflow:** 🟪 test-specialist (RED) → 🟨 implementer-backend (fix+Mig47+GREEN) → 🟥 reviewer (PASS, 0 issues). - 3 Master configs (Department:18 / Project:19 / Supplier:24) → unique Code index `.HasFilter("[IsDeleted] = 0")` (byte-for-byte from the existing 13 filtered indexes). Mig 47 = 3× DropIndex+CreateIndex filtered (Up) / reverse (Down). - **Root cause** (test-specialist pinned it): app-level dup-check `db.X.AnyAsync(x => x.Code == req.Code)` runs *through* `HasQueryFilter(!IsDeleted)` → ignores the soft-deleted row → says "Code free"; the **bare** DB unique index counts the soft-deleted row → UNIQUE-500. Admin delete+re-add same Code = reachable 500. `.HasFilter` aligns the index with the query filter. - test-before RED confirmed (3× `SqliteException UNIQUE`) → GREEN after fix. Test 200→203. - Prod (Run #260): 3 indexes `filter_definition` NULL → `([IsDeleted]=(0))` live (cicd sqlcmd). - **gotcha #57 EXT backlog CLOSED** — cumulative 6× (Holiday Mig 43 S45 + 3 HRM Mig 45 S51 + 3 Master Mig 47 S53). ## Part 3 — Task C+D (one commit `dbf6648`) **Workflow:** 🟨 implementer-backend (D-BE) → 🟧 implementer-frontend (C + D-FE) → 🟥 reviewer (PASS, 0 issues). - **Task C — ItTicket admin reassign-UI** (fe-admin ONLY, intentional mirror-break): per-card pencil → Dialog with user Select (reuse existing `GET /users` pagedSize 200) → `PUT /it-tickets/{id}/assign` (Admin-only, 204 handled) → invalidate `['it-tickets']`. fe-user `ItTicketsPage` untouched (employees don't reassign). Top comment updated to flag divergence. - **Task D — AttendanceReport menu-key** (no migration): `MenuKeys.OffAttendanceReport = "Off_AttendanceReport"` + `All[]` + DbInitializer seed `(…, "Báo cáo chấm công", MenuKeys.Off, 8, "FileBarChart")`. Admin-perm auto via `SeedAdminPermissionsAsync` iterating `All`. Idempotent seed → prod gets leaf on restart. FE: `menuKeys.ts` const + `Layout.tsx` staticMap → existing `/attendance/report` route (only 2 of 4-place needed; page+route from S52). - **Menu-key = 5 mirror points** (gotcha #50) — reviewer byte-verified `"Off_AttendanceReport"` identical at: BE const, BE `All[]`, DbInitializer seed, FE `menuKeys.ts`, FE Layout staticMap. - Prod (Run #261): `Off_AttendanceReport` MenuItems row seeded (ParentKey=Off, Order=8) · admin bundle `DfCfHUE9` rotated / user `_3S0BPJ2` unchanged · smoke health 200, /users + /it-tickets 401. ## Part 4 — Closeout (doc-drift E + session-end) - **Doc-drift E (H1 top-5 patched):** ef-core SKILL.md + skills/README (43→47, Mig 47, S45→S53) · agents/README roster 10→11 (×3) + plugin "18 enabled"→"18 registered/15 enabled" · CLAUDE.md root 45→47 mig + 186→203 test + Mig list +46+47 · docs/CLAUDE.md 56→57 gotcha + 91→92 ERD + Mig 27-47. - database-agent adap-report: executed-file → **verified-runtime** (§2 nấc + §5 caveat #1 + commit-sha `e9ee97f`). --- ## §L.b(d) Spawn-records (4-field {agent · task · nấc · evidence}) | Agent | Task | Nấc | Evidence | |---|---|---|---| | 🔵 database-agent | verified-runtime spawn-test (introspect ItTickets/migrations) | **verified** | LocalDB connect + `__EFMigrationsHistory` read + caught Mig 46-unapplied-local + table-count 93 | | 🟫 tooling-auditor (H1) | session-start re-report (4-mặt freshness diff vs S50) | verified | top-5 doc-drift coords → all patched Part 4 | | ⬜ harvest-curator (H2) | session-start re-report + session-end gate (5-trục) | verified | 11 diaries byte>0, S52 proxy-append present, 0 orphan | | 🟪 test-specialist | Mig 47 test-before (3 `MasterCatalogFilteredUniqueTests`) | verified | RED 3× SqliteException → GREEN; 200→203 | | 🟨 implementer-backend | Mig 47 (configs+migration) + D-BE (MenuKeys+DbInitializer) | verified | Run #260 + #261; dotnet build 0-err; em-main re-verified | | 🟧 implementer-frontend | C reassign-UI + D-FE menu wiring (fe-admin) | verified | npm build 0-err; admin bundle `DfCfHUE9` rotated prod | | 🟥 reviewer | Mig 47 pre-commit + C+D pre-commit | verified | 2× PASS 0-issues; em-main confirmed builds + git scope | | 🟩 cicd-monitor | Mig 47 prod verify + C+D prod verify | partial (truncated 2×) | Run #260/#261 success + filter_definition + menu-row; **gaps curl-self-recovered** | ## §L.a — Deterministic detect (AS scan) - **AS-truncation (gotcha #53/#55):** cicd-monitor truncated output 2× (C+D verify cut mid-Q3 on its own `AspNetRoles` query typo). **Guard held** (not a new RCA — existing `feedback_agent_kill_recovery` guard): em-main curl-self-verified the gaps (Gitea run #261 + bundle hashes via public curl; menu-row from agent's pre-truncation sqlcmd). No prod impact, no re-spawn needed. Active-Guard "curl-self-verify recovery" → marked verified (2nd consecutive session held: S52 session-limit + S53 truncation). - No bug-production (all 203 green, both deploys verified). No new RCA entry. ## Lessons 1. **Read-advisory DB lens earns its seat on first spawn.** database-agent caught a committed-but-unapplied-local migration that *every other green signal missed* (SQLite tests build from snapshot, prod uses CI-applied DB). Local DB is the unverified surface. 2. **cicd-monitor truncation is now a 2-session pattern** → curl-self-verify (public Gitea API + bundle HTTP) is the reliable recovery; don't re-trust a 2nd agent round-trip. Bundle-hash diff is content-addressed ground truth for "right FE shipped". 3. **Hybrid scout→pipeline** (em-main recon inline → Workflow with exact coords) kept both workflows tight + 0-issue reviews. ## Next session (anh pick) - **Phase 9 Ops** (anh main coordinate): SMTP · rotate creds · SQL auto-backup register · UAT real user. - **Monthly drift audit 2026-07-01** (cron). - Optional: mirror ItTicket reassign to fe-user · RAG re-index S42-S53 (AI_INFRA op).