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

8.3 KiB
Raw Blame History

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