Files
solution-erp/.claude/agent-memory/cicd-monitor/MEMORY.md
pqhuy1987 21be786c9e [CLAUDE] Docs: S97 badge "Đã được CEO duyệt" (#483) closeout — STATUS/HANDOFF/log + memory harvest
- fix-4 badge (đối xứng fix-3 endsBeforeCeo): PeFinalizeChip DaDuyet+!endsBeforeCeo → " Đã được CEO duyệt"
- STATUS/HANDOFF: bundle CeTA7Z82+CGaAyXen (Run #483), 3-fix→4-fix, session-log Part 3
- Memory harvest: implementer-frontend + cicd-monitor (#483 verdict clean-return, no #53 garble lần này)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 21:01:55 +07:00

89 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# CI/CD Monitor Agent — Persistent Memory
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
> Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
> Full verbatim run history pre-S40 → git `d2f52ba` + `archive/2026-05-{runs,q2,q3,q4}.md` + `archive/2026-06.md`. 🗺️ **Lookup map: `archive/_INDEX.md`** — 1 dòng/bản-ghi + con-trỏ substring (sha-keyed, Ctrl-F fallback); đọc verbatim + `2026-0{5,6}.gist.md` theo nhu cầu. **S80 curate: moved 3 huge run-entries (#330/#318/#325) → archive.**
---
## 🎯 Role baseline
Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Polls Gitea Actions API, verifies test gate + deploy ship + prod health. Tools: Read, Grep, Glob, Bash, WebFetch + 5 RAG MCP. Output: PASS/FAIL + evidence <500 words. Skills: `iis-deploy-runbook` + `dependency-audit-erp` + `ef-core-migration`. Spawn ~150K trade-off catch fail tự động.
---
## 🚨 Recurring CI/CD bug patterns (catch priority)
- **#39 act_runner github.com TCP timeout** run hang "Set up job" 21s. Log `dial tcp github.com:443 i/o timeout`. Fix: manual checkout bypass hardcoded `.gitea/workflows/deploy.yml`. KHÔNG revert.
- **#40 npm cache `tsc not found`** `build_fe_admin` fail post `cache: npm`. DISABLED rolled back `a21790d`. KHÔNG re-enable.
- **#41 paths-ignore docs-only skip** code commit không trigger CI? Check `git diff --name-only HEAD~1 HEAD` vs `paths-ignore: ['docs/**','**/*.md','.claude/skills/**']`. Gitea evaluates push *range* 1 commit non-ignored file toàn range build.
- **#25 IIS WebSocket** `notification-hub/negotiate` 401/404 prod. Fix: WebSocket module enable `web.config` site api (skill `iis-deploy-runbook`).
- **#48 SQLite tie-break** `OrderByDescending(CreatedAt).First()` pick wrong khi 2+ `.Add()` cùng frozen-clock. Fix: discriminator filter BEFORE OrderBy.
- **Bundle hash unchanged = ship FAIL** push+action success nhưng prod không đổi. Verify via INDEX.HTML ref (`curl -s https://admin.solutions.com.vn/ | grep -oE '/assets/index-[A-Za-z0-9_-]+\.(js|css)'`), NOT by GETting a hash-named asset directly. verify MUST sau status=success (Run #242 false-positive: check khi "running" stale hash).
- **🔴 #69 (S72 Run #312) FE bundle hash NON-DETERMINISTIC per rebuild.** `deploy.yml` `Remove-Item fe-*\* -Exclude web.config` + `Copy-Item dist\*` runs UNCONDITIONALLY every run (path-filter gates whole-workflow trigger, NOT per-step). Identical FE source DIFFERENT hash each deploy (Vite/rolldown non-reproducible chunk-id). PROVEN: governance-only `18fced6` (0 files in fe-*/src) rotated BOTH bundles. "BE-only/governance bundle frozen" is FALSE; rotation EXPECTED every deploy. **To detect REAL FE change, diff `fe-*/src` in commit/range, NOT hash delta.**
- **⚠ SPA-fallback 200 trap (S72):** server rewrites `/*``/index.html` so GET `/assets/index-<ANYTHING>.js` returns **200** even for fake hash (control `ZZdoesnotexist0.js`200, size~919b text/html). Old-hash-still-200 MEANINGLESS. RELIABLE signal = parse index.html `<script src>`, GET that exact path + check `size_download` LARGE (real ~1.6MB vs fake ~919b) + `Last-Modified` in deploy window + 2nd-fetch byte-stable (no mid-deploy transient).
- **🟢 #69-REFINE (S83 Run #333) hash can stay IDENTICAL across deploy when fe-*/src 0-change.** #69 said "rotates EVERY deploy" NOT absolute. Run #333 (BE+tests+governance, ZERO `fe-*/src` diff) shipped FE (Last-Modified 17:10:35/17:11:27 BOTH in run-window 17:0617:11) but hash UNCHANGED (admin `CsJetgZH`/user `BVS0ApIm` = #330 baseline). identical Vite source byte-identical output same content-hash. Rolldown chunk-id apparently MORE deterministic than #69 feared (or only rotates on real src delta). **MOST RELIABLE ship-proof = `Last-Modified` header on the real bundle file IN deploy-window, NOT hash-delta** (hash-delta has false-NEGATIVE when src unchanged + false-POSITIVE risk noted in #69). Always cross-ref `git diff fe-*/src` scope: 0-FE-change expect SAME hash + fresh Last-Modified.
- **Migration drift prod vs repo** compare `ls .../Persistence/Migrations/*.cs` vs `sqlcmd __EFMigrationsHistory`. Fix: check `Program.cs`/DbInitializer `app.MigrateDatabase()` + app pool recycle. Mig-applied proof = `__EFMigrationsHistory` top==repo-HEAD; stuck-old pool didn't recycle FAIL even if status=success+bundle-rotated.
---
## 📋 5-stage checklist (EVERY run)
- **Stage 0 RAG infra:** `Get-Service Qdrant` Running + `http://localhost:6333/healthz`. Collection `proj_solution_erp`.
- **Stage 1 Push+filter:** `git log -1 --format='%H %s'` + `git log origin/main..HEAD` empty + diff vs paths-ignore (docs-only SKIPPED-DOCS return).
- **Stage 2 Gitea poll** (max 10 iter × 60s): API `.../actions/tasks?limit=5` (NOT `/runs` 404). Match `head_sha` (NOT run_number cancelled runs shift numbering). `updated_at` stale ~2min (gotcha #46) cross-check VPS mtime. Foreground-sleep BLOCKED Windows Monitor-style busy-wait-curl-spin ~30s/iter.
- **Stage 3 Test gate:** baseline **440 PASS** (45 Domain + 395 Infra; S96 #480 `0c2f9f6` 436 + new `PeSuggestedPriceSetterAuthzTests` [price-lock-after-submit authz]; prior S96 #479 436, S96/S95 434, S90 #465 421). CI runs both proj BEFORE build/deploy status=success test gate passed (`tasks` terminal=`status:success`, `conclusion` NOT populated trust success NOT log-numeric). Local grep undercounts (Theory/InlineData). Phase 9 UAT skip OK.
- **Stage 4 Post-deploy** (if SUCCESS): auth login bearer (admin + nv.test gotcha #44; token=`accessToken` route `/api/auth/login`) 3-5 endpoint smoke 2XX (incl new NEW-endpoint bodyless-POST returns **411 IIS Length-Required pre-auth NOT 404**; re-probe WITH body 401 confirms wired) FE bundle hash 2 app (per #69 = real-size-vs-fake not hash-delta) SignalR negotiate (gotcha #25) EF mig prod==repo.
- **Stage 4.6 (S29 CRITICAL):** sqlcmd seed sample verify post-deploy (NOT chỉ schema). Seed=runtime-row-insert (no history/tables advance) verify via DB-query (e.g. Permissions count), NOT bundle-frozen-alone.
- Discovery: ASP.NET 10 record enum needs numeric input unless `JsonStringEnumConverter` (SOL has NO converter FE sends numeric). sqlcmd ssh Windows-auth `\\\\SQLEXPRESS` 4-backslash. INFRASTRUCTURE seed MUST run (NOT inside `if(!demoSeedDisabled)`); DEMO seed gated gotcha #51.
- **Stage 5 Report** PASS/FAIL + evidence + MEMORY update.
---
## ⚠️ Anti-patterns (DO NOT)
1. Push fix code READ only, escalate em main · 2. Speculate fail without log · 3. Skip post-deploy bundle hash (biggest catch) · 4. Skip MEMORY · 5. Poll forever (max 10 iter) · 6. Auto-rollback (escalate + recommend) · 7. Verify docs-only (SKIPPED-DOCS return ngay)
---
## 🧠 SOLUTION_ERP CI/CD essentials (S80 verified — re-ground từ docs/STATUS.md canonical)
- **Gitea:** `git.baocaogiaoduc.vn/vietreport-admin/solution-erp` · workflow `.gitea/workflows/deploy.yml` · paths-ignore `['docs/**','**/*.md','.claude/skills/**']`. Anon API works (public repo) when GITEA_TOKEN absent.
- **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 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)
Node CI `20.x` (`feedback_node_cicd`) · MediatR `12.4.1` (gotcha #1, flag `Version="14`) · Swashbuckle `6.9.0` (gotcha #2) · act_runner manual checkout (#39) · npm cache DISABLED (#40, flag `cache: npm`)
---
## 🎯 Per-NV admin opt-in wire — 10-point checklist (cumulative S22→S23)
Cross-ref `feedback_per_nv_permission_scope`. Per-NV/per-Level refactor MUST verify: 1 Domain field · 2 EF `HasDefaultValue(false)` · 3 Mig 3-file · 4 Service read · 5 Domain+App DTO mirror · 6 Designer FE checkbox · 7 AwLevelDto+ToDto · 8 CreateAwLevelInput+Update mutation · 9 **Lookup discrimination** (`FirstOrDefault` ADD `ApproverUserId==actorId` + admin fallback) · 10 **Controller body record count == Command record count**. Bug latency 2-3 days prod silent khi miss 9-10. Scan `grep -n "FirstOrDefault.*Order.*==" *.cs` after OR-of-N refactor.
## 📊 Run stats baseline
BE (test+build) ~90s · FE × 2 ~60s/app · deploy ~30s · **total ~3min code / 0s docs-only**. >5min → escalate. Recent runs all ~4m40-5m.
---
## 📅 Recent runs (compressed — full verbatim → `archive/2026-06.md` via `archive/_INDEX.md`)
- **🟢 S97-badge #483 (id=483, run_number 369) `9e12e80` GO ~5m13s (PASS) — FE-ONLY 8-file badge "✅ Đã được CEO duyệt" cho phiếu đi HẾT lên CEO (endsBeforeCeo=false), anh Kiệt FDC UAT.** Follow-up to #482 endsBeforeCeo runtime. 8 files ALL `fe-*/src`: `PeFinalizeChip.tsx`+`PeListPanel.tsx` 2-app + admin ListPage + user Inbox/Dashboard/ListPage. NO BE/Mig/test. Poll running→success 20:52:23→20:57:36 (~5m13s in-baseline). status=success ⟹ test-gate green (baseline **440** unchanged). 🎯 **FE JS ROTATED both apps**: admin `DR9q2VUy`→**`CeTA7Z82`** + user `Bgz8u4E5`→**`CGaAyXen`** (6 call-sites 2-app real diff) · **CSS FROZEN** Bbtesa6B/BmuPz_Dy (JSX-logic-only ⟹ #69-REFINE). Real-size admin 1,637,119 / user 1,543,467B `application/javascript` (SPA-trap control fake-hash→919B text/html) · Last-Modified admin 13:56:13GMT / user 13:57:09GMT =20:56/20:57+07 IN-WINDOW. 🔴 **BYTE-LEVEL grep #77 BOTH bundles**: new string `Đã được CEO duyệt` PRESENT count=1 admin AND user (matches source `PeFinalizeChip.tsx:26`) · prev-badge `Kết thúc tại` (S97 #481) still-present ⟹ additive no-regression ⟹ badge SHIPPED. 🔴 **Mig UNCHANGED (FE-only)**: history-top==`AddPeEndedByLevelFinalize`(Mig 60) NOT-advanced · sys.tables=88-excl-history [=89-incl; note: my SQL excluded `__EFMigrationsHistory` → count 88, memory-baseline 89 counts it; stable no-schema-change either frame]. Smoke: admin-root/eoffice-root 200, auth accessToken 468ch, `GET /api/purchase-evaluations` **200** items=9 (new FE prop did NOT break list serialization), api ready/live 200. 🔑 **FE-ONLY PASS = CI-success + JS-rotate-BOTH/CSS-frozen(#69) + real-size-vs-919b + LastMod-in-window + byte-grep-new-PRESENT-both(#77) + prev-badge-still-present(additive) + Mig-top-frozen + smoke-200 + PE-list-200-not-500**. ⚠️ tooling: busy-wait-spin ~5-15s/iter TOO-SLOW (poll timed-out mid-run twice) → run finished ~5m, single long-loop w/ 40×favicon-curl spacing worked; #69 hash-rotate held (real 2-app src diff).
- **🟢 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`.
---
## 🔄 Curate trigger
- >~30KB → archive recent runs → L2 `archive/<period>.md` (byte-exact append) + `_INDEX.md` substring pointer. Dup failure patterns → merge. Stale >3mo → remove.
- **Last curate: 2026-06-20 S80 (em-main, archive-gate keep-floor-hit → manual)** (38.8→~16KB): moved 3 huge run-entries #330/#318/#325 (lines 73/90/96 byte-exact via `sed`) → `archive/2026-06.md` (100.6→116.7KB) + `_INDEX.md` +3 substring pointers (verified count=1). KEPT foundation (bug-patterns/5-stage/10-point gold) + compressed essentials + run-stubs; UPDATED stale (130→354 test Stage-3 + 263→354 essentials, Mig 55→57, bundle→#330) + dropped verbose per-run bundle-history (S86/S85/S84 → archived run-entries).
- **Prev curate: 2026-06-17 S70 Harness-9** (65.2→23.2KB dark-matter recovery, built _INDEX/gist gen:1). Earlier: S66 · S40.