---
description: Nhận email cross-project (2-stage) qua broadcasts/ (Harness 3 §N) cho SOLUTION_ERP (self=se). Verify hash đối chứng. §J2. Adopt AI_INFRA Harness 3 (2026-06-07).
argument-hint: <from_project | all>
---
# /check-email <from_project> — nhận email cross-project (Harness 3 · self=`se`)

> 🔴 Kênh DUY NHẤT (§N) · **pull-copy** chỉ ghi repo MÌNH (§J2). self=`se`. Path map: xem `send-email`. Detail: AI_INFRA `broadcasts/README.md` §Harness 3.

## Tham số
- `$1` = from_project (BẮT BUỘC) ∈ 6 others, hoặc `all` = quét cả 6.

## Nhịp chạy — 🔴 4 CỬA PHIÊN (owner chốt S148, 2026-07-24)

> 🔴 **Đây là NHÀ CANONICAL của "khi nào chạy `/check-email`".** 4 file lệnh cửa **chỉ TRỎ vào đây** rồi gọi lệnh; **CẤM chép luật sang** (B1 — chép 4 nơi = 4 nguồn sự-thật).

**Anh chốt @S148:** *"mỗi session end/start luôn — vì 1 session giờ có thể kéo dài 2-3 phiên qua 2-3 ngày."*
⇒ nhịp neo vào **SỰ-KIỆN PHIÊN**, **KHÔNG** vào đồng-hồ ngày. Lý-do anh nêu là lý-do kỹ-thuật đúng: một phiên-LOGIC trải nhiều cửa-sổ nhiều ngày ⇒ ngưỡng-theo-ngày **không map** được vào nhịp làm việc thật.

🔴 **Vì sao 4 cửa chứ không 2 — lead MỞ RỘNG từ câu chữ, khai thẳng để anh bác được:** cửa VÀO có 2 và cửa RA có 2.

| | cửa-1 | cửa-2 |
|---|---|---|
| **VÀO** | `/session-start` (phiên mới) | `/tiep` (nối phiên-logic) |
| **RA** | `/session-end` (đóng sổ) | `/pause` (dừng chủ-động) |

Chỉ cắm 2 cửa `session-start`/`session-end` thì **đúng ca anh đang lo VẪN LỌT**: phiên S148 vào bằng `/tiep`, phiên trước ra bằng `/pause` ⇒ **cả hai lần đều không check**. Mà chính câu *"1 session kéo 2-3 phiên"* hàm ý các phiên GIỮA vào bằng `/tiep` ⇒ **phần lớn cửa nằm ở nhánh `/tiep`**, không ở `/session-start`. Phủ 4 cửa mới đạt được điều anh nói.

### 🔴 HAI CHẾ-ĐỘ — sửa @S148 sau khi đọc thư `goi-chot-owner-nam-khoan` khoản 3 (BINDING)

> **Lead tự bắt vi-phạm của chính mình:** bản đầu @S148 cắm **PULL đầy-đủ** vào cả 4 cửa. Thư hub `2026-07-19-Governance-goi-chot-owner-nam-khoan` §3 là **ràng-buộc thiết-kế CỨNG**, verbatim: *"bất kỳ van/gate/phép-đo nào về sau cũng **KHÔNG ĐƯỢC** chặn hoặc làm chậm các cửa **dừng–nối–checkpoint**"*, floor: *"bước nào nặng (spawn agent, đo đạc lớn, **quét rộng**) đang nằm trong đường pause-tương-đương là **vi-phạm**: dời nó về **closeout/bookend**"*. ⇒ `/pause` + `/tiep` **là đúng 2 cửa đó**.
> 🔴 **Hub bắt ĐO chứ không đoán** (SELF-CHECK: *"Đo wall-clock một lần — điểm dừng phải rẻ"*). **Đo @S148, 3 lượt:** **dò** (list 6 repo + so id) = **66ms lạnh / 4–5ms nóng**; **kéo** (copy + hash + `python stamp_verify.py`) = python-startup **~200–500ms × số thư**. ⇒ **dò KHÔNG nặng, kéo MỚI nặng.** Nên vá đúng là **tách 2 chế-độ**, KHÔNG phải bỏ cửa — bỏ cửa sẽ mất đúng thứ anh cần (phiên giữa vào bằng `/tiep`).

| chế-độ | cửa | làm gì | chi-phí |
|---|---|---|---|
| **DÒ** (detect-only) | `/tiep` · `/pause` | list + so id → in `thu-moi: se=X all=Y`. 🔴 **KHÔNG copy · KHÔNG hash · KHÔNG python.** X hoặc Y > 0 ⇒ nêu **1 dòng** rồi đi tiếp, để bookend kéo | ~5ms |
| **KÉO** (đầy-đủ) | `/session-start` · `/session-end` | `se>0` → **`/check-email`** STAGE 1 (copy + verify 2 tuyến + log `_index`) · `all>0` → **`/adap-apply`** | theo số thư |

🔴 **DÒ PHẢI QUÉT CẢ HAI KÊNH — đây là kẽ thật, và nó nằm ở NHỊP chứ không ở tool:** `outbox/se` (directed, → `/check-email`) **VÀ** `outbox/all` (fan-out, → `/adap-apply`). Không có nhánh `all` thì **10 broadcast đợt adap-11 nằm im 5 ngày** (07-18→07-23) — ca đã xảy ra thật, không phải giả-định. **DÒ chỉ ĐẾM và ĐỊNH TUYẾN, không kéo** ⇒ vẫn rẻ.
🔸 **Watermark cho `outbox/all`:** bỏ qua id ≤ **`2026-07-15`** — 51 file mốc 06-02→07-15 là lớp *đã-adopt-đọc-tại-chỗ* (`/adap-apply` đọc thẳng bên AI_INFRA, **KHÔNG đòi copy** ⇒ vắng mặt trong inbox là **BÌNH THƯỜNG**, không phải nợ). Không có watermark thì mỗi lượt DÒ kêu 51 cái rồi tự bị bỏ qua.

🔒 **Bất-biến:** việc NẶNG chỉ sống ở **bookend**. Ai thêm bước vào đường `/pause`·`/tiep` sau này **phải đo wall-clock trước**, đúng câu hỏi hub đặt: *"có làm điểm dừng đắt lên không"* — **TRƯỚC** khi bàn giá-trị của bước đó.

## BƯỚC 0 — TIỀN KIỂM ĐẦU CỬA (chỉ đọc, chi phí ~0, **KHÔNG chặn**)

🔴 Chạy **TRƯỚC** DÒ/KÉO: `powershell.exe -ExecutionPolicy Bypass -File scripts/tien-kiem-cua.ps1 -Cua check-email` → in **1 dòng** `TIEN-KIEM: …`.
🔴 **KHÔNG CHẶN** — lỗi ⇒ `tien-kiem loi (khong chan)` → đi tiếp; máy **luôn `exit 0`** (cổng chặn = W3b, chưa chốt).
🔸 Chọn cửa đóng gần nhất bằng **dấu thời gian TRONG tệp**, không tin `mtime`. `THIEU-TAP` = 0/2 nguồn đọc được, **cấm đọc thành "sạch"**. Nhãn bước lệch: `docs/governance/ritual-labels.md`.
🔸 **Đã tuân bất-biến `:41` ngay trên:** wall-clock đo TRƯỚC khi cắm (S180 W3) — ròng **~194 ms**, rẻ hơn `nhip-no-probe.ps1` (**~281 ms**) vốn đã được chấp nhận ở `/pause`·`/tiep`. **KHÔNG cắm bước này vào `/pause`·`/tiep`** (hai cửa đó đã có probe; thêm nữa là làm điểm dừng đắt lên).

**Cách chạy ở mỗi cửa — `/check-email all`:**
- 🟢 **Không có thư mới ⇒ 1 dòng, im lặng đi tiếp.** KHÔNG báo-cáo dài, KHÔNG chờ anh.
- 🔴 **FAIL-SOFT, CẤM chặn nghi-thức:** lỗi bất-kỳ (repo bên kia không có trên máy · path đổi · thiếu python) ⇒ in `check-email loi (khong chan)` rồi **ĐI TIẾP**. Cùng khuôn `nhip-no-probe.ps1`: một bước MỚI **không bao giờ được phép** làm hỏng nghi-thức đã chạy tốt.
- Có thư ⇒ chạy trọn **STAGE 1** (copy + verify hash). **STAGE 2** (move → `processed`) đi theo việc xử-lý, **KHÔNG ép** trong cùng lượt.

**Quan-hệ với vế-4 `pull-cach` (`nhip-no-probe.ps1`) — ĐỔI VAI:** trước định làm **chuông báo** (cần ngưỡng `pull_warn_days`). Nay 4 cửa là cơ-chế CHÍNH ⇒ `pull-cach` thành **chỉ-báo sức-khoẻ của chính nghi-thức**: số ngày cứ leo trong khi phiên vẫn mở/đóng đều đặn ⇒ **nghi-thức đang bị chạy tắt**, chứ không phải hub im. 🔒 **`pull_warn_days` CỐ Ý để TRỐNG** — anh không đặt số @S148, và script cấm tự chế mặc-định.
🔸 **Giới-hạn giữ khai (đo @S148):** vế-4 mạnh với **quãng im DÀI**, yếu với **trễ-kéo NGẮN** — ca hub-gửi-giục 07-18 chỉ `N=2` mới bắt, mà `N=2` nằm ngay trên trung-vị ⇒ kêu gần như liên-tục. Đừng kỳ vọng `pull-cach` chặn tái-diễn ca đó; **4 cửa mới là thứ chặn nó.**

## Quy trình 2-STAGE (audit qua folder)
**STAGE 1 — Nhận (đọc → inbox root, PENDING):**
1. Validate `$1`.
2. READ `<from>/broadcasts/outbox/se/*.md` (message gửi **đích danh** se).
   🔴 **CHỈ `outbox/se` — ĐÚNG, đừng "sửa" thành đọc cả `outbox/all`.** Hai kênh, hai tool, hai sổ:

   | kênh | nội dung | tool kéo | sổ theo dõi |
   |---|---|---|---|
   | `outbox/se/` | thư **directed** (`to: se`) | **`/check-email`** (file này) | `broadcasts/_index.md` §INBOUND |
   | `outbox/all/` | **fan-out** (`to: all-fit`) | **`/adap-apply`** ([`adap-apply.md:14`](adap-apply.md) đọc **thẳng tại chỗ**) | **KHÔNG** vào `_index` — xem header `_index.md` dòng 7 |

   🧊 **Vết sai @S148 — giữ làm bài học:** lead đọc `C14-disposition-per-khoan.md:21` (@S144) khai *"kẽ đã bịt: `/check-email` bước 2 chỉ đọc `outbox/se`, không nhắc `outbox/all`"* → **tin bản tóm-tắt** → sửa bước này thành đọc cả 2 kênh. **Sai:** `outbox/all` chưa bao giờ là việc của `/check-email`. Kiểm ngược bằng máy: **22/22** thư `outbox/se` đều có dòng `_index`, **thiếu 0** ⇒ tool này vốn **không hề thủng**. 🔴 **Hai lỗi chồng nhau, cả hai đều là *tin chữ thay vì đo*:** C14 tuyên "đã bịt" một kẽ **không tồn tại**, rồi lead vá một tool **không hỏng**.
   🔴 **Kẽ THẬT nằm ở NHỊP, không ở tool:** không cửa phiên nào **dò** `outbox/all` ⇒ 10 broadcast fan-out nằm im **5 ngày**. Vá đúng = **DÒ 2 kênh ở cửa phiên rồi ĐỊNH TUYẾN** (§"Nhịp chạy" trên), KHÔNG phải nhét kênh này vào STAGE 1 của tool kia.
3. Mỗi file CHƯA có trong inbox (so id): **COPY VERBATIM** → `broadcasts/inbox/<id>.md` (**root = pending**). [repo MÌNH §J2]
4. **Verify đối chứng:** (a) **whole-file** `Get-FileHash` copy == nguồn (byte-identical = tuyến CHÍNH); (b) **body** recompute `SHA256(body)` == `content_sha256` khai ở frontmatter.

   **4(b) — đầu-đọc stamp KHOAN-DUNG (adopt S141, ghim S142):**
   - 🔴 **ƯU TIÊN chạy SCRIPT, đừng tự chế lệnh rút hash:** `python scripts/stamp_verify.py <file>` — **bản port LOCAL trong repo này** (KHÔNG trỏ hub-path `AI_INFRA/scripts/...` nữa; hub-path chỉ còn là nguồn **re-pull** khi hub đổi §N canon). Script in `declared / canonical / no-strip` + verdict; **exit 0 = OK**, exit 1 = có MISMATCH. Nó còn tách được `WRONG-METHOD` (stamp bằng biến-thể no-strip) khỏi `MISMATCH` thật — thứ mắt thường không phân biệt nổi.
   - **Rút hash declared — PIN mẫu KHOAN-DUNG:** `content_sha256:\s*"?([0-9a-fA-F]{8,64})"?` — phủ **CẢ 3 dạng đang sống trên đĩa**: (i) **có-ngoặc** `content_sha256: "abc..."` · (ii) **không-ngoặc** `content_sha256: abc...` · (iii) **rút-gọn ≥8-hex** (so bằng **tiền-tố**, KHÔNG đòi bằng độ-dài).
   - 🔴 **CẤM mẫu quote-strict `content_sha256:\s*([0-9a-fA-F]+)`** — nó **whiff ngay ký-tự `"` đầu tiên** ⇒ hash có-ngoặc rút ra rỗng ⇒ đọc thành "không khớp" ⇒ **FALSE-TAMPER**. Bẫy ĐÃ GẶP, không phải giả-định: S141 suýt kết oan tamper cả ba trên ba thư mà cả ba đều lành. Mẫu chặt hơn ở đây **KHÔNG** an-toàn hơn — nó chỉ đổi lỗi "bỏ sót" thành lỗi "vu oan".
   - **Body canonical** (khớp ĐÚNG `scripts/stamp_verify.py`): `$txt=[Text.Encoding]::UTF8.GetString([IO.File]::ReadAllBytes($f)) -replace "^\uFEFF",""; (($txt -replace "\r","") -split "(?m)^---\s*$",3)[2] -replace "^\n",""` → SHA256-UTF8. 🔴 **CẤM `Get-Content -Raw` cho hash** — PS 5.1 đọc UTF-8-no-BOM bằng ANSI → mojibake → **false-tamper** (S125).
   - ✗ → **nghi VERIFIER TRƯỚC** (chạy `python scripts/stamp_verify.py <file>` + test 1 sibling known-good; verifier fail cả sibling ⇒ lỗi tool, KHÔNG phải tamper); vẫn ✗ → **flag tamper, KHÔNG move**, báo anh.
5. Log `_index.md` §INBOUND: `received · id · <from> → se · status=pending · folder=(root) · sha256(12) · verify=✓`.

**STAGE 2 — Xử lý xong → archive (PROCESSED):**
6. Sau khi xử lý → **MOVE** `inbox/<id>.md` → `inbox/<from>/<id>.md`.
7. Update `_index.md`: `status=processed · folder=<from>`.

## Audit (anh)
`ls broadcasts/inbox/*.md` (root) = **pending chưa xử lý** (backlog hiện ngay) · `inbox/<proj>/` = **đã xử lý**.

## Luật
🔴 §N single-channel · 🔴 §J2 pull-copy chỉ-ghi-inbox-MÌNH (KHÔNG push repo bên kia) · **KHÔNG sửa** file copy (bằng chứng) · PHẢI committed · verify-hash trước move.
