[CLAUDE] Docs: S97 part-2 closeout — endsBeforeCeo config→RUNTIME (Mig 60) + gotcha #78 + memory harvest

- STATUS/HANDOFF S97 mega-line: +fix-3 endsBeforeCeo; State → Mig 60 / 89 tables / gotcha 78 / bundle DR9q2VUy+Bgz8u4E5 (Run #482)
- gotcha #78: display-flag CONFIG-vs-RUNTIME (nói dối khi instance lệch config; nặng sau opt-in flip)
- session-log Part 2: endsBeforeCeo root-cause + fix + verify (test 440 + reviewer PASS 0-issue + cicd #482 bug-fixed-LIVE)
- Memory harvest: test-specialist + reviewer + cicd-monitor (#482 verdict recover từ diary — #53 return-garble lần-5, root-cause structural noted)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-01 20:16:43 +07:00
parent 8037fa01d1
commit 07c89058d7
7 changed files with 54 additions and 16 deletions

View File

@ -51,8 +51,8 @@ Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Polls Gitea Actions API, ve
- **Prod:** api/admin/eoffice `.solutions.com.vn` · SSH `ssh vietreport-vps` (Administrator, id_ed25519) · IIS phys paths: API `C:\inetpub\solution-erp\api` · admin `\fe-admin` · user `\fe-user`. DB `.\SQLEXPRESS`/`SolutionErp`/`vrapp` SQL-auth. **Conn key = `ConnectionStrings.Default` (NOT `DefaultConnection`)**. DB pw = `buKL3TGBkD0wDDbYVw65QeX9` (User Id=`vrapp`; Password field has NO `vrapp/` prefix S89 login-failed when prefix included; read verbatim from prod `appsettings.Production.json` ConnectionStrings.Default when `$env:PROD_DB_PASSWORD` empty). skill-doc path `C:\inetpub\apps\SolutionErp\Api` STALE.
- **SSHPS quoting (S42):** nested bashsshpowershell mangles `$var`/`\"` use `iconv UTF-16LE | base64` `powershell -EncodedCommand $B64`; OR write ps1-file + `powershell -File $(cygpath -w)`. sqlcmd over SSH direct `-W -h -1` pw-inline. sys-catalog string-concat `COLLATE DATABASE_DEFAULT` (collation conflict).
- **Tests baseline:** **440 PASS** (45 Domain + 395 Infra · 0 fail/skip; S96 Run #480 sha 0c2f9f6 436 + new `PeSuggestedPriceSetterAuthzTests`; prior S96 #479 436, S96/S95 434, S90 #465 421). Phase 9 UAT skip per chunk OK.
- **Mig latest repo:** **Mig 59 `20260624084608_AddCcmBudgetPeriodToPurchaseEvaluation`** (S88 #345; PE +1 AddColumn `CcmBudgetPeriodAmount` decimal(18,2) NULL no-backfill VERIFIED-APPLIED-PROD history-HEAD + col-exists 0-nonnull). Prev Mig 58 `AddPeMultiWinnerAndLevelFinalize` (S87 #344). Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/`. Prod check `sqlcmd __EFMigrationsHistory ORDER BY MigrationId DESC TOP 5`. **`sys.tables` (is_ms_shipped=0) = 88** (S61 Budget-replace DROPPED 9388 narrative-93 STALE; when commit touches no schema, 88 correct, don't FAIL on 88. Always cross-ref COMMIT scope vs ambient count). enum-additive (e.g. `ApprovalAttachment=5`) = int-stored NO-mig expect history NOT-advance + empty `git diff -- '*Migrations*'`.
- **Bundle hash live (S96 Run #480/id=480 JS-rotated real-FE, CSS-frozen):** admin js **`COYAX-yQ`**/css `Bbtesa6B` · user js **`0MU-kb4N`**/css `BmuPz_Dy` (JS rotated from S96 `kL1-N1Zq`/`BRCrr80A` = real PeWorkflowPanel+PeDetailTabs FE change; CSS IDENTICAL S96/S96 = logic+gate-only #69-REFINE byte-identical-CSSsame-hash). **id ≠ run_number(365); head_sha-keyed.** **PER #69: hash MAY rotate per deploy (real src-diff) OR stay frozen if 0 fe-src diff (byte-identical) — SNAPSHOT for THIS run, NOT a frozen baseline; ALWAYS re-snapshot LIVE pre-deploy (brief prev-hash=hint NOT truth).** Real FE ship = diff `fe-*/src` in commit/range + real-size-vs-fake (1.6/1.5MB vs ~919b SPA-trap) + Last-Modified-in-window, NOT hash delta alone.
- **Mig latest repo:** **Mig 60 `20260701120138_AddPeEndedByLevelFinalize`** (S98 #482; PE +1 AddColumn `EndedByLevelFinalize` bit NOT NULL default 0 + `Sql()` backfill Phase=7-marker→=1 [SQL-Server-only, tests skip-replay #63] VERIFIED-APPLIED-PROD history-HEAD + col-exists is_nullable=0 default CONVERT([bit],(0)) + backfill=0 fresh-UAT). Prev Mig 59 `AddCcmBudgetPeriodToPurchaseEvaluation` (S88 #345). Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/`. Prod check `sqlcmd __EFMigrationsHistory ORDER BY MigrationId DESC TOP 5`. **`sys.tables` (is_ms_shipped=0) = 89** (S98 LIVE-verified pre AND post #482 narrative/spec-88 STALE, re-ground 89 = current truth; AddColumn-only migs don't change count when commit touches no schema, 89 correct don't FAIL. Always cross-ref COMMIT scope vs ambient count). enum-additive (e.g. `ApprovalAttachment=5`) = int-stored NO-mig expect history NOT-advance + empty `git diff -- '*Migrations*'`.
- **Bundle hash live (S98 Run #482/id=482 JS-rotated real-FE, CSS-frozen):** admin js **`DR9q2VUy`**/css `Bbtesa6B` · user js **`Bgz8u4E5`**/css `BmuPz_Dy` (JS rotated from S97 `Cf0o8dx8`/`x8rppRAK` = real PeWorkflowPanel 2-app endsBeforeCeo-gate FE change; CSS IDENTICAL = JSX-logic-only #69-REFINE byte-identical-CSSsame-hash). **id ≠ run_number(368); head_sha-keyed.** **PER #69: hash MAY rotate per deploy (real src-diff) OR stay frozen if 0 fe-src diff (byte-identical) — SNAPSHOT for THIS run, NOT a frozen baseline; ALWAYS re-snapshot LIVE pre-deploy (brief prev-hash=hint NOT truth).** Real FE ship = diff `fe-*/src` in commit/range + real-size-vs-fake (1.6/1.5MB vs ~919b SPA-trap) + Last-Modified-in-window, NOT hash delta alone.
- **Bearer:** admin `admin@solutions.com.vn/Admin@123456` (full) · UAT `nv.test@solutions.com.vn/TestUser@123456` (Drafter CCM, gotcha #44 check).
## 🔑 Critical config (flag commit nếu tái xuất)
@ -70,12 +70,11 @@ BE (test+build) ~90s · FE × 2 ~60s/app · deploy ~30s · **total ~3min code /
## 📅 Recent runs (compressed — full verbatim → `archive/2026-06.md` via `archive/_INDEX.md`)
- **🟢 S97 #481 (id=481, run_number 367) `1c8fb6a` GO ~5m10s (PASS) — FE-ONLY PE finalize 2-fix, mirror 2-app SHA-identical `PeWorkflowPanel.tsx` (fe-admin+fe-user), NO BE/mig/test.** Fix1 badge cấp-sau-finalize `"không trình tới"``"Kết thúc tại {finalizeLevelName}"` (render-động + tooltip template-literal) · Fix2 đảo default checkbox "Cấp KẾT THÚC" opt-out→**opt-in** (`useState(true)``false` + reset onSuccess + helper reword). Poll running→success ~5m10s (18:05:56→18:11:06; busy-wait-spin, `updated_at` advancing=alive; foreground-sleep-BLOCKED Win). status=success ⟹ test-gate green (baseline **440**=45D+395I; tasks-API terminal-success trust-NOT-log-numeric). 🎯 **FE JS ROTATED (real FE proof — 2-app PeWorkflowPanel diff)**: admin `COYAX-yQ`(S96)→**`Cf0o8dx8`** + user `0MU-kb4N`(S96)→**`x8rppRAK`** ✅. **CSS FROZEN** admin `Bbtesa6B`/user `BmuPz_Dy` = IDENTICAL S96 (JSX-text+useState-bool-only, 0-style-diff ⟹ #69-REFINE byte-identical-CSS⟹same-hash). Real-size guard-SPA-trap: admin JS **1,636,732B** + user **1,543,053B** `application/javascript` (control fake `ZZfakehash0.js`→919B text/html=SPA-fallback ⟹ real-genuine); Last-Modified admin 11:09:44GMT=18:09:44+07 / user 11:10:38GMT=18:10:38+07 (in-window 18:05→18:11). 🔴 **BYTE-LEVEL grep (gotcha #77) BOTH apps CLEAN**: NEW `Kết thúc tại`=PRESENT(×1) + NEW helper `Mặc định: duyệt xong phiếu TRÌNH TIẾP`=PRESENT(×1) + tooltip `không cần trình tới`=PRESENT · OLD JSX `không trình tới`=ABSENT(0) + OLD helper `Đã BỎ tick`=ABSENT(0) ⟹ fix shipped byte-level, UI-cũ=cache→incognito NOT deploy-fail. **Mig prod=59 `AddCcmBudgetPeriodToPurchaseEvaluation` UNCHANGED**=repo-HEAD (0-mig-file commit⟹correct-frozen) + `sys.tables`(is_ms_shipped=0,excl-history)=**88** frozen. Smoke: api ready/live+admin/eoffice-root ALL 200, auth accessToken 468ch, GET /api/purchase-evaluations **200 items[]-valid** (PE-not-broken) + /approval-workflows-v2 **200**. ⚠️ UI badge-text/checkbox-default NOT curl-verifiable (login+phiếu-thật → anh Kiệt UAT); scope=deploy-ship+test-gate+JS-rotate+byte-grep+smoke+Mig-frozen. 🔑 **FE-ONLY-REAL-CHANGE PASS = JS-hash-rotate(vs prev-snapshot) + real-size-vs-919b-trap + Last-Modified-in-window + CSS-frozen-OK(#69-REFINE logic-only) + BYTE-LEVEL-grep-new-PRESENT/old-ABSENT(#77) + Mig+88-frozen + smoke-200-payload-valid**. ⚠️ tooling: **no-jq → Python-JSON-parse for id-match** (grep-slice `"id":<id>,` BROKE→empty-status, wasted iter); background-output-file NEVER-materialized this Win-setup → **foreground-poll-only reliable**.
- _(S96 #480 `0c2f9f6` GO ~5m25s PASS — cross-stack PE 3-commit range ba4b8e0→HEAD [e657faa opt-out-checkbox BE+FE + 36cbf8b mark-read-noti BE + 0c2f9f6=HEAD khóa-giá-PRO/CCM-sau-gửi BE+FE PeDetailTabs+test], NO-mig · baseline-440 +new PeSuggestedPriceSetterAuthzTests · JS admin`0T6vVJST``COYAX-yQ`/user`BGXEVZO6``0MU-kb4N` rotated **CSS FROZEN** Bbtesa6B/BmuPz_Dy · real-size 1636639/1542960B · Mig59-frozen · w3wp PID3184@16:12:39 · full verbatim → git `0c2f9f6` + archive `2026-06.md` via `_INDEX`)_
- _(S96 #479 `36cbf8b` GO ~5m40s PASS — PE 2-commit e657faa opt-out-checkbox+36cbf8b mark-read-stale-noti NO-mig · baseline-436 · JS admin`0T6vVJST``kL1-N1Zq`/user`BGXEVZO6``BRCrr80A` rotated **CSS FROZEN** Bbtesa6B/BmuPz_Dy · real-size 1636619/1542940B · Mig59-frozen · w3wp PID3024@15:52:19 · full verbatim → git `36cbf8b` + archive `2026-06.md` via `_INDEX`)_
- _(S96 #477 `ba4b8e0` Infra data-only seed import NCC `DONGDUONG` Excel anh-Kiệt NO-mig ungated-idempotent · baseline-434 · 🎯 DONGDUONG-LANDED pre=3→post=4 suppliers total=21 EXACT+1-idempotent Type=2-NhaThauPhu · **FE bundle FROZEN** admin `0T6vVJST`/user `BGXEVZO6` 0-fe-src-diff(#69-REFINE) · Mig59-frozen · w3wp PID13660@14:54:28 recycle+DLL-in-window · 🔑 **DATA-SEED-PASS = pre-vs-post-DB-row-EXACT-delta + DLL-mtime + w3wp-recycle + Mig-frozen + API-payload-contains-row** · ⚠️ sqlcmd `-W` diacritic-LIKE false-NEG use `_`-wildcard; base64-EncodedCommand-FAIL→`.ps1`-File-method reliable — full verbatim → git `ba4b8e0` + archive `2026-06.md` via `_INDEX`)_
- _(S95 #476 `18a17f5` GOVERNANCE-ONLY adopt Harness-17 — 2 `.ps1` scripts/ trigger CI despite 0-prod-code · baseline-434 · JS→`0T6vVJST`/`BGXEVZO6` rotated **CSS FROZEN** · Mig59 frozen · brief-prev-hash STALE→re-snapshot-LIVE · 🔑 GOVERNANCE-PASS=CI-green+JS-rotate/CSS-frozen(#69)+3×200+Mig-frozen — full verbatim → git `18a17f5` + archive `2026-06.md` via `_INDEX`)_
- _(S93 #473 `8ee8f3e` FULL-STACK PE tree-node show-CODE DTO+3-proj NO-MIG · S92 #472 `1408d4e` BE-only permission-revoke +5-menu-group VERIFY-PROD-EFFECT [hidden-key non-Admin CanRead=0, Admin-retained, Pe_* untouched, leak=0; ⚠️ **PROD Identity tables NON-prefixed `Roles` NOT `AspNetRoles`**] · S91 #470 `55494ad` GO-LIVE no-resurrect demo-NCC seed-gate [pre+post-restart demo-code=0; **PATTERN go-live-no-resurrect = pre+post-DB-count-diff + dll-in-window + w3wp≥run-window**; integrated-auth `-E`] · S90 #465 `a71753b` FULL-STACK PE draft-private js-rotate-css-FROZEN → all PASS baseline-422→434, full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- **🟢 S98 #482 (id=482, run_number 368) `8037fa0` GO ~4m (PASS) — CROSS-STACK BE+Mig60+FE+tests, endsBeforeCeo config→RUNTIME (phiếu lên CEO hết báo sai "không qua CEO", anh Kiệt FDC UAT).** 12 files: Domain PE +`EndedByLevelFinalize` · **Mig 60 `20260701120138_AddPeEndedByLevelFinalize`** (AddColumn bit NOT NULL default 0 + `Sql()` backfill Phase=7-marker→=1, SQL-Server-only tests-skip-replay #63) · Features list+detail ternary · WorkflowService · FE `PeWorkflowPanel.tsx` 2-app. Poll running→success 19:23→19:28. status=success ⟹ test-gate green (baseline **440**). 🔴 **Mig 60 APPLIED-PROD**: history-top==Mig60 (pre=Mig59, advanced) · col `EndedByLevelFinalize` bit is_nullable=0 default `CONVERT([bit],(0))` EXISTS · backfill=0 (fresh-UAT no-marker) · **sys.tables=89 pre AND post** (AddColumn no-new-table; ⚠️ spec/baseline-88 STALE, LIVE-truth=89 identical pre/post NOT regression). 🔴 **EF-TERNARY SQL-Server TRANSLATE LIVE-CONFIRMED (SQLite≠SQL Server)**: `GET /api/purchase-evaluations` **200** items=9 endsBeforeCeo-present (NOT 500 → `Phase==DaDuyet?EndedByLevelFinalize:subquery.Any()` translates ✅) + PE-detail `31faef0d` **200** endsBeforeCeo=False phase=7 (runtime-path executed = exact-bug-fix) + `/inbox` 200 + `/approval-workflows-v2` 200 (`/approved` 404=wrong-route NOT regression). 🎯 **FE JS ROTATED (real 2-app diff)**: admin `Cf0o8dx8``DR9q2VUy` + user `x8rppRAK``Bgz8u4E5` · **CSS FROZEN** Bbtesa6B/BmuPz_Dy (JSX-logic-only ⟹ #69-REFINE). Real-size 1,636,753/1,543,074B `application/javascript` (control fake→919B text/html SPA-trap) · Last-Modified admin 12:27:07GMT/user 12:27:59GMT =19:27+07 in-window. 🔴 **BYTE-LEVEL grep #77 admin bundle**: `endsBeforeCeo`=PRESENT(1)+`allowApproverFinalize`=PRESENT(2) ⟹ shipped (`finalizeFlowStep`=0=local-const MINIFIED expected-absent). Smoke: api ready/live+admin/eoffice-root 200, auth 468ch. w3wp recycle-clean (transient 127.0.0.1:5443 refused mid-recycle 19:25 → public 200 by verify). 🔑 **CROSS-STACK+MIG PASS = CI-success + Mig-top==HEAD + col-correct-default + sys.tables-stable + EF-ternary-200-NOT-500-live + JS-rotate/CSS-frozen(#69) + real-size-vs-919b + LastMod-in-window + byte-grep-field-PRESENT(#77) + smoke-200**. ⚠️ tooling: busy-wait-spin TOO-SLOW this Win-setup → single-shot-recheck + DLL-mtime-cross-signal beats blind-loop; no-jq→Python-JSON.
- _(S97 #481 `1c8fb6a` GO ~5m10s PASS — FE-ONLY PE finalize 2-fix mirror 2-app SHA-identical PeWorkflowPanel [badge `không trình tới``Kết thúc tại {name}` + checkbox opt-out→opt-in] NO-BE/mig/test · baseline-440 · JS admin`COYAX-yQ``Cf0o8dx8`/user`0MU-kb4N``x8rppRAK` rotated **CSS FROZEN** Bbtesa6B/BmuPz_Dy · real-size 1636732/1543053B · #77 byte-grep BOTH-apps new-PRESENT/old-ABSENT · Mig59-frozen sys.tables-88[STALE→89] · full verbatim → git `1c8fb6a` + archive `2026-06.md` via `_INDEX`)_
- _(S96 #480 `0c2f9f6` cross-stack PE 3-commit-range khóa-giá+mark-read+opt-out NO-mig baseline-440+new-PeSuggestedPriceSetterAuthzTests JS-rotate/CSS-frozen · S96 #479 `36cbf8b` PE 2-commit mark-read-stale-noti baseline-436 JS-rotate/CSS-frozen · all PASS Mig59-frozen · full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- _(S96 #477 `ba4b8e0` Infra data-seed NCC `DONGDUONG` ungated-idempotent 🎯 pre=3→post=4 suppliers total=21-EXACT Type=2 **FE-FROZEN** 0-fe-src(#69) · 🔑 **DATA-SEED-PASS = pre/post-DB-row-EXACT-delta + DLL-mtime + w3wp-recycle + Mig-frozen + API-payload-contains-row** · ⚠️ sqlcmd `-W` diacritic-LIKE false-NEG use `_`-wildcard; base64-EncodedCmd-FAIL→`.ps1`-File · S95 #476 `18a17f5` GOVERNANCE-ONLY .ps1-triggers-CI JS-rotate/CSS-frozen 🔑 GOVERNANCE-PASS=CI-green+JS-rotate(#69)+3×200+Mig-frozen — all PASS full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- _(S93 #473 `8ee8f3e` PE tree-node show-CODE NO-MIG · S92 #472 `1408d4e` BE permission-revoke +5-menu VERIFY-PROD [non-Admin CanRead=0, Pe_* untouched; ⚠️ **PROD Identity tables NON-prefixed `Roles` NOT `AspNetRoles`**] · S91 #470 `55494ad` GO-LIVE no-resurrect demo-seed-gate [**PATTERN go-live-no-resurrect = pre+post-DB-count-diff + dll-in-window + w3wp≥run-window**; integrated-auth `-E`] · S90 #465 `a71753b` PE draft-private js-rotate/css-FROZEN → all PASS baseline-422→434, full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- _(S89 #348 `1aa3bdb` PE create-contract-1→N multi-winner endpoint-411→401 · S88-quad #347 `73cce1f` PE D1 Block-B re-key+CEO-notify · S88-bis #346 `0d3c0cf` FE-only PE-layout js+css-BOTH-rotate · **S88 #345 `9b1ee0c` = Mig 59 `AddCcmBudgetPeriodToPurchaseEvaluation` AddColumn-no-backfill VERIFIED-PROD** setter PATCH-401 + 7 authz-test → all PASS, full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- _(S87 #344 `f1b10e9` FULL-STACK PE CCM 3-fix + **Mig 58 `AddPeMultiWinnerAndLevelFinalize`** backfill-winners=13 VERIFIED-PROD select-winner-411→401 · S86 #343 `ae4f106` BE-only notify-exclude-drafter ship-proof=Infrastructure.dll-Last-Modified · S85 #342 `d4f6021` DOCS+SQL-no-op INVERTED-PASS-when-FROZEN [gotcha #73 TZ + #69-REFINE] · S83 #333 `fc1f19d` BE-only guard-V2-required hash-FROZEN-but-shipped · S78 #330 `7886fd0` enum-attach-on-approve · S76 #318 `e33481e` Mig56-ProInitial/Adjust · S74-bis #315 Mig55 · S73 #313 Mig54-endpoint-401-not-404-probe · S69b #307 Office-golive-seed-16/16 → all PASS, full verbatim → git + archive `2026-06.md` via `_INDEX`)_
- **Older runs (S83 #325 FE-budget-indent ← S77 #329 banner ← S75 #301 ← S62 #286 ← … → S29 #232) full verbatim → git `d2f52ba` + `archive/2026-06.md`** (incl #291 06-16 FAIL forensic [gotcha #65]); pre-S38 → `archive/2026-05-{runs,q2,q3,q4}.md`.