# Lane B — eol-crlf

> RETURN-only tu /fable-clone ensemble wf_1f6bd5e2-478 (vai investigator-codebase, model opus).
> Lead ghi (B3 single-writer) — sub KHONG tu ghi. agentId=a764864a453971129

---

VERDICT: SE **KHÔNG SKIP** (autocrlf=true@system + file-frontmatter agents = có bề-mặt), NHƯNG lăng-kính B lật 2 tiền-đề của broadcast: (a) tôi ĐÃ ĐỌC ĐƯỢC parser mà broadcast tự khai chưa đọc — **js-yaml 4.1.1** nhúng trong `claude.exe`, `readLineBreak` xử-lý CRLF native → nửa `': '` **THẬT-SỰ N/A** cho SE (12/12 block-scalar), nhưng tôi cũng tìm thấy **regex delimiter LF-only `^---[ \t]*\n` ×2 tồn tại song song bản đã vá `\r?\n` ×2** → **CRLF ĐƠN-ĐỘC có thể đủ giết, KHÔNG cần `': '`** → SE **KHÔNG được tuyên miễn-nhiễm**; (b) §5.0 squash của SE = `git reset --soft` = **worktree-neutral** → 188 file **KHÔNG phải squash-fallout** mà là **`dotnet ef`/VS sinh CRLF** (131/188 = Migrations) → **acceptance `count==0` toàn-repo của hub là FALSE-POSITIVE FACTORY cho SE, phải scope**.

---

## 1) PROJECT-FIT — kết-luận từng nửa

| Nửa | Verdict SE | Bằng-chứng |
|---|---|---|
| "dùng agent dạng file-frontmatter?" | **CÓ** → không SKIP | `.claude/agents/` 12 agent + `.claude/commands/` 30 + `.claude/skills/*/SKILL.md` — cả 3 class đều frontmatter `---` |
| "autocrlf mọi tầng = false?" | **KHÔNG** → không SKIP | `git config --show-origin --get-all core.autocrlf` → `file:C:/Program Files/Git/etc/gitconfig  true` |
| **nửa `': '` chưa-quote** | **N/A THẬT — đã chứng ở tầng mã-nguồn** | 12/12 dùng `description: |` (verify từng file). Block scalar YAML = nội-dung KHÔNG bị quét chỉ-thị `:`. Parser = **js-yaml 4.1.1** (chuỗi license trong `claude.exe`) — thư-viện trưởng-thành, block-scalar đúng spec. |
| **nửa CRLF** | **🔴 KHÔNG miễn — và broadcast UNDER-STATE rủi-ro** | Xem §2 |

### §2 — Phát-hiện lật mô-hình broadcast (đây là giá-trị chính của lane B)

Broadcast dòng 29 tự khai: *"KHÔNG khẳng-định đã đọc mã-nguồn của bộ-đọc"*. Tôi đọc được:

**(a) Tầng chặt = js-yaml 4.1.1 → CRLF-safe, ĐÃ CHỨNG.** Trích `readLineBreak` minified nguyên-văn từ `C:\Users\pqhuy\AppData\Roaming\Claude\claude-code\2.1.209\claude.exe`:
```js
function qM(e){var t;t=e.input.charCodeAt(e.position),
 t===10?e.position++
 :t===13?(e.position++,e.input.charCodeAt(e.position)===10&&e.position++)
 :ar(e,"a line break is expected"),e.line+=1,...}
```
`13`=CR → nuốt, rồi nuốt tiếp `10`=LF → CRLF = **một** line-break. Broadcast đoán đúng, nay có chứng-cứ mã-nguồn.

**(b) NHƯNG tầng LF-only CÓ THẬT, và nó ở tầng TÁCH DELIMITER — TRƯỚC cả js-yaml.** Đếm literal trong cùng binary:

| regex | số | CR-tolerant? |
|---|---|---|
| `^---\s*\n` | 4 | ✅ (`\s` khớp `\r`) |
| `^---[ \t]*\r?\n` | 2 | ✅ (đã vá tường-minh) |
| **`^---[ \t]*\n`** | **2** | **🔴 KHÔNG — `[ \t]` KHÔNG khớp `\r`** |

→ Có **≥2 đường đọc frontmatter chưa-vá**. Trên file CRLF, dòng 1 = `---\r\n`; `^---[ \t]*\n` **không match** → frontmatter **không được nhận-diện** → agent rớt registry **mà js-yaml chưa từng được gọi** → **block-scalar KHÔNG cứu**.
Chứng phụ (telemetry-name trong binary): `tengu_frontmatter_shadow_mismatch`, `tengu_frontmatter_shadow_unknown_key`, `agentFrontmatter`, `Failed to parse YAML frontmatter` → xác-nhận kiến-trúc **≥2 parser**.

> **CHƯA VERIFY:** đường nào trong 2 đường LF-only đọc đúng `.claude/agents/`. String-table lưu theo index, không lấy được code-context. → **Phải giả-định xấu nhất.** Kết-luận: SE khai **"miễn nửa `': '` (đã chứng mã-nguồn) — KHÔNG miễn nửa CRLF"**.

**(c) Vector lật của SE KHÁC hub.** `session-end.md:112` — §5.0 dùng `git reset --soft HEAD~K`; `--soft` **không đụng worktree** → squash SE **không** lật EOL. 188 file = **công-cụ sinh CRLF**: 131/188 nằm `Migrations/` (`dotnet ef` sinh CRLF trên Windows) + 145 `.cs` / 4 `.csproj` / 1 `.slnx` (Visual Studio). `.claude/agents/*.md` LF vì **Write-tool của Claude Code phát LF**.
→ **Rủi-ro thật của SE = ai đó sửa agent-file bằng công-cụ phát CRLF (PowerShell `Set-Content`/`Out-File`)** — SE đã từng cắn đúng họ lỗi này (gotcha #30 → memory: *"#30-via-Edit (.ps1 pure-ASCII)"*). Và **`.gitattributes` KHÔNG chặn được cái này** (attr chỉ áp lúc checkout/add, không áp lúc tool ghi tùy-ý) → **validator + LOAD-VERIFY mới là lớp bảo-vệ thật cho agent-file, không phải `.gitattributes`.**

---

## 3) Bảng khối

| Khối | SE hiện-trạng (đo 2026-07-15) | GAP | Đối ứng cụ-thể | Acceptance ĐO ĐƯỢC |
|---|---|---|---|---|
| **① SELF-CHECK** | Đã chạy: autocrlf=`true`@system · flip=**188** · frontmatter-class (`agents`+`commands`+`skills`) `w/crlf`=**0** · `i/crlf`=**0** · `i/mixed`=**0** | Không có nơi lưu/lặp | Nhét vào `session-start.md` BƯỚC 0.7 (cạnh WAL-check) | `git ls-files --eol -- .claude/agents .claude/commands .claude/skills \| grep -c 'w/crlf'` → **0** |
| **② SYMPTOM** | 12 tên roster ↔ 12 `VALID_ROLES` `hmw.js` ↔ 12 file — **khớp, chưa ai chết** | Không có bước đối-chiếu tự-động | Nối vào 0.7 | 3 con-số = 12/12/12 |
| **③(a) .gitattributes** | Chỉ 2 rule (`broadcasts/**`, `*.sh`); `.claude/agents/` **attr/ TRỐNG** | Không phủ CLASS | §4 dưới | `git check-attr text eol -- .claude/agents/reviewer.md` → `text: auto`, `eol: lf` |
| **③(b) re-smudge 188** | 188 CRLF worktree; **chỉ 1 file tracked dirty = `.claude/WAL.md`, mà nó `i/lf w/lf` → KHÔNG nằm trong 188** → **toàn-bộ 188 SẠCH** | Chưa làm | §5 dưới | Sau: flip=0 **VÀ** `git status --porcelain` vẫn còn ` M .claude/WAL.md` (chứng không bị checkout mù nuốt) |
| **③(c) quote `: `** | 12/12 block-scalar | **N/A — đã chứng mã-nguồn (§2a)** | **SKIP**, ghi lý-do vào adap-report | `grep -c '^description: |$' .claude/agents/*.md` → 12 |
| **③(d) RESTART+VERIFY** | BƯỚC 0.6 = **model-probe**, KHÔNG phải registry-probe | Thiếu registry-probe | Thêm 0.6b | 12 tên spawn-được |
| **④(a) validator BYTES** | **KHÔNG CÓ.** `governance-detectors.ps1` là Select-String text-mode → **PASS-giả đúng như broadcast cảnh-báo** | Thiếu | `scripts/eol-frontmatter-validator.ps1`: `[IO.File]::ReadAllBytes()`, FAIL nếu byte `0x0D` xuất-hiện trước delimiter `---` thứ 2 | §6 (positive-control) |
| **④(b) wire đóng-phiên** | — | Thiếu | Gọi trong `session-end.md` §5.2 | Đọc §5.2 thấy lệnh |
| **④(c) EOL-assert SÁT push** | `session-end.md:123` `git push origin main` — **trần, không guard**. §5.0/§5.1/§5.2 = **3 section rời** → assert đặt ở 5.0 sẽ bị nhánh chạy-lại-squash đi vòng | Thiếu + **hub's `count==0` toàn-repo KHÔNG DÙNG ĐƯỢC cho SE** | §7 | §7 |
| **④(d) LOAD-VERIFY onboard** | S107 `office-document` có spawn-test **cùng phiên** = tiền-lệ ĐÚNG, nhưng **ad-hoc, chưa thành luật** | Chưa codify | Thêm dòng vào `agents/README.md`: agent MỚI/SỬA → spawn-probe TRƯỚC khi commit | Session-log ghi `spawn-probe: <name> OK` |

---

## 4) `.gitattributes` đề-xuất (FULL)

> An-toàn bất-thường cho SE: **`i/crlf=0` + `i/mixed=0`** → index ĐÃ 100% LF → file này **KHÔNG đổi một blob nào**, chỉ sửa materialize. Không có file nào cố-ý CRLF (0 `.bat`/`.cmd`; 24 `.ps1` **đang w/lf và CHẠY THẬT** — `wal-flush.ps1` đẻ 57 wal-commit → **PowerShell KHÔNG cần CRLF, đã chứng bằng chính repo SE**).

```gitattributes
# .gitattributes — SOLUTION_ERP
# S119: vá theo CLASS (broadcast 2026-07-15 ③a). Nen-tang do 2026-07-15:
#   core.autocrlf=true @ SYSTEM (C:/Program Files/Git/etc/gitconfig) — ngoai repo
#   i/crlf=0, i/mixed=0  -> index DA 100% LF -> file nay KHONG doi blob nao,
#                           chi sua tang materialize (checkout/smudge).
#   188 file i/lf+w/crlf = tool sinh CRLF (131 = dotnet ef Migrations, VS .cs/.csproj),
#                           KHONG phai squash-fallout (§5.0 dung reset --soft = worktree-neutral).

# ---- CLASS default: moi file text = LF ca index lan worktree ----
* text=auto eol=lf

# ---- Binary THAT — dang co trong repo (do: git ls-files --eol | grep i/-text = 19) ----
*.docx  binary
*.xlsx  binary
*.png   binary

# ---- Binary phong-ho (chua tracked; PDF-export form-engine / favicon / font FE) ----
*.pdf   binary
*.ico   binary
*.jpg   binary
*.jpeg  binary
*.gif   binary
*.zip   binary
*.exe   binary
*.dll   binary
*.woff  binary
*.woff2 binary
*.ttf   binary

# ---- Text tuong-minh (chong misdetect) ----
*.svg   text eol=lf
*.sql   text eol=lf
*.ps1   text eol=lf   # SE: 24/24 dang LF va CHAY THAT (wal-flush.ps1 Stop-hook). KHONG can CRLF.
*.sh    text eol=lf   # giu tu S111

# ---- Byte-exact channel: Harness 3 email body-hash (content_sha256 tren body LF) ----
broadcasts/** text eol=lf

# ---- Registry frontmatter: CHINH class ma ca ban va nay ton-tai de bao-ve (S119) ----
.claude/agents/**       text eol=lf
.claude/commands/**     text eol=lf
.claude/skills/**       text eol=lf
```
Không có fixture byte-cố-ý nào cần `-text` (đã quét: `eval/golden-set-*.jsonl` + `tests/**/Common/*Fixture.cs` đều là text thường).
⚠️ Churn kỳ-vọng, **lành-tính**: VS/`dotnet ef` sẽ tiếp-tục đẻ `.cs`/`.slnx` CRLF ở worktree → chúng lại hiện `i/lf w/crlf`. Index vẫn LF → repo vẫn đúng. **Đây chính là lý-do §7.**

---

## 5) Quy-trình re-smudge 188 file — AN-TOÀN

**Tiền-đề đã đo:** file tracked dirty **duy-nhất** = `.claude/WAL.md`, và nó `i/lf w/lf` → **giao của {dirty} ∩ {188} = ∅** → nhánh "rewrite byte tại chỗ" của broadcast ③(b) **N/A cho SE**; đi thẳng nhánh sạch. **Nhưng vẫn phải chạy guard B2** (tiền-đề có thể đổi trước khi anh chạy).

```bash
cd "D:/Dropbox/CONG_VIEC/SOLUTION/SOLUTION_ERP"
S="$TMP/eol"; mkdir -p "$S"

# B0 — .gitattributes PHAI LEN TRUOC (bat buoc, khong doi thu tu).
#      Chua co attr ma checkout => autocrlf=true materialize lai thanh CRLF = phan tac dung.
git add .gitattributes && git commit -m "[CLAUDE] Infra: .gitattributes class-level eol=lf (S119)"
git check-attr text eol -- .claude/agents/reviewer.md   # PHAI thay: text: auto / eol: lf

# B1 — chup danh sach flip (nguon chan-ly = git ls-files --eol, KHONG dung grep dem byte CR)
git ls-files --eol | grep 'i/lf.*w/crlf' | sed 's/.*\t//' > "$S/flip.txt"
wc -l < "$S/flip.txt"        # ky-vong 188

# B2 — GUARD: giao {dirty tracked} ∩ {flip} PHAI RONG. Khac 0 => DUNG, xu tay tung file.
git status --porcelain | grep -E '^( M|M |MM|A |AM)' | cut -c4- | sed 's/^"//;s/"$//' > "$S/dirty.txt"
comm -12 <(sort -u "$S/flip.txt") <(sort -u "$S/dirty.txt") > "$S/danger.txt"
test ! -s "$S/danger.txt" || { echo "STOP: file dirty nam trong flip-set:"; cat "$S/danger.txt"; }

# B3 — chi khi B2 rong: xoa roi checkout LAI DUNG 188 path (KHONG BAO GIO `git checkout -- .`)
#      Dropbox dang sync thu-muc nay -> mass-rewrite se noi song sync; chay luc ranh.
xargs -a "$S/flip.txt" -d '\n' rm -f --
xargs -a "$S/flip.txt" -d '\n' git checkout --

# B4 — ACCEPTANCE (3 dieu-kien, phai dung CA BA)
git ls-files --eol | grep -c 'i/lf.*w/crlf'                 # => 0
git status --porcelain | grep -c '^ M \.claude/WAL\.md'     # => 1  (viec chua-commit CON NGUYEN)
git diff --stat                                             # => trong (index von LF, khong blob nao doi)
```
**3 bẫy TIPS đã né trong quy-trình trên:** (i) không dùng `grep` msys đếm byte CR — chân-lý = `git ls-files --eol`; (ii) không tin `git diff` (nó **sẽ trống** dù byte worktree đổi, vì index vốn LF) → tin `--eol`; (iii) metric = `i/lf` **KÈM** `w/crlf`, không dùng `w/crlf` trần (SE có 0 `i/crlf` nên trần cũng ra 188, nhưng giữ đúng metric để khỏi dương-giả về sau).

---

## 6) ④(a) Validator + **giải bài positive-control** (SE không có file-đã-chết)

Broadcast bảo hiệu-chỉnh bằng byte file-đã-chết, "control thật hơn synthetic". **SE không có xác** — nhưng **không cần đợi tai-nạn: SE TỰ CHẾ control THẬT được**, và nó **mạnh hơn** cách hub:

```powershell
# Positive-control INDUCED (that, khong synthetic): dung CHINH reader, CHINH byte, CHINH registry.
$src = ".claude/agents/reviewer.md"
$b = [IO.File]::ReadAllBytes($src)
$t = ([Text.Encoding]::UTF8.GetString($b) -replace "`r`n","`n") -replace "`n","`r`n"   # ep CRLF toan file
$t = $t -replace '^name: reviewer', 'name: eolprobe-tmp'
[IO.File]::WriteAllBytes(".claude/agents/eolprobe-tmp.md", [Text.Encoding]::UTF8.GetBytes($t))
# -> RESTART -> spawn-probe `eolprobe-tmp`.
#    KHONG spawn duoc  = duong doc agent la mot trong 2 regex LF-only (§2b) -> SE DINH THAT, uu-tien CAO
#    Spawn DUOC        = duong doc la nhanh \s* / \r?\n         -> SE mien nua CRLF, ha uu-tien
# Ket thuc: xoa file probe (KHONG commit).
```
Khai thật: control này **mạnh hơn** hub's post-mortem control ở 3 điểm — **tái-lặp được**, **không cần thảm-hoạ**, **falsifiable** (đúng tinh-thần ④d "chịu để bị chứng-minh sai"). Yếu hơn 1 điểm: nó chứng **điều-kiện gây chết**, không chứng "đã từng chết ở SE". Chấp-nhận được, và nó **trả lời luôn câu CHƯA VERIFY ở §2b** — đây là **thí-nghiệm quyết-định duy-nhất**, đề-nghị lead chạy TRƯỚC khi quyết mức đầu-tư cho toàn gói.
Validator (`scripts/eol-frontmatter-validator.ps1`) hiệu-chỉnh bằng chính byte file probe này; đọc `[IO.File]::ReadAllBytes()` — **tuyệt-đối không** `Get-Content`/`splitlines` (nuốt CR → PASS-giả). Có sẵn khuôn fault-injection: `governance-detectors.ps1:32-33` đã có `param([string]$RepoRoot=...)` → copy pattern, inject cây tạm để chứng detector **có răng** (memory: feedback_faultinjection_proves_teeth).

---

## 7) ④(c) EOL-assert sát push — **PHẢI TAILOR, KHÔNG BÊ NGUYÊN**

🔴 **Hub's `git ls-files --eol | grep -c 'i/lf.*w/crlf'` == 0 là FALSE-POSITIVE FACTORY ở SE.** Lý-do đo được: `dotnet ef migrations add` + VS **sẽ luôn** đẻ `.cs`/`.csproj`/`.slnx` CRLF ở worktree; `git add` chuẩn-hoá index về LF nhưng **không** viết lại worktree → `i/lf w/crlf` **mọc lại ngay** sau mỗi phiên có migration (131/188 hiện-tại chính là dấu-vết này). Assert toàn-repo sẽ **chặn push hợp-lệ** → bị disable trong 2 phiên → **Goodhart, tệ hơn không có**.

**Đối ứng — 2 tầng, tách vai:**

**(a) BLOCKING, scope đúng class chết-im-lặng** — nhét **TRONG `session-end.md` §5.2, CÙNG khối với `git push`** (không phải §5.0 — nhánh chạy-lại-squash sẽ đi vòng, đúng cảnh-báo broadcast):
```bash
# §5.2 Push remote — EOL-assert DINH LIEN push (S119 ④c, scoped)
N=$(git ls-files --eol -- .claude/agents .claude/commands .claude/skills | grep -c 'w/crlf')
test "$N" = "0" || { echo "BLOCK: $N frontmatter-file CRLF -> agent co the chet im-lang"; exit 1; }
git push origin main
```
Ổn-định được vì class này **chỉ do Write-tool (LF) sinh** — hiện **0/…** đã sạch, không có generator CRLF nào đụng vào.

**(b) INFORM-only, toàn-repo** — thêm **C6** vào `scripts/governance-detectors.ps1` (script `exit 0` cố-định ở `:455` → **đúng vai INFORM, không thể làm gate**): in số flip toàn-repo + breakdown theo thư-mục, `resolve:` = re-smudge §5. Bắt drift mà không chặn ai.

**Acceptance §7:** (i) đọc §5.2 thấy assert **cùng khối** `git push`; (ii) fault-inject 1 file CRLF vào `.claude/agents/` cây tạm → assert **FAIL** (chứng có răng); (iii) chạy `dotnet ef migrations add` bịa → assert **VẪN PASS** (chứng không dương-giả) ← đây là test **anti-Goodhart** quan-trọng nhất.

---

## 8) Ưu-tiên đề-nghị lead

1. **Chạy §6 probe TRƯỚC** — nó quyết SE dính CRLF thật hay không; mọi thứ khác phụ-thuộc kết-quả này.
2. §4 `.gitattributes` — **rẻ, zero blob churn**, làm ngay bất-kể (1) ra sao.
3. §7(a) assert scoped — rẻ, ổn-định, chặn đúng chỗ.
4. §5 re-smudge 188 — **giá-trị thấp nhất** (index vốn đúng; 131/188 sẽ mọc lại). Làm để `--eol` sạch một lần, không phải để sửa lỗi thật.
5. §6 validator + ④(d) codify spawn-probe — lớp bảo-vệ **thật** cho agent-file (`.gitattributes` **không** cứu được tool-write CRLF).

**Khai thật tổng:** claim mạnh nhất của lane này (js-yaml 4.1.1 + `readLineBreak` CRLF-safe) là **source-verified**; claim "có đường LF-only" là **string-verified** (đếm literal regex trong binary) nhưng **đường nào đọc agents thì CHƯA VERIFY** — chỉ §6 probe giải được.