wal: flush 20260717T1446

This commit is contained in:
pqhuy1987
2026-07-17 14:46:51 +07:00
parent 1e799eed3d
commit 169b0dc42f
4 changed files with 164 additions and 0 deletions

View File

@ -0,0 +1,79 @@
# sub-cicd-monitor-0 — S133 pe-budget-freeze deploy verify (commit d4fbced)
> Read-only CI/CD verifier. Evidence dồn dần (anti-#53). VERDICT ở cuối khi đủ 5 mục.
> Target commit: `d4fbced02f6a24df7177c33adc21b8ca89140a0c`
> Subject: `[CLAUDE] PurchaseEvaluation: freeze ngân sách phiếu DaDuyet — Mig 67 snapshot 11 cột + display-gate budgetFrozen + 2 terminal-guard (UAT anh Kiệt 07-16)`
## Stage 1 — Push + path-filter (DONE)
- `git rev-parse origin/main` = `d4fbced02f6a24df7177c33adc21b8ca89140a0c` → d4fbced IS on origin/main. PASS.
- `git branch -r --contains d4fbced``origin/main`. PASS.
- Local HEAD = `bf79842 wal: flush 20260717T1116` (1 commit ahead, unpushed docs/WAL — NOT the target, irrelevant).
- Files changed `9e874ca..d4fbced` (28 files): FULL-STACK
- BE: PeBudgetAccumulator.cs, PeWorkItemBudgetFeatures.cs, PurchaseEvaluationFeatures.cs, PurchaseEvaluationDtos.cs, Domain/PurchaseEvaluation.cs, PurchaseEvaluationConfiguration.cs, DbInitializer.cs, PurchaseEvaluationWorkflowService.cs
- Mig 67: `20260717032812_AddPeApprovedBudgetSnapshot.cs` + .Designer.cs + ApplicationDbContextModelSnapshot.cs
- FE: fe-admin/{PeDetailTabs.tsx, types/purchaseEvaluation.ts}, fe-user/{PeDetailTabs.tsx, types/purchaseEvaluation.ts} → 4 real fe-src files → bundle MUST rotate ×2
- Tests: PeBudgetFreezeTests.cs
- Governance/memory/run-trace: .claude/WAL.md, agent-memory×4, run.md, spec + 4 sub-*.md
- Non-docs code present → CI MUST trigger (NOT docs-skip). CONFIRMED triggered (run #398 exists).
## Stage 1b — Migration file review (Mig 67, DONE)
- `20260717032812_AddPeApprovedBudgetSnapshot.cs`: 11 AddColumn on PurchaseEvaluations, 0 CreateTable:
1. ApprovedBudgetProInitialAmount decimal(18,2) null
2. ApprovedBudgetProAdjustmentAmount decimal(18,2) null
3. ApprovedBudgetProNote nvarchar(1000) null
4. ApprovedBudgetCcmInitialAmount decimal(18,2) null
5. ApprovedBudgetCcmAdjustmentAmount decimal(18,2) null
6. ApprovedBudgetCcmNote nvarchar(1000) null
7. ApprovedBudgetPrevSubmittedTotal decimal(18,2) null
8. ApprovedBudgetPrevSubmittedCount int null
9. ApprovedBudgetPrevSelectedTotal decimal(18,2) null
10. ApprovedBudgetPrevSelectedCount int null
11. ApprovedBudgetSnapshotAt datetime2 null
- Backfill `Sql()`: `UPDATE ... SET ... SnapshotAt=SYSUTCDATETIME() WHERE pe.Phase=7 AND pe.ApprovedBudgetSnapshotAt IS NULL AND pe.IsDeleted=0`. Idempotent. → post-apply ALL Phase=7 rows have SnapshotAt NOT NULL → expected chua=0.
- NO CreateTable → sys.tables invariant 89 should hold.
## Stage 2 — Gitea CI poll (IN PROGRESS)
- API: `/api/v1/repos/vietreport-admin/solution-erp/actions/tasks?limit=8` (anon, GITEA_TOKEN empty — public repo OK). NOT /runs (404, gotcha #46).
- Run #398 | head_sha d4fbced02f | status=running | conclusion=None (prev #397 72f68d1 success — matches SPEC baseline).
- Polling until terminal status... (conclusion stays None even on success per memory — trust `status`).
### Stage 2 RESULT — CI PASS
- Run #398 (d4fbced02f) → `status=success` @ updated_at `2026-07-17T11:20:02+07:00` (conclusion=None = Gitea tasks-API norm, trust status). Prev #397 success — baseline OK.
- Poll note: python subprocess `capture_output=True` (text) crashed cp1252 on Vietnamese titles ×14 iters; re-fetch with `text=False`(bytes)+`json.loads(bytes)` → clean. Elapsed ~6min covered the run.
- Test gate (web-UI log `runs/398/jobs/0/logs`, 17936 bytes, NO /api/v1):
- `Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45` — SolutionErp.Domain.Tests
- `Passed! - Failed: 0, Passed: 475, Skipped: 0, Total: 475` — SolutionErp.Infrastructure.Tests
- 45 + 475 = **520**, 0 fail/skip → matches SPEC baseline. **PASS.**
## Item 2 — Mig prod (ssh vietreport-vps sqlcmd, DONE)
- `__EFMigrationsHistory` TOP3: `20260717032812_AddPeApprovedBudgetSnapshot` (top) · `20260714035636_AddPeApprovedPriceRange` · `20260712142652_Backfill...` → top == SPEC target. **PASS.**
- sys.columns ApprovedBudget* on PurchaseEvaluations = **11** (all 11 names present, exact match to Mig 67 file). **PASS.**
- Backfill `WHERE Phase=7 AND IsDeleted=0`: total=**18**, chua(SnapshotAt IS NULL)=**0** → all 18 DaDuyet phiếu snapshotted. **PASS.**
- sys.tables is_ms_shipped=0 = **89** (no new table — AddColumn-only). **PASS.**
## Item 3 — Bundle FE rotate + byte-verify #77 (DONE)
- ADMIN index.html: js `/assets/index-3NCdyODe.js` css `/assets/index-B--dUHcm.css` (was S129 js `yCkX-2Bp` css `CXD7q9xH`) → JS+CSS ROTATED.
- EOFFICE index.html: js `/assets/index-CKsoiNCI.js` css `/assets/index-BuntB63r.css` (was S129 js `DKSD4p9k` css `CjwZwYJo`) → JS+CSS ROTATED.
- Real-size + LM: admin.js 1,657,025 B, LM `Fri 17 Jul 2026 04:18:42 GMT` (11:18:42 +07) · eoffice.js 1,563,373 B, LM `04:19:36 GMT` (11:19:36 +07) — both application/javascript, LM in CI window (run done 11:20:02 +07). NOT SPA-trap.
- Byte-verify markers (python bytes-search): admin.js `budgetFrozen`=1, `Ngân sách chốt tại thời điểm duyệt`=1 · eoffice.js both=1.
- CONTROL old admin `yCkX-2Bp` → 900 B text/html (SPA-fallback trap), markers=0 → confirms markers are NEW not fallback. **PASS.**
## Item 4 — Smoke (DONE)
- api/health/live=200 · api/health/ready=200 (body "Healthy") · admin=200 · eoffice=200 · GET /api/purchase-evaluations no-token=**401** (secured). **PASS.**
## Item 5 — Traps handled
- S116: polled CI to `success` BEFORE bundle snapshot ✓ · #69: rotate benign (4 real fe-src changed → rotate expected) ✓ · #77: curl byte-level + old-hash control (900b SPA-trap) not browser ✓.
---
## VERDICT | GO (5/5 PASS)
| # | Item | Verdict | Key evidence |
|---|------|---------|--------------|
| 1 | CI run #398 + gate 520 | PASS | status=success; Domain 45/45 + Infra 475/475, 0 fail |
| 2 | Mig 67 prod applied | PASS | history top=AddPeApprovedBudgetSnapshot; 11 cols; backfill 18/18 chua=0; 89 tables |
| 3 | Bundle rotate ×2 + byte-verify | PASS | admin js 3NCdyODe / eoffice js CKsoiNCI; markers present; old-control 0; real-size+LM-in-window |
| 4 | Smoke 5-probe | PASS | live/ready 200, admin/eoffice 200, PE no-token 401 |
| 5 | Traps (S116/#69/#77) | PASS | poll-then-snapshot; benign rotate; byte-level+control |
Run URL: https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/398
Token cost: ~90K. No production file modified (only this run-trace sub-file).

View File

@ -60,3 +60,60 @@ Failed! - Failed: 1, Passed: 0, Skipped: 0, Total: 1, Duration:
**Verdict:** T0 RED PASS-as-designed. KHÔNG PREMISE-FAIL (không GREEN bất ngờ). KHÔNG chạm production. Sẽ GREEN sau khi implementer thêm snapshot ngân sách tại 4 site DaDuyet + display-gate đọc cột snapshot.
**Baseline:** 509 → 510 test (test này RED tới khi fix land — test-before đúng quy trình bug-fix docs/rules.md §7).
---
# STAGE C — INV-C T1-T9 (BE ĐÃ LAND, T0 ĐÃ GREEN → phủ nhánh/guard/edge còn lại)
Role: test-specialist. KHÔNG đụng src/ · KHÔNG sửa T0/test cũ. Thêm T1-T9 vào cùng file `PeBudgetFreezeTests.cs`.
## Anchors verified (đọc code truth — BE post-fix)
- Domain `PurchaseEvaluation.cs:122-132` — 11 cột snapshot: ApprovedBudgetProInitialAmount/ProAdjustmentAmount/ProNote · CcmInitialAmount/CcmAdjustmentAmount/CcmNote · PrevSubmittedTotal/Count · PrevSelectedTotal/Count · SnapshotAt.
- Service helper `ApplyBudgetSnapshotOnFinalizeAsync` def :994; gọi 4 site: :861 (level-finalize AllowApproverFinalize) · :900 (CCM-threshold delegation) · :933 (all-steps-done) · :1108 (V1 legacy — CHỈ snapshot, KHÔNG ApplyApprovedPrice). Helper: WorkItemId null → 10 cột null + SnapshotAt set; pair thiếu → 6 pair cols null; 4 lũy kế qua PeBudgetAccumulator; LUÔN overwrite + LUÔN SnapshotAt=dateTime.UtcNow.
- Helper NAMING: pair.InitialAmount/AdjustmentAmount = CCM; pair.ProInitialAmount/ProAdjustmentAmount = PRO.
- Display-gate `PurchaseEvaluationFeatures.cs:928` `frozen = Phase==DaDuyet && ApprovedBudgetSnapshotAt!=null`. Frozen branch :929-954 → CanEditPro/Ccm HARDCODE false,false (KỂ CẢ Admin) + BudgetFrozen=true + lũy kế từ snapshot + CurrentProposalTotal VẪN live-own-quotes. Live branch :956-984 → accumulator + canEditPro/Ccm theo role + BudgetFrozen=false.
- Guard 7a `SetPeCcmBudgetPeriodCommandHandler` PeWorkItemBudgetFeatures.cs:235 — `Phase is DaDuyet or TuChoi` → Conflict TRƯỚC role-gate (chặn CẢ Admin lẫn CCM).
- Guard 7b `AdjustPurchaseEvaluationBudgetCommandHandler` PurchaseEvaluationFeatures.cs:365 — cùng message, TRƯỚC isAdmin block.
- Accumulator: peers cùng (ProjectId,WorkItemId), Id!=this, CreatedAt<this. TestApplicationDbContext KHÔNG wire audit interceptor set CreatedAt thủ công (peers earlier, current later).
- V1 legacy: PurchaseEvaluationWorkflowDefinition + Steps + Approvers(Kind=User AssignmentValue=userId). Match qua userManager.FindByIdAsync cần user THẬT (fix.CreateUserAsync).
## T1-T9 danh sách (tên test = scenario_expected)
- T1 `LevelFinalize_SnapshotsAll11Columns_FromPairAndAccumulator` (:861) 6 pair cột + notes + 2 peer (PrevSubmitted 150tr/2, PrevSelected 90tr/1) + SnapshotAt.
- T2 `CcmThresholdFinalize_SetsBudgetSnapshot` (:900) CCM delegation below-threshold snapshot pair cols + SnapshotAt.
- T3 `AllStepsDoneFinalize_SetsBudgetSnapshot` (:933) 1 Bước 1 Cấp no-finalize-flag, approve last slot snapshot + DaDuyet.
- T4 `V1LegacyFinalize_SetsBudgetSnapshot_WithoutApprovedPrice` (:1108) def+step+user-approver snapshot set + ApprovedPriceAmount==null.
- T5 `SetCcmBudgetPeriodGuard_BlocksDaDuyet_ForCcmAndAdmin_AllowsChoDuyet`.
- T6 `AdjustBudgetGuard_BlocksDaDuyetAndTuChoi_ForAdmin`.
- T7 `BudgetSummary_LiveVsFrozen_FlagsAndEditability`.
- T8 `Finalize_NullSafe_NoWorkItemAndNoPairRecord`.
- T9 `ReFinalize_AlwaysOverwritesStaleSnapshot_RefreshesSnapshotAt`.
## Kết quả chạy — ✅ ALL GREEN (T1-T9 phủ đủ, 0 RED phase vì BE đã land)
**Filtered:** `dotnet test SolutionErp.slnx --filter "FullyQualifiedName~PeBudgetFreeze" --nologo -p:BuildInParallel=false -maxcpucount:1`
`Passed! - Failed: 0, Passed: 10, Skipped: 0, Total: 10` (T0 + T1-T9).
**FULL:** `dotnet test SolutionErp.slnx --nologo --verbosity minimal -p:BuildInParallel=false -maxcpucount:1`
Domain `Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45`
Infra `Passed! - Failed: 0, Passed: 474, Skipped: 0, Total: 474`
**Tổng 519 PASS / 0 fail / 0 skip** = baseline 510 (509 + T0) + 9 (T1-T9).
## Bảng T1-T9 (verdict)
| Test | Nhánh/guard/edge | Verdict |
|---|---|---|
| T1 `LevelFinalize_SnapshotsAll11Columns_FromPairAndAccumulator` | :861 level-finalize 11 cột | PASS |
| T2 `CcmThresholdFinalize_SetsBudgetSnapshot` | :900 CCM-delegation | PASS |
| T3 `AllStepsDoneFinalize_SetsBudgetSnapshot` | :933 all-steps | PASS |
| T4 `V1LegacyFinalize_SetsBudgetSnapshot_WithoutApprovedPrice` | :1108 V1 + giá null | PASS |
| T5 `SetCcmBudgetPeriodGuard_BlocksDaDuyet_ForCcmAndAdmin_AllowsChoDuyet` | guard 7a | PASS |
| T6 `AdjustBudgetGuard_BlocksDaDuyetAndTuChoi_ForAdmin` | guard 7b | PASS |
| T7 `BudgetSummary_LiveVsFrozen_FlagsAndEditability` | display live/frozen | PASS |
| T8 `Finalize_NullSafe_NoWorkItemAndNoPairRecord` | null-safe (a)+(b) | PASS |
| T9 `ReFinalize_AlwaysOverwritesStaleSnapshot_RefreshesSnapshotAt` | overwrite semantics | PASS |
## Surprise / bẫy đã xử
- **UNIQUE(ApprovalWorkflows.Code, Version)**: T8 gọi `SeedAndFinalizeAsync` 2 lần/1 db helper `SeedFinalizeWorkflowAsync` Code cố định "QT-BF-V2" v1 SQLite Error 19 (RED lần 1). Fix: thêm param optional `code="QT-BF-V2"` (T0 call-site 2-arg GIỮ NGUYÊN, hành-vi T0 bất biến) + `SeedAndFinalizeAsync` truyền `$"QT-BF-V2-{suffix}"`. Không đụng T0-logic.
- KHÔNG chạm src/ production. KHÔNG sửa T0. Test 0 regression (509 baseline vẫn xanh). KHÔNG REGRESSION-FOUND.
**Verdict:** INV-C COMPLETE 9 test mới GREEN, phủ 4 nhánh snapshot + 2 guard + 2 edge + display live/frozen. Tổng 519/519.