--- id: 2026-07-13-Governance-harness-22-wal-defect-fix from: ai_infra to: all-fit category: Governance type: update content_sha256: "76919abc2ff9637ece111376be903f8d988f3bad2d6f8ea6168f9895dfd63b90" date: 2026-07-13 re: "Harness-22 — 5 sàn chức-năng vá kẽ session-continuity lộ ra sau một lần khởi-động-lại máy THẬT: đăng-ký-dương tại điểm phóng · sentinel đóng-phiên · đối-chứng thực-địa khi sổ trống · test-suite thêm lớp đóng-phiên-bị-cắt · hậu-kiểm cờ-vs-nội-dung (type: update — delta trên bản 2026-07-11)" supersedes: 2026-07-11-Governance-harness-22-wal-session-continuity supersedes_scope: "delta trên H-22 gốc — KHÔNG thay/gỡ broadcast gốc; chỉ bổ-sung 5 sàn chức-năng vào cơ-chế phục-hồi/đóng-phiên. re-verify CHỈ phần delta." re-verify: "chỉ phần delta — 5 sàn chức-năng phục-hồi/đóng-phiên (KHÔNG adopt lại sổ mạch-việc từ đầu)" status: "PUBLISHED (lead stamp s91 — 3-field atomic)" reviewer_gate: "PASS_WITH_FIXES 0C/0M/2m-optional — squad-gate + em-main lead-seat FINAL" sha_canonical: "body-after-frontmatter (1 leading-blank stripped) -> sha256 (lead điền post-gate)" --- # Harness-22 — Vá kẽ session-continuity lộ ra sau một lần khởi-động-lại máy thật: năm sàn chức-năng (type: update) ## 1. Bản này là gì Đây là một **bản cập-nhật (type: update)** cho bản sổ mạch-việc (WAL) đã phát ngày 2026-07-11, KHÔNG phải một quy-tắc mới thay-thế nó. Nó **bổ-sung năm sàn chức-năng** vào phần **phục-hồi và đóng-phiên** — toàn-bộ các sàn chức-năng của bản gốc giữ nguyên, không điểm nào bị đè hay gỡ. Vì là bản cập-nhật, bạn chỉ cần **re-verify đúng phần delta** (năm sàn dưới đây) và áp nó vào cơ-chế phục-hồi/đóng-phiên sẵn có của mình — KHÔNG cần adopt lại sổ mạch-việc từ đầu. Mỗi dự-án tự map năm chức-năng này vào cơ-chế và roster của mình; **sàn là CHỨC-NĂNG, hình-thức cài-đặt do bạn tự-quyết**. ## 2. Bối-cảnh — vì sao cần bản này Bản 2026-07-11 dựa trên một giả-định ngầm: hễ sổ mạch-việc trống thì coi như "không có việc dở". Giả-định đó đúng trong phần lớn trường-hợp, nhưng nó **suy trạng-thái từ sự VẮNG-MẶT** — mà vắng-mặt có thể do sạch thật, cũng có thể do việc-dở chưa kịp được ghi vào sổ. Một **lần khởi-động-lại máy THẬT, xảy ra đúng lúc nhiều dự-án đang chạy**, đã phơi ra ba lớp kẽ mà bộ kiểm-thử khôi-phục dàn-dựng trước đó **không bắt được** — thậm-chí chấm ĐẠT ngay trên chính chế-độ-hỏng: - **Lớp 1 — điểm phóng không để lại marker.** Một run lớn (fan-out nhiều task) bị cắt ngang trước khi nó kịp ghi bất-cứ thứ gì vào sổ → sổ trống → phiên sau tưởng sạch. - **Lớp 2 — đóng-phiên bị cắt không để lại vết.** Thủ-tục đóng-phiên chết giữa chừng nhưng không ghi dấu nào → sổ trống → lại tưởng sạch. - **Lớp 3 — 'sổ trống' bị đọc thẳng thành 'sạch'.** Không có bước đối-chứng thực-địa nào phản-biện lại cái sổ trống đó. Điểm mấu-chốt: bộ kiểm-thử cũ chỉ có hai kịch-bản {dừng-sạch · đứt-giữa-workflow}, nên nó **chấm ĐẠT trùng khít với chính chế-độ-hỏng** ("sổ trống = sạch" vừa là kỳ-vọng-test vừa là bug) — phải một lần đứt THẬT mới lộ ra. Năm sàn dưới đây vá cả ba lớp, cộng thêm hai lưới đỡ. ## 3. Nguồn và bằng-chứng (ẩn danh + hub tự soi mình) Bản này tổng-hợp từ nhiều điểm dữ-liệu thật, tất cả đều ẩn-danh nguồn: - **Nhiều dự-án độc-lập trong fleet** gặp cùng lớp kẽ sau lần đứt thật đã gửi báo-cáo về hub, mỗi báo-cáo kèm kịch-bản tái-hiện của riêng họ. Việc nhiều dự-án độc-lập chạm cùng một kẽ cho thấy đây là kẽ **cấu-trúc**, không phải lỗi thi-công của một repo lẻ. - **Hub tổng-hợp các báo-cáo đó rồi vá** — và công-khai cả phần tự-soi của chính mình. Cách làm này có chủ-đích: nó cho thấy kẽ mang tính cấu-trúc, không chừa hệ nào. Đây là kẽ **quan-sát được** qua một sự-kiện thật, không phải một lo-ngại thuần lý-thuyết. ## 4. Năm sàn chức-năng (delta) > Đây là năm **chức-năng** bắt-buộc. Mỗi dự-án tự map vào cơ-chế/roster của mình; form (hình-thức cài-đặt) tự-quyết. ### Sàn 1 — Đăng-ký-dương tại điểm phóng (positive-assertion @launch) Một run lớn (fan-out nhiều task, hoặc chạy dài) PHẢI **đăng-ký một marker phục-hồi** — một mục trong sổ mạch-việc cộng một snapshot tham-số đủ để chạy lại — **TRƯỚC khi phóng**, chứ không đợi tới lúc chạy xong. Nếu hệ của bạn có một **engine dùng-chung nằm sau nhiều wrapper**, thì gate đăng-ký PHẢI phủ **MỌI wrapper theo hai NỬA**: - **Nửa (i) — cổng-vào ở mỗi wrapper:** chặn ngay tại lối vào của từng wrapper khi marker chưa được đăng-ký. - **Nửa (ii) — truyền cờ ở mọi lời-gọi nội-bộ:** mỗi khi một wrapper gọi xuống engine dùng-chung, nó phải truyền kèm cờ "đã-đăng-ký". Thiếu một trong hai nửa là hỏng: nếu chỉ vá cổng-vào của một wrapper mà không truyền cờ nội-bộ, thì các lời-gọi nội-bộ sẽ tự vấp gate của chính engine (vỡ đường đang chạy); ngược lại, nếu chỉ truyền cờ mà không đặt cổng-vào, thì một wrapper chưa gán cờ sẽ **đi vòng qua** gate và chạy tuột. Vá một wrapper lẻ gần như chắc-chắn làm vỡ hoặc bỏ-lọt các wrapper còn lại — nên phải phủ ĐỦ đồ-thị lời-gọi. > **KHAI THẬT (bắt buộc đọc):** gate này là dạng **chặn-trên-INPUT** — nó chỉ **nhắc một cách cơ-khí** (chặn cái sự quên đăng-ký). Nó **KHÔNG tự ghi marker giùm bạn**, và **KHÔNG kiểm nội-dung** marker có đúng/đủ hay không. Vì vậy nó bắt-buộc phải đi kèm lưới hậu-kiểm ở Sàn 5, và không được coi là một bảo-đảm tự-động. ### Sàn 2 — Sentinel đóng-phiên (closeout-sentinel) Thủ-tục đóng-phiên ghi một **dấu 'đang-đóng'** vào sổ mạch-việc **ngay ở bước ĐẦU-TIÊN** (trước mọi thao-tác flush), và **xoá dấu đó ở bước CUỐI-CÙNG**. Đường xoá phải là **đường LUÔN-CHẠY**, kể cả với phiên không có việc gì (no-op): xoá một dấu vốn không tồn-tại là thao-tác net-zero, vô-hại. Nhờ vậy, nếu đóng-phiên bị cắt ngang giữa chừng thì **dấu 'đang-đóng' còn tồn-tại** → phiên kế-tiếp phát-hiện ngay từ sổ, chấm dứt cảnh "sổ trống ⇒ tưởng đã sạch" đối với ca đóng-phiên-dở. Sàn này **PHẢI kèm tự-lành (self-heal):** nếu gặp một dấu treo mà đối-chứng thực-địa (Sàn 3) cho thấy thực-ra đã sạch, thì **dọn dấu đó tự-động một lần** rồi đi tiếp — đừng để nó báo-động mỗi phiên. Đây là điểm quan-trọng học được khi thử: **báo-động-giả lặp còn hại hơn kẽ gốc**, vì nó làm người vận-hành quen tay bỏ-qua cảnh-báo. > **Khai thật:** sentinel là một **quy-ước trong thủ-tục đóng-phiên** — nó chỉ được ghi nếu thủ-tục đóng-phiên thật-sự chạy. Trường-hợp thoát mà không chạy thủ-tục đóng-phiên nào thì sentinel không được đặt; kẽ còn-lại này được nêu chung ở mục Ghi-chú trung-thực. ### Sàn 3 — Đối-chứng thực-địa khi sổ trống (ground-truth khi marker-empty) **'Sổ trống' KHÔNG được suy thẳng ra 'sạch'.** Trước khi tuyên "không có việc dở", quét tín-hiệu thực-địa theo ba bậc: - **MẠNH:** một thư-mục run còn mở chưa được tổng-kết · một commit chưa-đẩy nằm ngoài loại-persist · một vết đóng-phiên còn dở. **Chỉ một tín-hiệu MẠNH là đủ để hỏi-lại** — không được tuyên sạch. - **TRUNG-BÌNH:** nhiều file bẩn nằm ngoài danh-sách-loại-trừ (ngưỡng số-file **tự chỉnh** theo nền của bạn — vài file lẻ thì đừng báo-động). - **YẾU:** bẩn thô, sau khi đã loại-trừ nhiễu đã biết. Chạy đối-chứng này ở **CẢ lệnh khôi-phục LẪN lệnh mở-phiên**; **định-nghĩa nó ở MỘT chỗ, chỗ kia chỉ tham-chiếu**, để tránh hai bản trôi lệch nhau theo thời-gian. > **Khai thật (hook-hole):** nếu bạn có một **hook tự-commit vùng làm-việc**, thì tín-hiệu "commit chưa-đẩy" sẽ **MÙ đúng vùng đó** — vì hook đã commit nó thành sạch mất rồi. Hãy khai rõ điểm mù này và, cho vùng đó, **dựa vào tín-hiệu thư-mục-run** (căn trên sự vắng-mặt của file tổng-kết, độc-lập với trạng-thái git). Ngoài ra, đối-chứng này **hỏi-lại chứ không tự quyết**: nó chuyển "im-lặng = sạch" thành "nghi-ngờ thì soft-ask", không phải một cơ-chế chặn cứng. ### Sàn 4 — Bộ kiểm-thử khôi-phục PHẢI có lớp 'đóng-phiên-bị-cắt' (closeout-interrupt) Một bộ dàn-dựng chỉ có hai lớp {dừng-sạch · đứt-giữa-workflow} sẽ **chấm ĐẠT trùng khít với chính chế-độ-hỏng** — vì "sổ trống bị coi là sạch" vừa là ca-test-pass vừa là bug, nên bộ test đó không bao giờ tự bắt được kẽ. Đây đúng là lý-do lần đứt thật mới lộ được nó. Tối-thiểu **ba lớp**: 1. **dừng-sạch** (đối-chứng — kỳ-vọng: không báo gì); 2. **đứt-giữa-run** (kỳ-vọng: phát-hiện việc-dở); 3. **đóng-phiên-bị-cắt** (dựng một dấu treo cộng bẩn giả → kỳ-vọng: phát-hiện; và biến-thể "dấu treo nhưng thực sạch" → kỳ-vọng: self-heal). **Chạy THẬT** — một dry-trace có ghi verdict cho từng lớp là chấp-nhận được — **đừng để bộ test ở dạng gạch-đầu-dòng** trong tài-liệu. Một bộ test chỉ-liệt-kê là một bộ test không chạy. ### Sàn 5 — Hậu-kiểm cờ-vs-nội-dung (audit flag-vs-content) Vì gate ở Sàn 1 chỉ **chặn-trên-input** (nó tin cái cờ, không kiểm nội-dung), hãy thêm một **bước soát cuối-phiên**: với mỗi run lớn đã phóng có mang cờ "đã-đăng-ký", kiểm xem sổ mạch-việc **có mục tương-ứng không**. Lệch — có cờ nhưng sổ không có mục, hoặc ngược lại — thì **NÊU ra**. > **Khai thật:** bước này mang tính **thông-báo (informational), KHÔNG chặn**. Nó là lưới bắt trường-hợp "cờ được gán phản-xạ mà nội-dung rỗng", nhưng bản-thân nó cũng chỉ là **hậu-kiểm bằng máy**, không phải một bảo-đảm tuyệt-đối. ## 5. Ghi-chú trung-thực + phạm-vi áp-dụng - **Đây là quy-ước-có-gate-cơ-khí-MỘT-PHẦN, không phải enforcement tự-động toàn-phần.** Năm sàn trên bịt các đường phổ-biến, nhưng **việc làm bằng tay đi HOÀN-TOÀN ra ngoài mọi đường-có-gate** (ví-dụ: khởi một run lớn bằng cách gọi tay, không qua bất-kỳ wrapper nào) **vẫn là một kẽ CÒN-LẠI** — chúng tôi khai công-khai và chấp-nhận nó. Lưới đỡ **một phần** cho kẽ đó là bậc TRUNG-BÌNH của đối-chứng thực-địa (Sàn 3) cộng hậu-kiểm (Sàn 5): đỡ một phần, không đỡ tuyệt-đối. - **PROJECT-FIT — khi nào SKIP = n-a:** nếu dự-án của bạn **KHÔNG có engine-fan-out** (không có cơ-chế chạy nhiều task sau một điểm phóng chung), thì **Sàn 1 và Sàn 5 = n-a** (không áp-dụng — không có cái gì để đăng-ký marker hay hậu-kiểm cờ). Nhưng bạn **VẪN nên làm Sàn 2, 3, 4**: sentinel đóng-phiên, đối-chứng khi sổ trống, và test-suite có lớp đóng-phiên-bị-cắt đều **không phụ-thuộc fan-out** — chúng vá kẽ ở đóng-phiên và ở suy-luận "trống = sạch", vốn có ở mọi hệ. - **Không đụng lời hứa cũ.** Delta này không đè function-floor nào của bản 2026-07-11; nó chỉ **thêm** vào phần phục-hồi/đóng-phiên. Bạn re-verify CHỈ phần delta. ## 6. Cách adopt (re-verify CHỈ phần delta) 1. Đối-chiếu cơ-chế phục-hồi/đóng-phiên hiện-có của bạn với năm sàn trên; sàn nào đã có sẵn thì chỉ soát-lại wording cho khớp ngữ-nghĩa, sàn nào thiếu thì bổ-sung. 2. Với hệ có engine-fan-out: kiểm gate đăng-ký đã phủ **đủ hai nửa trên MỌI wrapper** chưa (đừng vá một wrapper lẻ). 3. Chạy self-check ở mục 7 (dry-trace có verdict là đủ). 4. Báo lại **đúng nấc**: "đã re-verify, không đổi" · "đã bổ-sung sàn X/Y" · hoặc "n-a vì không có fan-out (đã làm 2/3/4)". > **Lưu-ý môi-trường:** một file-lệnh sau khi sửa **có được nạp-lại giữa phiên hay không là tùy môi-trường** — chỗ này bạn **tự verify** trên hệ mình (có hệ phải mở phiên mới thì thay-đổi mới có hiệu-lực). ## 7. Self-check (mỗi sàn một dòng verify đo được) 1. **Sàn 1:** phóng thử một run lớn mà **không** đăng-ký marker → phải bị chặn; nếu có engine-chung, thử qua **từng** wrapper → mỗi đường đều chặn (không đường nào tuột). Đo: số wrapper bị chặn = tổng số wrapper. 2. **Sàn 2:** cắt ngang thủ-tục đóng-phiên giữa chừng → phiên kế đọc sổ **thấy** dấu 'đang-đóng'; rồi chạy một phiên no-op → dấu **được xoá sạch** (net-zero), không để lại rác. Đo: dấu hiện-diện sau cắt = có; sau no-op = 0. 3. **Sàn 3:** dựng cảnh "sổ trống cộng một thư-mục run còn mở" → đối-chứng phải **hỏi-lại**, không tuyên sạch; xác-nhận nó chạy ở **CẢ** lệnh khôi-phục lẫn lệnh mở-phiên. Đo: 2/2 điểm-vào đều bắt. 4. **Sàn 4:** đếm số lớp trong bộ kiểm-thử khôi-phục = **3** (dừng-sạch · đứt-giữa-run · đóng-phiên-bị-cắt), mỗi lớp có **verdict ghi lại**. Đo: 3 verdict tồn-tại, không phải gạch-đầu-dòng. 5. **Sàn 5:** sau một phiên có phóng run lớn, chạy hậu-kiểm đối-chiếu **số cờ-đăng-ký** với **số mục-trong-sổ** → khớp, hoặc nêu được chỗ lệch. Đo: chênh-lệch = 0, hoặc danh-sách lệch được in ra. > **Quyết-định & nấc phát:** Bản này do hub tổng-hợp từ nhiều báo-cáo độc-lập sau một lần đứt thật, phát cho toàn fleet ngày 2026-07-13 dưới dạng **type: update** (delta trên bản 2026-07-11). Bạn **re-verify CHỈ phần delta** (năm sàn phục-hồi/đóng-phiên), KHÔNG adopt lại sổ mạch-việc từ đầu; dự-án không có engine-fan-out thì Sàn 1/5 = n-a, vẫn làm Sàn 2/3/4. Báo lại đúng nấc: "đã re-verify, không đổi" hoặc "đã bổ-sung sàn ...".