---
distill-gen: 1
period: 2026-05 (S21→S37)
source-verbatim: archive/2026-05-q2.md (1) · 2026-05-q3.md (3) · 2026-05-q4.md (7) · 2026-05-runs.md (20 run-records + 6 [meta] curate-headers)
pointer-style: substring (Ctrl-F) back-resolve; each line names its FILE then → substring:"<unique>"
fields-per-line: VIỆC · KẾT-LUẬN(+commit/Mig) · BÀI-HỌC · BẤT-NGỜ · [confidence]
note: compression is a REPORTED number, not a target. Markers tagged ‹M#›. Even-older verbatim → git d2f52ba.
---

# CI/CD Monitor — GIST 2026-05 (4-field distilled)

> Distilled from the four 2026-05 archive files. Open the named file + Ctrl-F the trailing substring for the full block. `‹M#›` = checklist-marker survival tag.

## ★ gotcha #48 SQLite tie-break (the critical catch+fix pair) — q3 + runs.md

- VIỆC ‹M1›: Run #215 FAIL → #216 PASS pair (S25 t1-t2, Plan AB changelog visibility refactor). KẾT-LUẬN ‹M1›: #215 `cdfd542` FAIL at test_infra (51/53) — 2 ReturnMode tests `Expected changelog.ContextNote not to be <null>`; #216 `8c05947` PASS. ROOT CAUSE: `ApplyReturnModeAsync` adds NEW Changelog (EntityType=Workflow, NO ContextNote) in same SaveChanges as LogTransitionAsync (has ContextNote); test `.OrderByDescending(c=>c.CreatedAt).First()` with **SQLite + frozen test-clock → both rows SAME CreatedAt → tie-break returns WRONG (Workflow) entry**. FIX: add `.Where(c=>c.Summary!.Contains("Chuyển phase"))` discriminator BEFORE OrderByDescending (Plan AB code NOT reverted). BÀI-HỌC ‹M1›: **discriminator filter BEFORE OrderBy on frozen-clock ties**; UAT skip-test risky for >100-LOC BE refactor — CI caught BEFORE prod. BẤT-NGỜ: 8-min turnaround; test gate spared prod broken audit-trail. [cao] → file: archive/2026-05-q3.md · substring:"Run #215 FAIL → Run #216 PASS (gotcha #48 SQLite tie-break catch+fix pair)"
- VIỆC ‹M1›: [meta] curate-note for #215 (S25 t1 Plan AB FAIL). KẾT-LUẬN: records the gotcha #48 birth + 3 fix approaches. BÀI-HỌC ‹M1›: multi-Changelog.Add() in one txn + OrderByDescending(CreatedAt) tie risk in SQLite frozen-clock. BẤT-NGỜ: none (curate log). [vừa] → file: archive/2026-05-runs.md · substring:"added S25 t1 Plan AB Run #215 entry"

## Per-NV opt-in wire — the 10-point checklist births (S23-S25) — runs.md

- VIỆC: Run #194 (S23 t1 Plan K, Mig 31 per-Approver-slot refactor). KẾT-LUẬN: **PARTIAL** `098baa6` — Mig 31 + schema OK BUT K3 DTO-mirror INCOMPLETE: `AwLevelDto` missing `AllowApproverSkipToFinal` (only in a comment, not a record-param) + `ToDto` ctor missing it → FE Designer 7th checkbox ships but BE never returns value → no round-trip. BÀI-HỌC: schema-OK ≠ wired; check Application DTO + Handler expose the new column. BẤT-NGỜ: 7th-checkbox silently no-op. [cao] → file: archive/2026-05-runs.md · substring:"Run #194 id=308 sha=`098baa6`"
- VIỆC: Run #195 (S23 t1 K10 hotfix). KẾT-LUẬN: PASS `0062fcb` — AwLevelDto +AllowApproverSkipToFinal + ToDto + CreateAwLevelInput + handler init. BÀI-HỌC: **8-surface-point checklist** (AwLevelDto + CreateAwLevelInput were the 2 gaps em-main+Reviewer missed). BẤT-NGỜ: round-trip needs 4 edits across DTO/Input/Handler. [cao] → file: archive/2026-05-runs.md · substring:"Run #195 id=309 sha=`0062fcb`"
- VIỆC: Run #201 (S23 t4 Plan N HOTFIX). KẾT-LUẬN: PASS `fb3c22c` — per-NV lookup discrimination at `PurchaseEvaluationFeatures.cs:765` (`FirstOrDefault(Order==X && ApproverUserId==actor) ?? admin-fallback`). Live: NV-Test 7/7 TRUE vs admin 1/7 (fallback). BÀI-HỌC: **surface-point 9 = lookup discrimination in lookup-site handler**; bug 2 days prod silent (Mig 29 deploy → S23 t4 catch). BẤT-NGỜ: 3× refactor (Mig 29/30/31) all missed point 9. [cao] → file: archive/2026-05-runs.md · substring:"Run #201 id=315 sha=`fb3c22c`"
- VIỆC: Run #202 (S23 t5 Plan O HOTFIX). KẾT-LUẬN: PASS `a1c8386` — cascade 4 lookup-sites same pattern (Service:204, :258-260, DetailFeatures:75-76, Features:314-315). Live: NV-Test POST transition → **409 mode-mismatch NOT 403 actor-mismatch = discrimination active**. BÀI-HỌC: scan ALL `grep -n "FirstOrDefault.*Order.*==" *.cs` after OR-of-N refactor; surfaced pre-existing TransitionPeBody schema gap. BẤT-NGỜ: 3-day prod-bug latency. [cao] → file: archive/2026-05-runs.md · substring:"Run #202 id=316 sha=`a1c8386`"
- VIỆC: Run #203 (S23 t6 Plan P HOTFIX). KẾT-LUẬN: PASS `1727bd5` — Controller `TransitionPeBody` record +3 fields (ReturnMode/ReturnTargetUserId/SkipToFinal). Live: admin numeric `4` → 204; string `"Drafter"` → 400. BÀI-HỌC: **point-10 = Controller body record param-count MUST mirror Command record**; **Discovery#4 = ASP.NET10 record-with-enum needs NUMERIC input (no JsonStringEnumConverter registered)**. BẤT-NGỜ: missing body fields silently `default` (no 400) → FE wire dead 2 prod days. [cao] → file: archive/2026-05-runs.md · substring:"Run #203 id=317 sha=`1727bd5`"
- VIỆC: Run #200 (S23 t3 Plan M, Service F1 OneLevel/OneStep edge-case Bước1 reset). KẾT-LUẬN: PASS `f4055a1`, Mig31 unchanged. BÀI-HỌC ‹M3›: **Discovery#3 anomaly — docs-only TIP `f4055a1` STILL triggered CI** (reinforces push-RANGE eval not just tip). BẤT-NGỜ: anomaly is BENEFICIAL (catches verify on docs commits). [cao] → file: archive/2026-05-runs.md · substring:"Run #200 id=314 sha=`f4055a1`"

## S25 FE audit-recovery + S24 filter/menu (runs.md)

- VIỆC: Run #221 (S25 t7 Plan AF FE userMap fallback). KẾT-LUẬN: PASS `506cada`, bundle rotate `C8TvDy7r`/`BvcWrq2z`. BÀI-HỌC: FE-only fallback Map<userId,name> from embedded bundle (drafter+approvals+approvers+opinions); **Discovery: 503 mid-deploy expected (app-pool recycle ~5-15s, self-recovers); auth route `/api/auth/login` field `accessToken` NOT `token`**. BẤT-NGỜ: /api/v1/auth/login = 404. [cao] → file: archive/2026-05-runs.md · substring:"Run #221 id=335 sha=`506cada`"
- VIỆC: Run #220 (S25 t6 Plan AE Changelog UserName 9-sites batch). KẾT-LUẬN: PASS `9ea62be`, BE-only bundle FROZEN. BÀI-HỌC: preventive batch-fix ALL Changelog.Add() sites (PE=9), not just the 1 reported; `UserName = currentUser.FullName ?? Email`. BẤT-NGỜ: stale empty-userName rows are pre-fix history (forward-only fix). [vừa] → file: archive/2026-05-runs.md · substring:"Run #220 id=334 sha=`9ea62be`"
- VIỆC: Run #219 (S25 t5 Plan AD) + #218 (S25 t4 Plan AC2). KẾT-LUẬN: both PASS (`0aaf2df`, `25837b6`), bundles rotate. BÀI-HỌC: FE synthetic-rows from Changelog entityType=5 + ContextNote keyword; parse comment for semantic next-target hint (reusable Contract/Budget audit recovery). BẤT-NGỜ: dual-phase badges mostly self-loop noise (ChoDuyet→ChoDuyet). [vừa] → file: archive/2026-05-runs.md · substring:"Run #219 id=333 sha=`0aaf2df`"
- VIỆC: Run #210 (S24 t1 Plan AA, IsUserSelectable filter + Pe_DuyetNcc_WfView menu + sidebar). KẾT-LUẬN: PASS `ac2c859`, 4/4 wire, bundle rotate `Dmk--X6w`/`Bd4gh3Tp`. BÀI-HỌC: new-filter-param + new-menu-key + Order-shift-idempotent + **non-admin Read 200 NOT 403** (gotcha #44 any-auth read). BẤT-NGỜ: none. [vừa] → file: archive/2026-05-runs.md · substring:"Run #210 id=324 sha=`ac2c859`"
- VIỆC: Run #214 (Plan AA wrap fix sidebar), #209 (Plan U truncate), #208/#207 (Plan T DemoSeed disable + wipe ~720 rows), #204 (Plan Q FE banner). KẾT-LUẬN: all PASS (`ee0902a`,`86d8806`,`7b7b28f`,`0b97840`,`108268a`). BÀI-HỌC: **DemoSeed:Disabled flag gates 5 demo-seed methods (NOT infra seed) — proven end-to-end via force-recycle no-reseed**; #214 = baseline before Plan AB fail. BẤT-NGỜ: appsettings.Production.json is .gitignore'd → flag default committed in appsettings.json. [vừa] → file: archive/2026-05-runs.md · substring:"Run #207 sha=`0b97840`"

## Foundation + Discovery births (S21-S22) — runs.md + q3

- VIỆC ‹M3›: S22-chốt cumulative verify. KẾT-LUẬN: PASS, 104 test, Mig30. BÀI-HỌC ‹M3›: **Discovery#3 push-range eval — `b079b27`(BE Mig30)+`b04a11a`(FE) pushed batched → single Run on TIP**; #190 CANCELLED by concurrency-supersede (next push within 3min) = NORMAL not fault. BẤT-NGỜ: `**/*.md` glob matches `.claude/agent-memory/*.md` at any depth → those commits DO skip (gotcha #47 disproven for .md, kept preventive for non-.md state files). [cao] → file: archive/2026-05-runs.md · substring:"Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits) VERDICT=PASS"
- VIỆC: Run #188 (S22 Plan D/C/E). KẾT-LUẬN: PASS `a74e671`, 103 test, Plan E strict-V2-scope (nv.test 8 < admin 17). BÀI-HỌC: **Discovery#1 rate-limit 429 at ~5 login/min → cache token across endpoints**; **Discovery#2 `.claude/agent-memory/**` NOT in paths-ignore** (later refined — `**/*.md` still catches .md). BẤT-NGỜ: token-cache pattern avoids 429. [vừa] → file: archive/2026-05-runs.md · substring:"Run #188 id=302 sha=a74e671"
- VIỆC: Run #187 (S21 t5 Mig 29 Allow*-per-NV refactor + Designer 5-checkbox). KẾT-LUẬN: PASS `c0af9e0`, Mig29 applied (Levels +5 Allow*, Users +1, Workflows −6 dropped). BÀI-HỌC: **Discovery — Gitea task-table `updated_at` stale ~2min → cross-check VPS file mtime** (gotcha #46). BẤT-NGỜ: backfill 48/48 Levels correct, 0/13 Users (preserve). [vừa] → file: archive/2026-05-runs.md · substring:"Run #187 id=301 sha=c0af9e0"
- VIỆC: Run #186 (S21 t3+t4 gotcha#45 Trả-lại + F1/F2/F3 advanced-options + Mig 28). KẾT-LUẬN: PASS `eea86fd` baseline 3m32s, 84 test. BÀI-HỌC: **Discovery — Gitea Actions list endpoint = `/api/v1/repos/.../actions/tasks` NOT `/actions/runs` (404); public no-auth read OK**. BẤT-NGỜ: none. [cao] → file: archive/2026-05-runs.md · substring:"Run #186 id=300 sha=eea86fd"
- VIỆC: Setup baseline (agent init) + Verify-S22 (q3 copy, Discovery#3 first-surfaced). KẾT-LUẬN: init/PASS. BÀI-HỌC: 5-stage checklist + bundle-hash-verify pattern established; S22-verify also lives in q3 (cross-file dup with runs.md — keyed distinctly). BẤT-NGỜ: none. [thấp] → file: archive/2026-05-q3.md · substring:"2026-05-12 — Setup baseline"

## Plan B Contract V2 + Hrm/Office (S29-S37) — q2 + q4

- VIỆC ‹M2›: Run #231 Plan B Contract V2 wire kick-off. KẾT-LUẬN: **PARTIAL** `3e92584` — PASS deploy (Mig 32+33 applied, bundles rotate) + seed-gap: `SeedSampleContractWorkflowV2` nested in DemoSeed gate → QT-HD-V2-001 NOT seeded → FE dropdown EMPTY → V2 not UAT-testable. Resolved Run #232 (`38f1c4d`, carve out of gate). BÀI-HỌC ‹M2›: **gotcha #51 birth — infra seed must not sit under demoSeedDisabled**. BẤT-NGỜ: ~150 LOC ApproveV2Async shipped with 0 test (gotcha #48 high-risk pattern). [cao] → file: archive/2026-05-q2.md · substring:"Run #231 (id=345) Plan B Contract V2 wire kick-off VERDICT=PARTIAL"
- VIỆC ‹M2›‹M22›: Run #350 (S33 Mig 34 EmployeeProfile + Plan C BW1-BW7 +9 test). KẾT-LUẬN: PASS `48a99e1`, test_infra 62. BÀI-HỌC ‹M2›: **gotcha #51 INFRASTRUCTURE-seed verify — SeedDemoEmployeeProfilesAsync correctly NOT gated; EmployeeProfiles=33 (16 demo+14 Solutions+3 admin)**. BẤT-NGỜ ‹M22›: **mem-labeled "#350" ≠ real Gitea run_number** (this is a memory-id; reconcile via run_number). [cao] → file: archive/2026-05-q4.md · substring:"Run #350 (S33 Plan B G-H1 Mig 34 EmployeeProfile"
- VIỆC: Run #237 (Hrm CQRS /api/employees + FE×2) + #238 (Danh-bạ /api/directory G-O1). KẾT-LUẬN: both PASS (`79a8343`,`ea440da`), bundles rotate. BÀI-HỌC: **BE namespace mới `SolutionErp.Application.Office` → MediatR auto-discovery WORKS (no manual registration, no gotcha #1)**; menu-seed Off/Off_DanhBa + Permissions auto-grant. BẤT-NGỜ: directory 34 rows @solutions.com.vn populated. [vừa] → file: archive/2026-05-q4.md · substring:"Run #238 (S34 Plan 2 G-O1 Danh bạ nội bộ"
- VIỆC: Run #222-#227 (S26 Plan AG PE-List tree-view UI iteration). KẾT-LUẬN: PASS `0bf6c7e`, bundle rotate. BÀI-HỌC: **hybrid-verify — spawn CICD-monitor 1× at Phase-wire start (ROI good for solo-dev iteration); polish chunks em-main self-verify (avoid re-spawn ~150K × N)**. BẤT-NGỜ: none. [vừa] → file: archive/2026-05-q4.md · substring:"Run #222-#227 cumulative — Plan AG series PE List tree view"
- VIỆC: S33 startup health-check [audit] + S32 wrap [meta] + S32 startup [audit]. KẾT-LUẬN: HEALTHY/no-run. BÀI-HỌC: **Discovery#7 — `eval/**` MISSING from paths-ignore → RAG eval-JSON commits trigger wasteful ~3m30s deploy**; cert api.solutions.com.vn notAfter 2026-07-23 (auto-renew ~06-23). BẤT-NGỜ: RAG-healthy 2949 chunks. [thấp] → file: archive/2026-05-q4.md · substring:"S33 startup health-check — em main spawn read-only verify, VERDICT=HEALTHY"

## Curate-note meta-headers (the remaining 5 [meta]) — runs.md

- VIỆC: 5 S40-curate notes (S23 t5 #202, t6 #203, S24 t1 #210, S25 t3 #217, t5 #219). KẾT-LUẬN: [meta] curate logs (thin — point to the rich run-record above). BÀI-HỌC: #217 note carries **Discovery#5 — sqlcmd Windows-auth over ssh needs `\\\\SQLEXPRESS` 4-backslash** (`\\SQLEXPRESS` = 0 silent output). BẤT-NGỜ: none. [thấp] → file: archive/2026-05-runs.md · substring:"added S25 t3 Plan AC Run #217 entry"

## ‹M7› ‹M19› cross-period markers (live in L1 foundation + spanning)

- VIỆC ‹M7›: gotcha #25 IIS WebSocket. KẾT-LUẬN: `notification-hub/negotiate` 401/404 prod → fix = enable WebSocket module in `web.config` site api (skill iis-deploy-runbook). BÀI-HỌC ‹M7›: SignalR negotiate failure = IIS WebSocket module not enabled. BẤT-NGỜ: this pattern lives in L1 MEMORY.md foundation (Stage 4), not in a dated 2026-05 record — recorded here for marker survival. [cao] → file: (L1) MEMORY.md · substring:"notification-hub/negotiate"
- VIỆC ‹M19›: BUNDLE-HASH lineage chain admin/user. KẾT-LUẬN: rotate chain spans #247→#308 across both gist periods; each record's bundle-hash transition is load-bearing ship-proof. BÀI-HỌC ‹M19›: every bundle-hash transition MUST survive — admin/user FE hashes are the canonical ship-evidence (e.g. early `CzesdXLh`/`DP-gH4LW` → … → live `BgNCjwsG`/`CBvh0vtf`). BẤT-NGỜ: prod CI hash ≠ local-build hash is NORMAL (CI rebuild). [cao] → file: archive/2026-05-runs.md · substring:"Run #186 id=300 sha=eea86fd"
