Files
solution-erp/docs/changelog/sessions/2026-06-08-S53-gotcha57-ext-p11-cd-closeout.md
pqhuy1987 d8cd111532 [CLAUDE] Docs: S53 closeout — gotcha #57 EXT Master (Mig 47) + P11-D/E + database-agent verified-runtime + doc-drift
Session 53 closeout (HMW-mode ON, 'làm hết' full close). Code already shipped in 44b9e54 (Mig 47, Run #260) + dbf6648 (C+D, Run #261), both prod-verified.

- STATUS/HANDOFF: S53 entry (mig 46->47, test 200->203, menu +Off_AttendanceReport, bundle admin DfCfHUE9, database-agent verified-runtime).
- Doc-drift E (H1 top-5): ef-core skill 43->47, agents/README roster 10->11 + plugin nac, CLAUDE.md root 45->47 mig + 186->203 test, docs/CLAUDE.md 56->57 gotcha + 91->92 ERD.
- adap-report: database-agent executed-file -> verified-runtime (spawn-test caught Mig 46-unapplied-local).
- session log 2026-06-08-S53 + 4 agent diaries (S53 work).
- Memory: +project_database_agent_verified_local_drift (user-memory, outside repo).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 15:24:45 +07:00

89 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).