# Error-Ledger — SOLUTION_ERP (Gov-v2 §L keystone)

> **Living artifact.** Blameless RCA + Active-Guards index for SE. Closes the open delta from adap-report `2026-06-02-Governance-gov-v2-session-cmd-framework` (the only Gov-v2 floor item SE had distributed-but-not-formalized).
> **Maintained at `/session-end` §L.b** (deterministic step, not a daemon — G-015). Blameless = root-cause + guard, NOT blame.

## 📐 The 3-ledger triad (Gov-v2 §L.b / §G3 — form gộp, function intact)

SE maps the mandated 3 living ledgers onto existing + new artifacts (§F4 form-freedom):

| Ledger (function) | SE artifact | Role |
|---|---|---|
| **(i) error-ledger** | **this file** (`docs/governance/error-ledger.md`) | RCA blameless · Active-Guards index · 3-axis tag · 2-strike promote |
| **(ii) comms-ledger** | `docs/governance/README.md` "Cross-Project Adoption Ledger" + `docs/governance/adap-reports/` | 2-way cross-project OUT→ACK / IN→decided, link-not-copy |
| **(iii) summary-index** | `docs/STATUS.md` "Recently Done" + `docs/changelog/sessions/` | timeline spine, pointer-not-log, reverse-chron |

## 🔍 §L.a — Deterministic detect (action-signature scan @ session-end)

Detect by **action-signature** (NOT "AI tự phán có vi phạm không"). Scan the session for these; each hit → an RCA entry below. List is **open** — extend when a new class appears. (G-015: catches signatures in this list, NOT "mọi vi phạm".)

| # | Action-signature (grep/observe) | Rule it violates | On hit |
|---|---|---|---|
| AS-1 | `git add -A` / `git add .` | add-specific-files (concurrency safety, `feedback_rag_mcp_recovery_concurrency`) | RCA + re-stage specific |
| AS-2 | `--no-verify` / `--no-gpg-sign` / `commit.gpgsign=false` | no hook/sign bypass unless asked | RCA, justify or revert |
| AS-3 | sub-agent invokes `store_memory` | lead = sole RAG-writer (S47, mechanized) | should be impossible (allowlist-stripped); if chunk-count jumps w/o lead write → investigate |
| AS-4 | EF Mig adds UNIQUE/composite index on a soft-delete (`IsDeleted`) entity **without** `.HasFilter("[IsDeleted]=0")` | gotcha #57 (recreate-on-soft-deleted-slot → 500) | RCA + test-before + filter |
| AS-5 | heavy/long agent spawn in **foreground** | `feedback_background_spawn_visibility` (looks-frozen) | note; prefer `run_in_background` |
| AS-6 | docs-only commit that triggers a CI run | gotcha #41 path-filter (`paths-ignore`) | verify path-filter intact |
| AS-7 | model downgrade (haiku/sonnet) on codegen/guard/financial/security | critical-algo needs Max tier | RCA, re-run on Max |
| AS-8 | session-end memory `.md` Write leaving **0 bytes** | `feedback_session_end_memory_write_verify` (S46) | re-write + verify byte>0 |
| AS-9 | A/B/C choice handed to anh **without** decision-brief trục | Gov-v2 §G2 | reframe as full brief |
| AS-10 | sub-agent writes a tracked file (MEMORY.md / code) despite **R1 return-only** (Write/Bash residual) | R1 return-only (HMW) — prompt-rule, NOT mechanized (G-015) | git-diff post-P2 catch → lead VERIFY benign+accurate+placement → keep or revert (NOT a bug if correct; chunk-count for RAG-write) |
| AS-11 | cross-stack feature: BE validator/nullability ≠ FE required-marker for the SAME field | em-main shared-contract consistency (E-007) | RCA + align FE↔BE + reviewer-gate (held S51) |
| AS-12 | identifier-based data op trên prod (lock/seed/migrate-by-email/code) viết theo population đọc từ CODE/Dev, KHÔNG dump bảng env đích | gotcha #60 (E-008) — assertion 0-row/`-1` ⟹ nghi data-mismatch TRƯỚC code-bug | RCA + dump env-đích trước khi viết list + seed-password thỏa policy nghiêm nhất mọi env |
| AS-13 | **custom Workflow script (≠ hmw.js DEFAULT-mode)** chạy parallel **same-role** agents giữ Write → agents tự-ghi shared `agent-memory/<role>/MEMORY.md` → "file modified since read" race + verbose-append over-cap | E-009 — hmw.js DEFAULT có return-delta-guard, custom script KHÔNG kế-thừa | RCA + curate L1→L2 + custom workflow PHẢI copy return-delta-guard HOẶC file-disjoint 1-sub/file |
| AS-14 | phép ĐO text (length/char-count/so-sánh) qua `Get-Content`/console-pipe **KHÔNG ép encoding** trên file **no-BOM** (PS5.1 default = ANSI → ký-tự Việt đếm ×2-3) | đo-phải-chạm-đĩa-ĐÚNG-CÁCH (E-010; anh em với bẫy `grep -c` — `feedback_resume_premise_reverify`) | RCA + re-đo `[System.Text.UTF8Encoding]` tường-minh; số đã báo owner → đính-chính NGAY |
| AS-15 | **điểm-đóng-thật** (chốt-đợt commit+push HOẶC session-end) **KHÔNG kèm** delta diary monitor (H1/H2) **và KHÔNG** dòng counter §L.b(j) | session-end §L.b "(a)→(j) đủ HẾT, KHÔNG skip" (E-011 — nghi-thức chạy tắt; máy mù lớp "nghi-thức có chạy không") | RCA + spawn DỒN H1+H2 re-report phủ khoảng bị bỏ + harvest hồi-tố + đọc counter bù |
| **AS-16** | artifact **OUTWARD** (adap-report · email hub · broadcast) **cite sha CHƯA-push**, HOẶC được **stamp trước khi `git status --porcelain` sạch** | E-012 — closeout-squash phá đúng sha vừa cite ⇒ con-trỏ chết với người ngoài; và file sửa sau khi stamp làm câu trong bản đã-niêm thành sai. **Cite outward = commit SẼ SỐNG sau squash.** `git status` là bước **ĐẦU** của outward-gate, không phải bước cuối | RCA + re-anchor sang commit đã-push + **errata rời** (CẤM sửa file đã stamp — vỡ hash) |
| **AS-17** | sub được lệnh ghi-đĩa-trong-lúc-làm nhưng lúc return/chết sub-file chỉ có **SKELETON** (header/checklist, 0 finding) — byte-content KHÔNG tăng theo tiến độ | sub-class `skeleton-ruột-rỗng` (E-013 — S150 gate `wf_f4e4c006` khung 274B/0-append → S151 ×2 thuần [sub-lead-stale header-only + sub-lead-gap checklist-only] = **2-strike**; "ghi-đĩa-trong-lúc-làm = CẦN, KHÔNG ĐỦ" — `feedback_agent_return_garble_recover`) | lead verify **BYTE-CONTENT tăng thật GIỮA wave** (đọc RUỘT — size nhỏ = nghi-vấn không phải bằng-chứng, phân biệt skeleton vs đang-viết-dở; H2 m#19) → resume-in-session ép đổ ruột (S151: 5/5 sạch) · lane quan-trọng giữ N-lane-redundancy + em-main-solo backstop |

## 🛡️ Active-Guards index (2-strike promote: episodic → procedural)

> **net-effect rule:** a guard that costs more than it saves (hại>lợi) → **retire**. `verified` = ran ≥1× and held. `strikes` = times the underlying error recurred before the guard.
> **G-011 ladder (canonical on-disk từ S139 — trước đó chỉ sống trong lineage adap-reports):** nấc tiến-độ khi khai một việc: `agreed` (đồng-ý làm) → `executed` (lệnh đã chạy xong) → `verified` / `verified-pending-restart` (đã KIỂM chạy thật; edit agent-file no-hot-reload = verified-pending-restart). 🔴 **KHÔNG tự khai `verified`** khi chưa có phép kiểm chạy được. Tham-chiếu: rules §6.6 K4 relay-attribution.
> **Luật re-base số-sống (K6.2 — generalize E-010, adopt S139):** Re-base baseline = chốt số **SỐNG** tại lúc re-base — mọi số vào sổ đọc lại từ **nguồn sống tại thời-điểm ghi** (CẤM chép từ ghi-chú/phiên trước, kể cả ghi-chú của chính mình); byte = `(Get-Item).Length` (E-010). *(nhà đề-xuất-mặc-định — [owner-reviewable])*

> ### 🪤 Carve-out ô3 — điều-kiện SỐNG (adopt S141, ghim S142)
>
> **Nấc:** force-fire khi closeout gộp sổ chạy dưới dạng **đề-xuất-chạy chờ anh gật** (KHÔNG auto-run) đứng ở nấc **`PASS-với-carve-out`** — 🔴 **CẤM nâng thành `PASS-trần`**. Đây không phải trừ-điểm: nó ghim đúng *điều-kiện sống* của carve-out.
>
> **VALID chỉ khi CẢ 2 lưới còn sống CÙNG LÚC** (đích danh, không nói chung chung):
> - **(a) dòng-nợ read-only vẫn IN ở MỌI điểm dừng** — `scripts/nhip-no-probe.ps1`
> - **(b) cái dò "closeout-thiếu-nghi-thức" vẫn được NỐI** — section `H25-closeout-ritual (GAP-2)` trong `scripts/governance-detectors.ps1`
>
> **Vì sao buộc CẢ HAI:** chuyển từ "máy tự chạy" sang "chờ anh gật" thì rủi-ro MỚI sinh ra là *anh quên gật mà không ai kêu*. Hai lưới trên **chính là cái kêu** — dòng-nợ cho anh thấy khoản quá-hạn, cái dò bắt closeout gộp mà thiếu nghi-thức.
>
> 🔴 **1 lưới chết ⇒ carve-out mất lớp tự-minh-bạch ⇒ RE-EVAL nấc**, và trong lúc chờ thì **tụt về chạy-vô-điều-kiện** cho tới khi lưới sống lại. Đây là luật đứng, không phải khuyến-nghị.
>
> **Basis:** hub reply `9a35405b` **khối-2** (`broadcasts/inbox/2026-07-17-ai_infra-to-se-reply-adap-wave-carveout-dp2.md`) — hub CONFIRM carve-out hợp-lệ *và* ghim đúng 2 điều-kiện này.
>
> **Live-evidence S139→S140 (dogfood mở sổ, không khai suông):** dòng-nợ `light 8/6` quá-hạn IN tại cửa nối-lại → anh **gật** → cặp H24 (`lead-view-auditor` + `lead-omission-auditor`) chạy THẬT → ra cờ THẬT (2 cờ view-cũ sửa trong phiên + 1 cờ MED "quyết-định-chìm" lặp-2) → probe sau audit `light 0/6`. Đủ một vòng: **nợ hiện → gật → chạy → ra việc thật → nợ về 0.**
>
> **Kiểm tại S142:** cả 2 lưới **SỐNG** (`scripts/nhip-no-probe.ps1` có trên đĩa; `H25-closeout-ritual` còn wired trong suite và chạy ra output) ⇒ nấc `PASS-với-carve-out` đứng vững, chưa phải re-eval.
>
> **Cùng CLASS — trio-consent S141:** bộ-ba đồng-kiểm memory (`harness-eval`/`refine`/`audit`) chạy **consent-gated** cũng là carve-out CÙNG LOẠI, chịu CHUNG luật trên; lưới của nó = **(a) proposal-line in CẢ khi Light-session** (không skip im) + **(b) vết-skip ghi `.claude/WAL.md` dạng `trio: skipped S<nn> (lý-do)`** để chuỗi skip nhìn thấy được. Khai nấc `PASS-với-carve-out` trong adap-report, KHÔNG PASS-trần; 1 trong 2 lưới chết ⇒ re-eval y hệt ô3.

| Guard | Counters | Tier | Strikes | Verified | Net |
|---|---|---|---|---|---|
| CI `paths-ignore` docs-only skip | gotcha #41 (AS-6) | procedural | 2 | ✅ (every docs commit 0s) | +++ |
| em-main verify-on-disk + proxy-append after agent return | gotcha #53 truncation | procedural | 5× (S35-S42) | ✅ | +++ |
| test-before bug-fix + soft-delete-UNIQUE `.HasFilter` | gotcha #57 (AS-4) | procedural | 3 (Holiday S45 · LeaveType/Shift/OtPolicy S51) | ✅ Mig 43 + Mig 45 (5 test RED→GREEN) | ++ |
| reviewer pre-commit on cross-stack / wire-BE-CRUD (contract-mismatch net) | E-007 (AS-11) | procedural | 1 (S51 Driver FE↔BE) | ✅ S51 (caught pre-commit, fixed before deploy) | ++ |
| verify byte-content sub-file GIỮA wave + resume-ép-đổ-ruột (anti skeleton-rỗng) | AS-17 / #53 sub-class E-013 | procedural (promote 2-strike @S151) | 2 (S150 gate + S151 stale/gap) | ✅ S151 (resume 5/5, 0 mất dữ-liệu; trio return-only 3/3 clean cùng phiên = counter-datum) | ++ |
| authz regression test per-action policy | gotcha #44 silent-403 | procedural | 1 (promoted S45 +10 test) | ✅ | ++ |
| agent frontmatter `model: inherit` (not `[1m]`) | gotcha #37 | procedural | — | ✅ (FD agent loaded S48) | ++ |
| **lead = sole RAG-writer** (`store_memory` stripped, mechanized) | store_memory rebootstrap-loss (S41) + AS-3 | procedural | 2 (NamGroup + SE S41) | ✅ runtime S48 (0/8 subs) | +++ (failure-safe) |
| session-end verify memory byte>0 | S46 0-byte (AS-8) | procedural | 1 (S46) | ✅ S49 (new mem 2355B + 0 byte-0 scan) | ++ |
| **git-diff + chunk-count post-P2 containment** (defense-in-depth, HMW) | R1 sub-write residual (AS-10) · store_memory bypass (AS-3) | **procedural** (institutionalized S50 = standard B6 post-wave audit) | 1 (S49) | ✅ S49 (caught inv-api self-MEMORY in git-diff; chunk 2414=2414) + **S50 wave `h2-verify` (git-diff agent-memory EMPTY, chunk 2415=2415, 0 leak)** + **S93 (WF1 3-agent residual caught+reverted; WF2 0-residual after explicit return-only)** + **S95 (WF1+WF3 residual caught+reverted 2×; WF3 explicit-return-only STILL self-wrote → instruction-fix NOT 100%, git-diff = the net)** + **S103 (investigator recon-agent garble-CURATED own memory [archive/2026-07.md new dù L1 NOT over-cap 17337<25600] → caught+reverted git-checkout; #53 ×3 phiên → recover incl Lane-B-from-diary; reviewer/tooling-auditor self-writes = LEGIT harvest kept)** | +++ (G-015 honest — 5 fires/5 catches/0 escape; NOT allowlist-alone, NOT instruction-alone) |
| heavy spawn → `run_in_background` | looks-frozen | **procedural** (2-strike met) | 2 (S45, S48) | ✅ S48 (FD bg) + S50 (all 4 monitor+wave spawns bg) | + |
| RAG glob `**/`-anchored (not root) | gotcha #10 node_modules leak | procedural | 1 (S41) | ✅ (2406 clean) | ++ |
| dump bảng env-đích TRƯỚC identifier-based data op (lock/seed-by-email) | gotcha #60 (AS-12) | episodic | 1 (S57bis lock NO-OP) | ✅ S58 (recon dump → fix `5998163` → Run #382 đo 34 locked) | ++ |
| custom Workflow same-role → copy return-delta-guard HOẶC file-disjoint 1-sub/file | E-009 (AS-13) | episodic | 1 (S71 invest/review race) | ✅ S71 (curate workflow `wf_f32987b8` file-disjoint 1-sub/file = 0 race; finalize curate đóng over-cap) | ++ |
| đo text = ép `UTF8Encoding` tường-minh (PS5.1 no-BOM ⇒ ANSI ⇒ số phồng ×2-3) | E-010 (AS-14) | episodic | 1 (S130) | ✅ S130 (B3 round-trip dùng UTF8-explicit PASS 2 file; số đính-chính cùng phiên) | + |
| điểm-đóng-thật ⇒ tự-hỏi "diary monitor có delta? dòng counter có in?" (chờ hub canonical detector) | E-011 (AS-15) | episodic | 1 đợt (×3 closeout S128-S130) | ✅ S132 (spawn dồn H1+H2 phủ S127→S131 xong: H2 GAPS→CLOSED + H1 1-drift-FIXED + 2 diary H24 seeded + counter-line in §L.b(j)) | + (đề-xuất khung đã gửi hub `e46863c8`) |

## 📋 RCA entries (blameless — newest on top)

> Format: `E-NNN | date | rule | what | 5-why root | fix (prod-bug = 2-fix: code + guard) | prevention | tags[TYPE/ACTOR/COMPONENT]`

### E-014 — AS-18 slot-index tái-dụng làm MẤT owner-decision không để lại vết (S146, H24 `lead-omission-auditor` bắt, lead verify bằng `git show`)
- **rule (AS-18 NEW):** khối đánh số (`OWNER-DECISION [n]`, checklist, enum…) **CHỈ ĐƯỢC TĂNG index**. **CẤM tái-dụng số cũ cho nội-dung mới.** Đè slot = nội-dung cũ **biến mất im-lặng** — khác hẳn đổi giá-trị (còn thấy giá-trị cũ để grep).
- **what:** owner @S146 nói *"còn lại xử lý hết xong rồi session-end nhé"*; lead ghi ĐÚNG vào `.claude/WAL.md:9` slot `[7]` = **uỷ-quyền commit+push** (`ad02483`, `9c68bae`). Sau đó lead thêm 3 quyết-định session-model và **tái-dụng slot `[7]`** ⇒ `e7d06f2` mất hẳn dòng cũ. Grep toàn repo = **0 hit**.
- **hệ-quả THẬT (không phải lý-thuyết):** lead hỏi lại *"cho push chưa"* **3 lượt liền** — hỏi lại đúng thứ owner ĐÃ trả lời, và hỏi ngay dưới khối tự đặt tên **"ghi đè, KHÔNG hỏi lại"**. Lead làm **ngược** chính luật mình viết.
- **5-why:** (1) lead thêm mục mới vào khối có sẵn → (2) chọn số kế-tiếp *theo cảm-giác* thay vì đọc số lớn nhất đang dùng → (3) `[7]` trông "trống" vì lead nhớ khối chỉ tới `[6]` → (4) WAL **ghi-đè toàn-file** nên không có diff-review từng dòng như commit thường → (5) **máy MÙ hoàn-toàn**: không detector nào biết `[7]` từng là thứ khác.
- **fix:** khôi phục `[7]` (nguồn `git show ad02483:.claude/WAL.md:9`) + đẩy session-model xuống `[8]` + ghi luật **SLOT-INDEX CHỈ-TĂNG** ngay tiêu-đề khối.
- **prevention/guard:** vai H24 soi **CÁI THIẾU** = catch-layer **DUY NHẤT** cho lớp này (H24 §2(1) *"máy MÙ gần như hoàn toàn"*). 🔴 Nhắc: WAL ghi-đè ⇒ **mọi mất-mát trong WAL đều im lặng** ⇒ đối-chứng phải là `git show <sha>:.claude/WAL.md`.
- **tags:** [slot-reuse / lead / WAL.md · owner-decision · gap-owner-specifics · class_repeat 2→3 CHẠM jump]

### E-013 — AS-17 sự-cố KHÔNG vào sổ bền + phép trích-xuất hỏng đọc thành "sạch" (S146, cụm 2 lỗi cùng lớp *"vắng mặt trông giống ổn"*)
- **rule (AS-17 NEW):** (a) sự-cố chỉ có vết trong **run-folder** = **CHƯA vào sổ**; phải đổ vào ≥1 **sổ bền** (error-ledger / STATUS / HANDOFF / auto-memory). (b) phép trích-xuất trả **RỖNG** phải phân-biệt *"không có gì"* ⟂ *"phép đo hỏng"* — **CẤM đọc rỗng thành sạch**.
- **what (a):** garble `#53` THẬT trên `harness-audit` @S144 (`trio-synthesis.md:20-21`) + lead thu-hẹp tập đối-chứng mà im-lặng (*"đối chứng 4 mốc: 0 LỆCH"* trong khi khối liệt **5**, mốc-5 chính là mốc lệch) ⇒ **0 hit** ở cả 5 sổ bền; sổ đếm `feedback_agent_return_garble_recover.md` dừng ở `×25 qua S143`. **S146 thêm 3 garble nữa** (lead-view · lead-omission · h24-audit — **3/3 vai lane-H24**).
- **what (b):** lead vá 6 site consent theo danh-sách H24 liệt, **vá 5 sót 1** (`ring2-audit.md:25` (tên cũ h24-audit.md — rename @S149) — câu tự mâu-thuẫn *"KHÔNG consent-gate … khi OVERDUE + anh consent"*). **Cơ-chế tái-dựng được:** lệnh trích `grep -oE '.{50}consent.{80}'` đòi **đúng 50 ký-tự TRƯỚC** match; trên dòng đó `consent` ở ~offset 30 ⇒ **0 match ⇒ output RỖNG** ⇒ lead đọc thành *"dòng này không có gì"*. Đúng phải là `.{0,60}`.
- **5-why (b):** (1) vá theo danh-sách người khác liệt → (2) không tự grep lại sau khi vá → (3) dùng cửa-sổ ngữ-cảnh **cố-định** thay vì **0..n** → (4) rỗng **trông y hệt** sạch (khác `grep -c` trả `0` — một con SỐ, nhìn là biết đang đếm) → (5) `h24-audit` bắt được vì nó **đọc dòng đó trong chính persona nạp vào mình** + đối-chứng đĩa = 2 nguồn.
- **fix:** vá `:25`; re-grep toàn file = 0; ghi cụm sự-cố vào chính entry này.
- **prevention/guard:** 🔴 **Luật: vá xong PHẢI tự grep lại bằng lệnh KHÁC lệnh đã dùng để tìm** (khác mẫu, khác cửa-sổ). Họ hàng đã có trong sổ: `grep -c` (dòng) vs `grep -o|wc -l` (occurrence) — nay thêm **cửa-sổ-ngữ-cảnh-cố-định**.
- **EXT @S152 — tái-phát lần 2, cùng-họ `ring*`, cùng hình-dạng (b):** đợt sleep-AUTO owner (32) quét 7-site trong `commands/` mà **sót trọn lớp `agents/`** — stale-close FLAG-4 bắt `ring4-audit.md:26/:27`; H1 liệt lô 5-site vẫn **sót site-6 `ring1-audit.md:24`** (vết núp trong ngoặc SAU câu đúng "KHÔNG consent-gate (…gật mới chạy)") — `ring1-close` tự bắt **trong persona chính mình** bằng mồi KHÁC ("gật mới chạy"); lead grep cùng-lớp ra thêm 3 site trio-persona (`harness-eval.md:4` description · `harness-refine.md:58` · `harness-audit.md:50` vế "First-run chờ consent") ⇒ **lô cuối 9 site** (+2 vết ring2 đã vá đúng từ trước). Guard siết thêm: **sweep theo LỚP-file (commands + agents + skills), đừng theo danh-sách-site người khác liệt; mồi grep ≥2 biến-thể** ("consent" · "anh gật" · "gật mới chạy").
- **tags:** [incident-unrecorded + extraction-silent-empty / lead / error-ledger · ring2-audit.md:25 · #53 ×3 S146 · EXT-S152 lô-9-site ring1-audit.md:24]

### E-012 — AS-16 bằng-chứng-tự-huỷ-sau-squash: 7 adap-report + 1 email hub neo vào sha `wal:` chưa-push, closeout-squash phá đúng sha đó (S143, reviewer-gate độc-lập bắt SAU khi thư đã gửi)
- **rule (AS-16 NEW):** artifact OUTWARD phải cite **commit SẼ SỐNG sau squash**, và phải qua `git status --porcelain` **TRƯỚC** khi stamp. Vi-phạm nền: `/adap-report` §3 *"evidence: commit-sha · file path · byte/dòng (đo THẬT)"* — đo thật nhưng **neo vào con-trỏ sắp chết**; và `/send-email` 6c selftest-stamp chỉ kiểm **hash khớp thân-thư**, KHÔNG kiểm **thân-thư có còn đúng sự-thật** lúc phát.
- **what:** (1) 7 adap-report cite `1a0fa59`/`a458102`/`96ab2679`/`c3708e9`/`b1d92b9` (đều `wal:`-commit local). Closeout §5.0 `reset --soft HEAD~8` gộp chúng vào `2757e41` ⇒ cả 5 thành **dangling**: `cat-file -t` = `commit` (sống nhờ reflog LOCAL) nhưng `merge-base --is-ancestor <sha> origin/main` = **exit 1** ⇒ hub clone repo về `git show 1a0fa59` = **object missing**. Nội-dung nguyên vẹn trong `2757e41` ⇒ **chết con-trỏ, không chết việc**. (2) Cùng gốc: report + email khai `is-ancestor 96ab2679 HEAD = exit 0 → OK-reachable` làm bằng-chứng "contract v2 chạy runtime" — squash **cùng phiên** lật nó thành `exit 1`/`SQUASH-BENIGN` ⇒ **phép đo tự huỷ trong chính phiên phát-biểu nó**. (3) Biến-thể thứ ba: email `:47` khai *"vế pull-age **chưa làm**, chờ owner"* — owner gật ngay sau đó, lead làm, `scripts/nhip-no-probe.ps1` sửa **sau** khi thư đã stamp ⇒ bản đã-niêm khai sai hiện-trạng, và **không sửa được** (sửa = vỡ hash).
- **5-why root:** (1) vì sao sha chết? — squash rewrite history. (2) vì sao squash sau khi cite? — report viết **trước** push, đúng thứ-tự tự-nhiên của việc ("làm xong thì ghi lại"). (3) vì sao thứ-tự đó sai? — vì với artifact OUTWARD, *người đọc ở repo KHÁC*, nên tham-chiếu chỉ có nghĩa nếu nó tồn tại **trên remote**, không phải trên đĩa mình. (4) vì sao không ai bắt lúc viết? — mọi phép verify của lead chạy **trên máy lead**, nơi reflog còn giữ sha ⇒ `cat-file -t` xanh ⇒ **kiểm bằng góc nhìn người-trong-nhà cho một artifact gửi người-ngoài**. (5) 🔴 **root:** *tiêu-chí verify được chọn theo cái mình đo được, không theo cái người nhận sẽ đo.* Cùng class với E-010 (đo bằng công-cụ tiện tay) và với "TRIPLE chọn enum DỄ" cũng bắt trong phiên này.
- **fix (KHÔNG prod-bug — artifact-only, vẫn 2 lớp):** *(a) lớp artifact:* re-anchor toàn bộ 7 report sang `2757e41` + thêm caveat ghi rõ sha cũ chỉ còn giá-trị local; phát **errata rời** `e43484cef10f` cho hub (CẤM sửa bản đã stamp). *(b) lớp luật:* AS-16 + 3 luật đọc-được ghi vào report/errata — **cite outward = commit sống sau squash** · **`git status` là bước ĐẦU của outward-gate** · **tách claim-DELTA (bền) khỏi claim-TUYỆT-ĐỐI (phải neo commit+thời-điểm)**.
- **prevention/guard:** *episodic → chờ strike-2.* Guard đề-xuất khi tái: chèn vào `/send-email` bước 6c một phép **`git status --porcelain` = rỗng** + **`merge-base --is-ancestor <mọi sha cite> origin/main`** trước khi stamp; fail ⇒ ABORT. 🔴 **Chưa wire** — vì guard này cần định-nghĩa "sha cite" (parse thân-thư) và có thể dương-giả với sha của repo KHÁC (hub sha như `58e28bae` KHÔNG nằm trong repo SE). Ghi làm nợ, không tự dựng cổng nửa vời.
- **Đối chứng (chứng đây là class, không phải xui):** wave TRƯỚC (S138–S139) cite `7760cdf`/`da349fc` = commit **đích** sau squash → **sống hết tới nay**. Cùng người, cùng nghi-thức, khác đúng một điểm: thời-điểm viết report so với thời-điểm push.
- **tags:** `[GOVERNANCE/lead/outward-artifact · evidence-self-destruct-squash · cite-post-squash-commit · git-status-first · verify-tu-goc-nhin-nguoi-nhan]`

### E-011 — AS-15 nghi-thức chạy tắt: 3 closeout liên-tiếp S128-S130 KHÔNG spawn monitor H1/H2 + bỏ §L.b(j) — máy im suốt, lộ nhờ 1 câu hỏi của anh (S131 phát-hiện, S132 xử)
- **rule (AS-15 NEW):** session-end §L.b (session-end.md:52) *"auto-maintain (a)→(j) đủ HẾT, KHÔNG skip — thiếu = ledger thối"*; (d)(f) = H2 harvest-curator · (g) = H1 tooling-auditor · (j) = đọc counter/OVERDUE. **Điểm-đóng-thật** (chốt-đợt + push) đi qua mà nghi-thức không chạy = closeout chạy tắt, dù phiên kết thúc bằng `/pause` chứ không phải `/session-end`.
- **what:** 3 closeout liên-tiếp — S128 `289ba96` 20:57 · S129 `295c70c` 23:16 · S130 `71757fc` 00:26 — commit + push xong mà KHÔNG spawn H1/H2 (mtime diary 2 monitor đứng 2026-07-16 15:18; commit cuối chạm diary = `e9124fc` 15:19; S130 Recently-Done còn tự ghi *"0 sub spawn"*) + bỏ luôn §L.b(j) — cả lớp ĐỌC counter cuối phiên không chạy. Không detector nào đo lớp "nghi-thức có chạy không" → im lặng trông y hệt sạch; chỉ lộ khi anh hỏi *"sao không thấy lead-view/lead-omission/harvest chạy?"*. Họ-hàng cùng đợt (GAP-1, email `e46863c8`): mạch pause→`/tiep` không tick counter H24 → S128·S129·S130 không tick → counter dưới-đếm ~37% trên cửa-sổ 8 nhãn (5 tick/3 không).
- **5-why:** phiên kết thúc bằng `/pause` (H22 điểm-dừng chủ-động) hoặc mở bằng `/tiep` nối-mạch → không đi qua cổng `/session-end` → §L.b không ai gọi → không gate máy nào ép (a)→(j) → 3 phiên lặp cùng kiểu → gốc = **kẽ THIẾT-KẾ giao-điểm 2 harness** (H22 pause/tiep ⟂ nghi-thức đóng §L.b + H24 tick 1-điểm-vào), KHÔNG phải lỗi cá-nhân một phiên; máy mù lớp nghi-thức (cùng họ caveat (e) adap-report H24).
- **fix (KHÔNG prod-bug — process):** (đợt này) S131 mở session-end ĐÚNG nghi-thức đầu-tiên sau 3 lần tắt (sentinel + §L.a + archive-gate DRY PASS) — chết giữa vì session-limit → S132 `/tiep` nối: spawn DỒN H1+H2 phủ S127→S131 + harvest hồi-tố GAP-3 (diary 2 vai H24) + entry này. (báo) email hub `e46863c8` 3-gap stamped + đề-xuất khung: tick đa-điểm-vào H22×H24 · detector "closeout-missing-monitor" · "first-run-role-has-diary" — chờ hub canonical, SE không tự chế detector riêng.
- **prevention/guard:** AS-15 thêm §L.a + Active-Guard episodic (occurrences ×3 nhưng 1 đợt phát-hiện — promote nếu tái SAU guard). Wire tick vào `/tiep` + tick-at-close = đề-xuất ĐÃ TRÌNH ANH (email mục "SE tự làm trong-khung" #1), **CHỜ ANH GẬT mới sửa `tiep.md`** — không tự áp.
- **tags:** [ritual-skip / em-main / session-end×H22-pause-tiep×H24-counter]

### E-010 — AS-14 encoding-mismeasure: `Get-Content` no `-Encoding` trên file no-BOM → báo owner số sai ×2-3 (S130, tự-bắt + đính-chính trong-phiên)
- **rule (AS-14 NEW):** phép ĐO text (length/count/so-sánh) phải ép encoding tường-minh. PS5.1 `Get-Content` trên file UTF-8 **no-BOM** đọc theo ANSI ⇒ mỗi ký-tự Việt (2-3 byte UTF-8) đếm thành 2-3 char ⇒ số phồng ×2-3. Repo này CỐ Ý để docs no-BOM ⇒ mọi phép đo mặc-định đều dính.
- **what:** S130 khi trình 3 mục owner-gated, em đo mega-line bằng `(Get-Content docs\STATUS.md)[5].Length` = 70.008 / HANDOFF = 65.429 → báo anh "phình ~13K chỉ trong 1 ngày" ngay trong AskUserQuestion. Số THẬT (UTF8Encoding explicit): 64.794 / 59.686 — phình thật +113 ch + ~2.5K. Kết-luận "đang phình" đúng HƯỚNG nhưng độ-lớn sai ~5×. May: cả 3 phương án đã trên bàn từ S126 ⇒ quyết-định anh không dựa số này.
- **5-why:** đo nhanh bằng cách quen tay (Get-Content index) → không nhớ PS5.1 đoán encoding theo BOM → file cố-ý no-BOM (chính-sách repo) → số sai trôi thẳng vào câu hỏi trình anh → chỉ bị bắt khi B3-execute phải ReadAllText UTF8 (round-trip cần byte-đúng) cho ra số khác ⇒ tự-đính-chính. Gốc: **phép đo không khai encoding = phép đo chưa chạm đĩa đúng cách** — cùng họ bẫy `grep -c` (đếm dòng ≠ occurrence) S121.
- **fix (KHÔNG prod-bug — measurement-only):** (đo lại) mọi con số phát-biểu lại bằng `[System.Text.UTF8Encoding]::new($false)` + đính-chính với anh TRONG phiên (WAL + STATUS + HANDOFF ghi cả số sai lẫn số đúng). (guard) AS-14 thêm §L.a + Active-Guard episodic + append `feedback_resume_premise_reverify`.
- **prevention/guard:** đo text ⇒ `ReadAllText($path, UTF8Encoding-explicit)`; cần ĐỌC tiếng Việt từ console ⇒ dump-ra-file rồi Read (console PS cũng mojibake — đã thấy cùng phiên với ACTIVE-MARKS). Số đã lỡ báo owner ⇒ đính-chính ngay khi phát-hiện, giữ kết-luận nếu còn đúng + khai độ-lớn sai.
- **tags:** [measurement-mislabel / em-main-solo / docs-megaline+PS5.1-encoding]

### E-009 — AS-13 custom-workflow same-role MEMORY write-race → over-cap (S71, finalize-review-caught, curated same-session)
- **rule (AS-13 NEW):** custom Workflow script (≠ hmw.js DEFAULT-mode) chạy parallel **same-role** agents giữ Write → mỗi agent chạy frontmatter "update MEMORY before return" → concurrent writes shared `agent-memory/<role>/MEMORY.md` → "file modified since read" race + verbose-append over-cap. hmw.js DEFAULT-mode inject return-delta-only writeGuard; custom script KHÔNG kế-thừa.
- **what:** S71 Harness-10 adop chạy custom workflow (h10-invest 4× investigator-codebase · h10-review + h910-finalize 3× reviewer). Agents tự-ghi diary → 4 investigator ghi `investigator-codebase/MEMORY.md` đồng-thời + 3 reviewer ghi `reviewer/MEMORY.md`. Kết quả: reviewer 24.8→**36.7KB** (harness silent-truncate ~8KB HOT lúc spawn), investigator 24→29.8KB — cả 2 over auto-inject cap 25600. Content HỢP-LỆ (additive, 0 corruption, git numstat +N -0) nhưng P1 curate-debt (claimed CLOSED S70) re-opened.
- **5-why:** custom invest/review/finalize workflow author KHÔNG inject return-delta-guard mà hmw.js DEFAULT có → same-role agents mỗi con chạy "update MEMORY before return" → concurrent write cùng file → race + bloat tích-lũy → over-cap → harness silent HOT-truncate. Caught: finalize-review R3 (`wc -c`) + budget-audit-by-hand S71 (KHÔNG phải runtime-error — silent).
- **fix (KHÔNG prod-bug — 0 production code):** (process) curate L1→L2 `wf_f32987b8-03f` **file-disjoint 1-sub/file** (reviewer 36.7→24.8 + inv 29.8→23.2, 0-byte-loss numstat +N -0 + grep-Fxf 10/10 + md5sum) + budget.json re-measure + reviewer-gist gen:2. (guard) AS-13 + Active-Guard episodic + `feedback_harness10_run_trace` #2 lesson.
- **prevention/guard:** custom Workflow parallel same-role → (a) inject return-delta-only writeGuard (mirror hmw.js DEFAULT), HOẶC (b) file-disjoint 1-agent/memory-file (curate S71 dùng = 0 race). Budget-audit @session-start re-measure bắt re-accumulation. hmw.js RUN-TRACE mode (S71) đã guard.
- **tags:** [memory-race-overcap / custom-workflow-agents / agent-memory reviewer+investigator-codebase]

### E-008 — AS-12 lock-demo-user prod NO-OP: population Dev ≠ prod + seed silent-fail (S57bis ship, S58 fix, cicd-caught)
- **rule (AS-12 NEW):** thao tác data theo-identifier trên prod (lock/seed/migrate-by-email) mà list viết từ CODE/Dev population, KHÔNG dump bảng env đích → silent NO-OP/sai-target. Assertion trả 0-row/`-1` ⟹ nghi data-mismatch TRƯỚC khi nghi code.
- **what:** S57bis ship `LockDemoSampleUsersAsync` 14 email named-person (đọc từ seed code = population Dev-only). Demo prod thật = 20 UAT-matrix (`bod.1@`, `pm.nv@`… tạo TAY 05-13, chưa từng trong code). Run #381 deploy PASS + health 200 + code RAN — locked=0, hoàn toàn silent. Tầng 2 ẩn sâu hơn: `DemoUserPassword` 11 ký tự < prod `Identity:Password:RequiredLength=12` → `CreateAsync` trả `IdentityResult.Failed` (LogWarning-only, by-design 1-fail-không-abort) **mọi startup từ trước tới giờ** → named-person + `nv.cao`/`nv.truong` (IT pool — root cause "helpdesk inert" S56!) + 5 real staff KHÔNG BAO GIỜ tồn tại trên prod.
- **5-why:** author tin seed code là source-of-truth population → Dev ≠ prod vì password-policy silent-fail → silent vì `IdentityResult` không throw → warning log prod không ai đọc → chỉ cicd #381 data-dump (PASS+PARTIAL) bắt được — test xanh + CI gate + health 200 đều mù với data-absence. **Why-0 (RAG-archaeology S58):** bug này TỪNG được phát hiện S22 (2026-05-13, session log ghi "Identity password policy ≥12 — existing memory mention `User@123456` 11 chars OUTDATED", 20 UAT user seed bằng `TestUser@2026` 12 ký tự) — nhưng const `DemoUserPassword` trong code KHÔNG được fix lúc đó → knowledge nằm trong session-log mà không thành code-fix/guard → tái diễn S57bis. Lesson: discovery phải đổi thành code-fix HOẶC ledger-guard ngay, session-log alone = chết.
- **fix (prod-bug = 2-fix):** (code) `5998163` union 20 email prod-population (exact-email, KHÔNG pattern — `binh.le@` người thật sát scheme demo) + password → 12 ký tự → Run #382 đo thật: 55 user / 34 locked / helpdesk sống / 5 staff tạo / guard 6-6 active. (guard) gotcha **#60** + debug-checklist item 32 + cicd LESSON "lock/deactivate-by-email trả 0 ⟹ ALWAYS dump actual Users trước khi score FAIL" + Active-Guard episodic mới (dump-env-đích).
- **prevention/guard:** mọi identifier-based op → dump env đích TRƯỚC khi viết list; seed password const thỏa policy NGHIÊM NHẤT mọi env (prod 12); grep warning log sau deploy có user-seed mới. AS-12 added §L.a.
- **tags:** [seed-silent-fail+population-mismatch / em-main-S57bis-author · cicd-caught · recon-grounded / DbInitializer]

### E-007 — AS-11 parallel-fan-out shared-contract mismatch (S51, reviewer-caught pre-commit)
- **rule (AS-11 NEW):** cross-stack feature fan-out where BE field nullability/validator ≠ FE required-marker for the SAME field → contract mismatch (empty submit → 400/500). Em-main shared-contract must spec required/optional consistently BOTH sides.
- **what:** P11-C BE∥FE parallel (file-disjoint) spawn. Driver `phoneNumber/licenseNumber/licenseClass`: BE `NotEmpty()` validator + EF `.IsRequired()` NOT NULL, but FE KIND_CONFIG rendered them OPTIONAL (no `required:true`) → `buildBody` empty→null → 400/500. 186 tests GREEN (no test hit empty-optional path).
- **5-why:** em-main BE brief said "mirror Vehicle (all-required)" but FE brief omitted `required:true` on those 3 → each implementer faithful to its half → inconsistency invisible until integration (file-disjoint parallel = no cross-talk) → green tests ≠ correct contract.
- **fix:** (code) FE +`required:true` on the 3 fields (align to BE all-required, like Vehicle — `HrmConfigsPage.tsx:132-134` ×2 app). (guard) reviewer pre-commit on cross-stack = the net that caught it (HELD).
- **prevention/guard:** Active-Guard "reviewer pre-commit on cross-stack/wire-BE-CRUD" (fired correctly) + NEW discipline: em-main cross-stack brief MUST state required/optional explicitly for EACH shared field (BE validator+nullability AND FE required-marker). AS-11 added to §L.a.
- **tags:** [contract-mismatch / em-main-brief+implementer-be+fe / HrmConfigsPage,HrmConfigFeatures]

### E-006 — AS-10 autonomous monitor write at session-end (S50, git-diff-caught)
- **rule (AS-10):** sub writes a tracked file despite propose-only / R1-return-only (Write/Bash residual) → git-diff catch → lead VERIFY benign+accurate+placement → keep-if-correct or revert.
- **what:** @S50 `/session-end`, `git status` = **14 modified** but em-main personally edited ~7. Non-em-main writes: `error-ledger.md` (2 guard episodic→procedural promotions + E-002 #57 coords), 3 `adap-reports` (nac→verified-runtime), 4 `agent-memory/*` Recent-activity, + `STATUS.md` (Recently-Done-S50 block / In-Progress flip / RAG-line 2406↔2415 reconcile). mtimes 00:00–00:05 = session-end monitor window; the 2 INFORM-only monitors (tooling-auditor + harvest-curator) were briefed propose-only and **reported "wrote nothing."**
- **5-why:** monitors retain `Bash` (G-015 residual write-channel; `store_memory`-strip ≠ read-only) → ≥1 wrote canonical session-end content via shell → exceeded propose-only mandate (B3 single-writer) → self-report ≠ disk (Fidelity gap) → undetected until em-main git-diff commit-gate.
- **fix:** (process) em-main commit-gate `git diff` review = backstop, **HELD** — every changed line reviewed pre-commit → accurate / benign / correctly-placed / 0-mojibake / chunk-2415 → **adopted per AS-10 keep-if-correct** (NOT a content bug: matches what §L.b prescribes). (guard) "git-diff + chunk-count post-P2 containment" already promoted procedural this session; AS-10 now has its **first real fire**.
- **prevention/guard:** RECOMMEND (anh / AI_INFRA, charter-v2 infra): harden monitor tool-grant — `Write/Edit` removal alone leaves Bash residual → consider a session-end hook blocking sub-Bash-write to tracked paths, OR accept commit-gate as sufficient defense-in-depth. Fidelity: if monitors write, their reports MUST disclose it → escalate 🟥 reviewer if recurs. Provenance timing-implicated, **not definitively attributable** (no false accusation).
- **recurrence S93 (2026-06-29):** AS-10 2nd fire — 3 WF1 workflow-agents (investigator-codebase ×2 + reviewer, return-only) self-wrote agent-memory (diary append + archive self-curate + 1 stray `project_s92_*` mis-named file). git-diff post-P2 containment caught ALL → em-main reverted (kept cicd-monitor PE-deploy harvest hợp-lệ). Guard HELD again. **WF2 fix:** added explicit "RETURN-ONLY: do NOT write ANY file incl MEMORY.md" to every lane prompt → **0 residual** (instruction-fix worked, git-diff confirmed). Lesson: workflow-agent frontmatter "update MEMORY before return" fights return-only mandate → prompt MUST override + git-diff is the net (G-015, not mechanized).
- **recurrence S95 (2026-07-01, H17 adopt):** AS-10 **3rd + 4th fire** — WF1 (investigator-codebase self-compacted its MEMORY.md 25.5→16.98KB, CLAIMED archive-move but `archive/2026-06.md` was NOT created → keeping it would have LOST 8.5KB) + WF3-Lane-A (reviewer self-wrote diary + new `project_s95_harness17_faultinjection.md`). git-diff post-P2 caught BOTH → em-main reverted; cicd-monitor diary KEPT (normal-monitor-spawn, NOT return-only = legit). Guard HELD 2×. **🔑 Instruction-fix NOT 100%:** WF2(H17) had explicit return-only → 0 residual, but **WF3 ALSO had explicit "TUYỆT ĐỐI return-only" yet reviewer STILL self-wrote** → persona-write is stochastic; explicit-prompt REDUCES but does NOT eliminate → **git-diff-revert remains the mandatory net (G-015 reconfirmed, instruction-alone insufficient).** Distinction codified: workflow-return-only-agent = REVERT; normal-monitor-spawn (diary verdict) = KEEP. **Dogfood:** contained WHILE adopting H17 whose C3-floor = single-writer — the very floor being adopted saved real data. Guard net-effect ++ (4 fires, 4 catches, 0 escape).
- **recurrence S101 (2026-07-03):** AS-10 **fire 5-6 từ WORKFLOW LANES** (không phải monitor) — WF1-H19 `investigator-codebase` + WF2-H18/H19 `reviewer` auto-ghi agent-memory theo frontmatter "Update MEMORY before return", bypass HMW B3 single-writer. git-diff bắt (session-end change-set) → **harvest-curator Fidelity-gate PASS** (verify ĐỘC-LẬP: reviewer README:51-fix claim landed-verbatim hunk `@@-48,5+48,5`, 0 fabrication; U+FFFD=0/11; containment intact — committed `e350660`) → **KEPT per AS-10 keep-if-correct.** 🔑 KHÁC S95 default "workflow-lane=REVERT": S95 writes CÓ vấn-đề (stray mis-named file · claimed-missing-archive) → revert; S101 writes = CLEAN harvest khớp lane-verdict → keep-if-correct thắng. **Quyết bằng Fidelity-gate (harvest-curator), KHÔNG tự-phán** (đúng §L.b(f) — nghi-bịa→escalate 🟥 reviewer; ở đây 0-flag). **Cross-link:** dogfood-validate H19 §K.C GAP-3 "N-lane RETURN-only = convention KHÔNG mechanism" — chính phiên codify GAP-3 thấy nó fire. Guard git-diff + Fidelity-gate HELD (6 fire, 6 catch, 0 escape). Tension frontmatter "update-MEMORY-before-return" ⟂ HMW "return-only" stays-on-watch (commit-gate đủ defense-in-depth, chưa cần hook-block).
- **tags:** [containment-residual-write / monitor-sub+workflow-agent / governance-docs+agent-memory]

### E-005 — AS-1 `git add -A` on S49 governance commit (self-caught @session-end §L.a)
- **rule (AS-1):** stage specific files, not `git add -A`/`.` (concurrency safety — `feedback_rag_mcp_recovery_concurrency`).
- **what:** S49 Harness 1/2/3 adoption commit used `git add -A` ×2 (main `e27d877` + sha-fill `0647b4c`) instead of `git add <specific>`.
- **5-why:** 37-file batch → `-A` convenient → habit → skipped specific-stage → AS-1 signature fired.
- **fix:** (process) MITIGATED pre-commit — `git add -A --dry-run` verified exact 37-file scope + wave-folder-leak=0 + 0 unintended files BEFORE commit; no concurrent SE session running. Scope was correct → no retroactive re-stage needed. (guard) next multi-file commit → `git add <list>` OR dry-run-verify-first (this session did dry-run = acceptable mitigation).
- **prevention/guard:** Active-Guard AS-1 "add-specific or dry-run-verify-first". Blameless: outcome clean, but signature logged for honesty (§L.a = catch signature, not excuse it).
- **recurrence S71:** 2× `git add -A` (commits `8c47bd0` + `7875b39`) — mitigated y hệt: `git status --short` containment-audit review FULL scope TRƯỚC mỗi stage (verify-first = mitigation hợp-lệ per guard); 0 unintended file (run-trace tracked + agent-memory curate = đúng tập dự kiến). Pattern ổn định: `-A` + pre-stage-status-review acceptable khi scope đã audit.
- **tags:** [git-hygiene / em-main / commit]

### E-004 — gotcha #53 agent truncation mid-MEMORY (recurring S35-S42)
- **rule:** agent must flush MEMORY before return; em main must receive complete work.
- **what:** heavy WRITE-agent (implementer/test-specialist) output truncates mid-MEMORY-update; return looks complete but isn't.
- **5-why:** brief too heavy → spawn output cap hit → truncation at the tail → MEMORY update is last step → silent partial.
- **fix:** (code/process) em main grep-verify-on-disk after return + proxy-append the agent's MEMORY next session (Strategy B, `feedback_implementer_truncation_mitigation`). (guard) brief ≤8K + Tiered Memory L1 ~30KB cap.
- **prevention/guard:** Active-Guard "verify-on-disk + proxy-append" (promoted, 5 strikes). 529 → em main solo fallback, no retry-loop.
- **tags:** [process-truncation / sub-agent / agent-memory]

### E-003 — gotcha #44 silent 403 (S18, regression-tested S45)
- **rule:** authorization must fail loud, not silently break UX.
- **what:** class-level `[Authorize(Policy="Workflows.Read")]` → non-admin 403 → TanStack Query catch silent → Drafter saw empty Workspace dropdown, no error.
- **5-why:** broad class-level policy → GET blocked for non-admin → FE swallowed 403 → no surfaced error → looked like "no data".
- **fix:** (code) class-level `[Authorize]` only; GET for any-authenticated; POST/DELETE keep admin policy. (guard) test-specialist authz regression test +10 (S45) reflection-scan per-action policy.
- **prevention/guard:** Active-Guard "authz regression test per-action policy" (promoted S45).
- **tags:** [authz-regression / backend+frontend / ApprovalWorkflowsV2Controller]

### E-002 — gotcha #57 Holiday UNIQUE unfiltered → 500 (S45, fixed Mig 43)
- **rule (AS-4):** soft-delete entity + UNIQUE index MUST `.HasFilter("[IsDeleted]=0")`.
- **what:** `Holidays` DB UNIQUE (Year,Date) unfiltered vs handler `!IsDeleted` → admin delete + re-add same-date holiday = reachable 500.
- **5-why:** UNIQUE created unfiltered → soft-deleted row keeps the slot → handler allows logical re-create → INSERT hits dead UNIQUE → 500.
- **fix:** (code) Mig 43 `.HasFilter("[IsDeleted]=0")` (matches 13× existing pattern). (guard) Gap1 test-before reproduced the 500 first.
- **prevention/guard:** Active-Guard AS-4 + test-before. ✅ **RESOLVED S51 (Mig 45 `FilterHrmCatalogUniqueIndexesByIsDeleted`):** LeaveType + ShiftPattern + **OtPolicy** (OtPolicy was MISSED in "2 catalog" backlog → caught via grep-all-config) now `.HasFilter("[IsDeleted]=0")`; test-before +5 `HrmConfigFilteredUniqueTests` RED→GREEN (guard 2nd strike → now verified). ⚠️ **EXT OPEN (worktree session S51, Mig 46):** Department/Supplier/Project (Master — GLOBAL query-filter quirk auto-hides soft-deleted → recreate reachable); ContractClause/MeetingRoom/EmployeeProfile = audit-SKIP (not-reachable, investigator S51).
- **tags:** [soft-delete-invariant / em-main+test-specialist / Holidays,LeaveType,ShiftPattern,OtPolicy,(ext)Master]

### E-001 — S46 user-memory 0-byte (close-out truncation)
- **rule (AS-8):** memory `.md` writes must persist (byte>0); index must not be empty.
- **what:** S45 close-out left `MEMORY.md` index + 1 entry at 0 bytes → S46 bootstrap ran with NO memory auto-inject (silent degrade).
- **5-why:** session-end Write created stub → body Write truncated (gotcha #53) → 0-byte file → not git-tracked (outside repo) → undetected until next bootstrap audit.
- **fix:** (process) rebuilt index + repopulated entry (S46). (guard) `feedback_session_end_memory_write_verify` + now session-end §L.b step (e)/(c) byte-check.
- **prevention/guard:** Active-Guard "session-end verify byte>0" (episodic→promoted S48, wired §L.b). `/session-start` audit also re-checks 0-byte (caught it S46, re-ran clean S48).
- **tags:** [memory-integrity / em-main / user-memory]

---

> **Maintenance:** append RCA on each AS-hit; promote a guard to `procedural` on its 2nd strike; mark `verified` once it holds through a session; retire by net-effect. Pointer entries only — full narrative lives in session-logs (summary-index).
