# SPEC — h22-wal-adopt — 12-07-2026 (S111)

> **Provenance (H21 note-c):** engine-propose = investigator-codebase **Fable-real single-deep-pass** (lệnh-A anh gõ `/fable-real invest và review — đề tài harness AI_INFRA apply xuống`; return SẠCH 0-garble, VERDICT `READY_WITH_NUANCES` 14 nuance N1-N14) → **lead verified + CHỈNH 3 điểm**: (1) **D2 hook = PowerShell `.ps1` variant** thay bash-nguồn — evidence xung-đột 2-context: lead đo PS-context `Get-Command bash` → `C:\WINDOWS\system32\bash.exe` WSL-HỎNG (execvpe fail) vs invest đo cmd-context `where bash` → Git-Bash đứng trước; exec-env hook thật KHÔNG xác định được trong phiên → chọn path-independent `powershell.exe` (system32, tuyệt đối); port NGUYÊN semantics sàn (per-path add + CAND commit + exit-0 mọi nhánh + 0 content/push/block); script-RUN verify tay được ngay phiên này — hook-FIRE vẫn phiên mới (N1 STAGED giữ) · (2) row #9 acceptance = `node --check` PASS (precedent S110 X7, bỏ wording mơ hồ) · (3) `.gitattributes` `*.sh text eol=lf` VẪN append (phòng-hờ .sh tương lai + fleet-parity, vô hại — repo hiện 0 file .sh) → **lead tự ghi file này** (single-writer). Worker KHÔNG tự đọc file — lead bơm nguyên văn qua args (hmw.js pattern).

## Mục 1 — Tính-năng / đề-bài

Adopt **Harness-22 WAL session-continuity** (broadcast `2026-07-11-Governance-harness-22-wal-session-continuity`, body-sha `3de0758a6377` verified): sổ `.claude/WAL.md` ≤40 dòng ghi-đè-không-append (chain-bằng-chứng `[x]/[!]/[ ]` + next 1-mệnh-lệnh + verify-trước-next, ground-truth thắng, cấm secret) · Stop-hook `.claude/hooks/wal-flush.ps1` persist-only per-path+CAND+exit-0 (**STAGED-until-verified** — hook nạp lúc khởi-động phiên, phiên này KHÔNG THỂ verify fire) + `.gitattributes` `*.sh text eol=lf` append · cặp `/pause` `/tiep` (MỘT đường recovery duy nhất) · delta session-start (**BƯỚC 0.7 MỚI** WAL-check — ngoại-lệ CHỜ duy nhất) + session-end (**§5.0** squash `wal:` trailing chưa-push + **§6.4** reset-WAL bước cuối) · WAL-cho-workflow (mandate run-trace ≥3-task/>5', taskList-snapshot vào run.md, dòng `wf:` 5-trường, harvest-liền C4 + per-agent-file + honest per-turn≠per-task N9, /tiep = relaunch-cắt-gọt + memory-pack re-derive tươi, resume-run-id = bonus SAME-SESSION-ONLY) · codify engine **PHẦN N** + CAVEAT:402 honest-update + rules §5.2 exception `wal:` + CLAUDE.md 2-dòng con-trỏ + honest (a)-(e) áp SE (e = Dropbox 2-chiều: risk index.lock + bonus .git-sync durability).

**Xong nghĩa là (DoD grep-được):** `Test-Path .claude/WAL.md`=True và ≤40 dòng · `.claude/hooks/wal-flush.ps1` chạy tay exit-0 + tạo commit `wal:` thật (script-RUN verified; hook-FIRE = phiên mới) · grep `"Stop"` `.claude/settings.json` ≥1 · grep `*.sh text eol=lf` `.gitattributes` =1 · grep `wal:` `docs/rules.md` ≥1 · grep `BƯỚC 0.7` session-start.md =1 · grep `reset --soft` session-end.md ≥1 · engine grep `PHẦN N` ≥1 + `STAGED-until-verified` ≥1 + honest (a)-(e) đủ 5 · CLAUDE.md grep `/tiep` ≥1 · workflows/README.md vùng :31 có `BẮT BUỘC` · adap-report + email AI_INFRA + mark-proposal trình anh (CHƯA stamp) · HANDOFF NEXT-anh có pilot-checklist + restart-CLI note.

## Mục 2 — Cách implement

### Quyết định thiết kế
- **D1 — WAL.md:** template rỗng nguồn §2 NGUYÊN VĂN; tracked (verify idiom N12: `git check-ignore` exit-1 = NOT-IGNORED cho re-included path `!.claude/**` .gitignore:82-83 — đừng đọc exit-code trần); ghi-đè toàn-file mỗi lần; lead single-writer nội-dung sau MỖI subtask đổi trạng-thái; dogfood ghi-chain ngay trong phiên S111 này.
- **D2 — Hook (LEAD-CHỈNH PS1):** `.claude/hooks/wal-flush.ps1` port NGUYÊN logic nguồn §3: 3 path cố định `.claude/WAL.md` + `.claude/agent-memory/` + `.claude/workflows/runs/` (N3 — GIỮ NGUYÊN, AS-6 không tăng: 2 json churn `.mfe-state`/`.archive-strikes` đã gitignored :124-125, `memory-budget.json` tracked đổi-hiếm-owner-directed; hook chỉ commit LOCAL, CI trigger lúc PUSH, squash → push-set ≡ hôm nay); **per-path `git add` từng cái** (X3 — add đa-pathspec = all-or-nothing khi 1 path vắng, bài học đắt nguồn) + CAND-list chỉ path thực-có-staged + commit `-m "wal: flush <yyyyMMddTHHmm>"` KHÔNG Co-Authored-By + **exit 0 MỌI nhánh** (try/catch bọc toàn thân; Stop-hook exit≠0 có hành vi riêng — CẤM); KHÔNG content-gen, KHÔNG push, KHÔNG block-stop, KHÔNG path ngoài list. `settings.json` CREATE MỚI (N1 — file chưa tồn tại, merge-concern moot) nested-schema: `{"hooks":{"Stop":[{"hooks":[{"type":"command","command":"powershell.exe -ExecutionPolicy Bypass -File .claude/hooks/wal-flush.ps1"}]}]}}`. **Status = STAGED-until-verified** (X5): codify + enable cùng commit nhưng CẤM claim "đang chạy" trước khi thấy commit `wal:` do HOOK sinh trong `git log` phiên MỚI (script-RUN tay ≠ hook-FIRE); honest-note (c) nguồn: nếu phiên mới không fire → thử biến-thể phẳng rồi verify lại.
- **D3 — /pause /tiep:** GIỮ tên nguồn (N11 — 16 command hiện có, 0 trùng); `.claude/commands/pause.md` = logic nguồn §4 /pause 5-bước (ngừng-spawn → flush-dirty → WAL-đúng-schema → commit ĐÍCH-DANH `wal: pause` KHÔNG `git add -A` → báo-cáo + DỪNG HẲN; bất-biến: commit TRƯỚC tuyên-bố an-toàn); `.claude/commands/tiep.md` = nguồn §4 /tiep 4-bước + nhánh `wf:` §6 (đọc WAL → không-tồn-tại/toàn-`[x]` = báo "không có mạch dở" DỪNG SẠCH → chạy TOÀN BỘ verify → lệch = TIN GROUND-TRUTH sửa WAL trước → thực-thi next; mục `wf:` → relaunch-CẮT-GỌT: đọc run-folder + taskList-snapshot, grep run-id trong log-phiên = bằng-chứng đích-danh task-đã-xong, harvest-hồi-tố partial-honest [lead verify rồi append], relaunch CHỈ task còn lại + memory-pack RE-DERIVE TƯƠI); /tiep verify đọc CẢ `git status` + disk run-folder KHÔNG chỉ git-log (N9); CẤM nạp transcript cũ; field `session:` khác phiên = BÌNH-THƯỜNG, chỉ cảnh-báo nếu `updated` mới hơn lúc phiên hiện-tại bắt đầu.
- **D4 — session-start:** **BƯỚC 0.7 MỚI** chèn sau BƯỚC 0.6 (:37-45) TRƯỚC Phase 1 READ (:47) — chặn trước read-set ~368K = token-save lớn nhất (N6); nội dung: đọc `.claude/WAL.md` → có `[!]` hoặc `[ ]` → báo "có mạch dở, `/tiep` để nối" + **CHỜ anh chọn** (ngoại-lệ CHỜ DUY NHẤT của quy-trình no-wait; chỉ là CON-TRỎ — quy-trình recovery viết ở MỘT chỗ = tiep.md); chain rỗng/toàn-`[x]` → tiếp bình-thường. GIỮ NGUYÊN số 0.5/0.5b/0.6 (X10, precedent D4 S110 chống renumber-churn).
- **D5 — session-end:** **§5.0 MỚI** ngay trước §5.1 (:111): đếm K = subject liên-tục `^wal:` từ HEAD xuống trong `git log --format=%s origin/main..HEAD` (span CHƯA-push — không bao giờ rewrite đã-push X4) → K>0 → `git reset --soft HEAD~K` gộp vào commit-chốt; K=0 → skip; biên N7: (i) push chết phiên trước → HEAD=chốt-cũ-chưa-push KHÔNG bị fold (đếm dừng ở subject ≠wal:), được push lần này; (ii) wal: sandwiched dưới chốt → GIỮ (noise chấp nhận, per nguồn §5); +1 dòng N14: "squash xong = điểm review-diff wal-paths (AS-10 backstop dời về đây, KHÔNG mất — push vẫn gated em-main)". **§6.4 MỚI** sau §6.3 (:129) TRƯỚC footer :139: reset WAL về template rỗng = bước CUỐI (hook sẽ commit lần reset thành wal-commit trailing sau turn cuối — vô-hại, phiên sau squash).
- **D6 — WAL-cho-workflow:** `workflows/README.md:31` + bảng :24 FLIP policy: mode-A vẫn cho fan-out NHỎ, nhưng **run ≥3 task HOẶC ước >5 phút = BẮT BUỘC RUN-TRACE mode (args.run — per-agent-file trong run-folder)** (sàn H22 owner nguồn đã chốt); run.md template +section `## taskList snapshot` (role · label · prompt-gist) ghi TRƯỚC launch (N10); dòng `wf:<mục-đích> run=<folder> runId=<id|pending> args=<snapshot-ref> done=<k>/<N> harvested=<yes|no|partial>` vào WAL NGAY SAU launch, lead điền runId khi có; harvest-LIỀN mỗi task xong = C4 per-turn (ĐÃ CÓ — hmw.js:99 + session-end:51) + honest-note granularity N9 (per-TURN ≠ per-TASK: `parallel()` trả cả batch cuối turn, Stop-hook cũng fire ở turn-boundary → chết GIỮA turn = returns mất, per-agent-file trên DISK là lớp cứu → /tiep đọc cả disk); memory-pack KHÔNG snapshot (X6 — re-derive tươi lúc /tiep; hiện đã compliant: pack qua args hmw.js:15); resume-by-run-id = bonus SAME-SESSION-ONLY (engine Workflow docs "same-session only" — CẤM claim cross-session, honest-note (d)).
- **D7 — Codify:** engine `docs/governance/harness-11-engine.md` **PHẦN N MỚI** (trước CAVEAT :401): schema WAL + 2 tầng ghi (lead nội-dung ⟂ hook persist) + hook ĐƯỢC làm {git add 3-path, CAND-commit `wal:`} / KHÔNG-ĐƯỢC {content-gen, push, block-stop, path-ngoài-list, exit≠0} + STAGED-until-verified + honest (a)-(e) áp SE [(a) pilot chưa chạy tại SE — kill-test/đổi-acc/hook-fire = phiên mới+anh; (b) SE 0-mark-cấm-hook, N2 mô-tả-vs-luật, thứ-tự codify-trước-enable ĐÃ tôn trọng cùng-commit; (c) nested-schema default, fallback flat nếu phiên mới không fire; (d) resume-run-id same-session-only; (e) Dropbox 2-chiều: risk index.lock thấp-nhưng-có fail-open tự-lành + bonus .git-sync = commit local chưa-push vẫn sống qua tắt-máy/đổi-máy → /pause không cần push vẫn durable]; CAVEAT :402 honest-update: thêm ngoại-lệ đích-danh "Stop-hook wal-flush persist-only (PHẦN N) — 0-content, fail-open, KHÔNG phải gate (E.3-compatible)"; `docs/rules.md` §5.2 (:213-221) append exception: "ngoại-lệ DUY-NHẤT: commit `wal:` (Stop-hook persist + /pause + WAL-reset) — máy sinh, KHÔNG Co-Authored-By, bị squash vào commit-chốt trước push (session-end §5.0)"; root `CLAUDE.md` 2 dòng con-trỏ: "Mạch việc dở nằm ở `.claude/WAL.md`; nối lại DUY-NHẤT bằng `/tiep` — kể cả khi anh gõ 'làm tiếp' bằng text thường. Không tự recovery cách khác."
- **D8 — hmw.js :9/:19 comment-only** (em-main, X7 KHÔNG đổi code): :9 meta note mode-A default → "+ mandate H22: ≥3-task/>5' PHẢI RUN-TRACE (em-main scaffold + set args.run — script no-fs không tự ép, enforcement = convention lead)"; :19 `run: OPTIONAL` → wording mandate-ref.
- **D9 — Mark H22 MỚI** trình anh cuối phiên (P4 report-before-stamp §L.b(h)) — KHÔNG tự stamp (X5-mark); đề xuất §-target: `engine PHẦN N` + `.claude/hooks/` + `session-start BƯỚC 0.7` / `session-end §5.0+§6.4` (≙ AI_INFRA H-22 CANONICAL §I4 + §H1).
- **D10 — Optional KHÔNG-block (owner-OK sau):** deploy.yml paths-ignore +`.claude/agent-memory/**` +`.claude/workflows/runs/**` (precedent `.claude/skills/**` :23) — triệt noise CI khi budget.json đổi; ghi option vào adap-report + HANDOFF, KHÔNG làm trong run này.

### Ràng buộc thật
Worker Opus edit-DIRECT trong PHẠM VI file được giao (3 lane disjoint; residual → em-main git-diff revert AS-10) · WAL.md + .gitattributes + settings.json + engine + rules + CLAUDE.md + hmw.js + adap-report + email + mark-proposal + HANDOFF = em-main · command .md + hook = restart-CLI/phiên-mới mới ăn (S27 + ENV-DEPENDENT S110) → pilot-checklist nằm HANDOFF NEXT-anh · HISTORY (session-log, archive verbatim, adap-report cũ, diary) GIỮ nguyên văn · script-RUN tay verify trong phiên ≠ hook-FIRE (phiên mới).

### Đường chết cần né
(X1) đụng `hmw-mode.on`/BƯỚC 0.5/`ultra-*` — HỆ KHÁC (HMW consent) · (X2) hook thêm content-gen/push/block-stop · (X3) add/commit đa-pathspec all-or-nothing · (X4) rewrite commit đã-push khi squash · (X5) claim hook "đang chạy" trước verify phiên mới (ghost-wire S100) · (X6) snapshot memory-pack · (X7) đổi code hmw.js (chỉ comment) · (X8) WAL append thay ghi-đè / vượt 40 dòng / chứa secret · (X9) commit script .sh trước khi .gitattributes có `*.sh` (n/a với .ps1 nhưng giữ thứ-tự: gitattributes trước) · (X10) renumber BƯỚC/§ cũ · (X11) tự stamp mark.

## Mục 3 — Checklist thực hiện

| # | Vai | Deliverable | Acceptance (đo được) |
|---|---|---|---|
| 1 | em-main | `.gitattributes` append `*.sh text eol=lf` (X9-first) + `.claude/WAL.md` template nguồn §2 | grep `*.sh text eol=lf` =1; `Test-Path .claude/WAL.md`=True; `(gc).Count` ≤40; check-ignore idiom → NOT-IGNORED |
| 2 | em-main | `.claude/settings.json` CREATE hooks-entry PS1 + STAGED-note trong engine | grep `"Stop"` =1; grep `wal-flush.ps1` =1; engine grep `STAGED-until-verified` ≥1 |
| 3 | worker-opus-1 (edit-direct, file MỚI) | `.claude/commands/pause.md` + `.claude/commands/tiep.md` (D3) | 2 file frontmatter `description:`; tiep grep "transcript"≥1(CẤM) + "ground-truth"≥1 + "wf:"≥1 + nhánh WAL-rỗng-dừng-sạch + "git status"≥1; pause grep "wal: pause"≥1 + "git add -A"≥1(CẤM-context) + trỏ /tiep |
| 4 | worker-opus-2 (edit-direct) | session-start.md BƯỚC 0.7 (D4) | grep "BƯỚC 0.7"=1; "CHỜ"≥1 vùng 0.7; git-diff KHÔNG chạm 0.5/0.5b/0.6/Phase-1+ |
| 5 | worker-opus-2 (edit-direct) | session-end.md §5.0 + §6.4 (D5) | grep "origin/main..HEAD"=1; "reset --soft"=1; "KHÔNG rewrite"≥1; "review-diff wal-paths"≥1; §6.4 sau 6.3 trước footer |
| 6 | worker-opus-3 (edit-direct, file MỚI) | `.claude/hooks/wal-flush.ps1` (D2 PS1-port) | lead chạy tay `powershell -ExecutionPolicy Bypass -File` exit-0 ×2 ca (có-delta → commit `wal:` thật; 0-delta → exit-0 im lặng); grep "exit 0"≥2 + try/catch; per-path loop + CAND; 0 push/content/block |
| 7 | worker-opus-3 (edit-direct) | workflows/README.md policy-flip :31+bảng + run.md template +`## taskList snapshot` (D6) | vùng :31 có "BẮT BUỘC" + "≥3"/"5 phút"; grep "taskList snapshot"≥1; mode-A vẫn hợp lệ cho fan-out nhỏ |
| 8 | em-main | engine PHẦN N + CAVEAT:402 + rules §5.2 + CLAUDE.md pointer (D7) | grep "PHẦN N"≥1; :402 có "ngoại-lệ"; rules grep "wal:"≥1; CLAUDE.md grep "/tiep"≥1; honest a-e đủ 5 trong PHẦN N |
| 9 | em-main | hmw.js :9/:19 comment-only (D8) | `node --check .claude/workflows/hmw.js` PASS; grep "OPTIONAL" :19 vùng = 0 (thay mandate-ref); git-diff hmw.js chỉ comment-line |
| 10 | em-main | WAL.md dogfood ghi-chain S111 + run.md update + adap-report + email AI_INFRA + mark-proposal (D9) | WAL chain ≥3 mục [x] bằng-chứng lệnh; report nêu ĐÚNG NẤC "khung dựng + STAGED + script-RUN-verified, hook-FIRE + pilot = phiên mới"; ACTIVE-MARKS CHƯA đổi; AskUserQuestion trình |
| 11 | reviewer-Fable (vai anh gán trong lệnh) | Cổng-cuối biên-test + sweep | fault-inject cây tạm: hook thiếu-1-path vẫn commit path-còn + exit-0; WAL >40-dòng bị bắt; /tiep WAL-rỗng dừng sạch; grep toàn-repo con-trỏ recovery = MỘT đường /tiep; honest a-e present; 0.5/hmw-mode/ultra-* untouched; spec-compliance từng row |
| 12 | em-main | HANDOFF pilot-checklist + restart-CLI note + STATUS blurb | NEXT-anh có: restart CLI · phiên mới verify hook-FIRE (git log `wal:`) · kill-giữa-chain → /tiep · đổi-acc · squash dry-run thật · pause-roundtrip 1 workflow THẬT |

**Map sàn-H22 → row:** ① sổ WAL ≤40/schema/ghi-đè → #1+#10 · ② hai tầng ghi (lead⟂hook persist-only 0-content fail-open per-path) → #2+#6+#8 · ③ /pause+/tiep 1-đường → #3+#11 · ④ delta mở/đóng (WAL-check · squash chưa-push · reset cuối) → #4+#5 · ⑤ WAL-workflow (snapshot args · wf: · harvest-liền · relaunch-cắt-gọt · mandate per-agent-file · trung-thực mất-mát) → #7+#8+#3(nhánh wf:) · honest (a)-(e) → #8+#10.
