# spec — hội tụ SE về khuôn bookend sister (5 vòng + session-model) — **v2 post-gate**

> 🔄 **v2 @S149:** W2 reviewer (`wf_9bf14de2-eef`, fable) trả **GO-WITH-FIXES** — 1 CRITICAL + 6 MAJOR + 4 minor, falsify 7 phép ([`sub-reviewer-hoi-tu.md`](sub-reviewer-hoi-tu.md)). Bản này đã áp TRỌN: FIX-1 tally-đơn-vị-phiên-LOGIC + freeze-dải · K5 predicate any-delta · K1 exit-semantics · M3 procedural-wording · M2 atomic-save · M4 land-trước-M6 · K6 +session-end · 3 caveat invest phục hồi (GAP-3-diary luật M9 · vết-chữ-owner K1 · budget-note đã vá on-disk) · residual dạng-ngắn 9-hit ĐÃ SWEEP (0 cả 2 dạng, positive-control lành). Diff-vs-v1 đọc bằng git.

> **Pipeline:** `/fable-clone` 8-lane ✅ → `/fable-real invest` ✅ (`wf_e9d970e1-85e`, CLEAN 256K) → **spec này** (lead verify + ghi) → `/fable-real reviewer` gate → implement.
> **Chi tiết đầy đủ:** [`sub-invest-hoi-tu.md`](sub-invest-hoi-tu.md) §① đo-hiện-trạng · §② khuôn-2-repo (verbatim file:dòng) · §④ M1-M8 + checklist. Spec này = bản CHỐT sau lead-verify; lệch nhau thì spec THẮNG.
> **Tên vai trong spec = TÊN MỚI** (rename 5 vai đã EXECUTED @S149, anh ratify; residual 0, TOTAL detector về baseline 46).

## §0 — Lead verify (đo lại trước khi ghi)

| Claim W1 | Lệnh lead | Kết quả |
|---|---|---|
| 0 script GHI `.session-counter.json`, chỉ 2 reader | `grep -rl session-counter scripts/` | ✅ đúng 2 file (detectors + nhip-no-probe), cả 2 READ-only |
| AI_INFRA bookend: cadence RETIRED, 3-wave tuần-tự, carve-out §A1 | đọc trực tiếp `session-start.md:110-125` @lượt đo bookend | ✅ verbatim khớp |
| VIPIX hybrid: pair vô-điều-kiện + deep giữ counter | đọc `:73/:151-157` | ✅ khớp |
| VIPIX có scaffold máy | `ls` = `scripts/session-scaffold.js` | ✅ |

## ① Đề-bài

**Gốc bệnh (W1 xác nhận nghi chính):** SE = **rules-đủ, máy-thiếu**. Ba việc SE làm TAY mà cả 2 sister đã script-hoá: **(1) scaffold session** (BƯỚC 0.8 = prose → quên tạo `session-3`, anh phải bắt) · **(2) tick+classify+history counter** (0 script ghi → chuỗi "đo rồi như chưa đo": backfill S146, tally view-* rơi @S148, ×27≠33) · **(3) ghi signal sau audit** (tay chép → rơi nửa `view-*`, 2 FLAG mất vĩnh viễn). Máy hiện có (C10) bắt **ABSENCE không bắt LATENESS** — tự khai trong code.

**Đích (anh chốt):** chạy như VIPIX/AI_INFRA — nghi thức 2 đầu phiên chạy bằng **máy chạm đĩa**, không bằng trí nhớ lead.

## ② Cách implement — 8 hạng mục (M1-M8) + hình

### Hình vận hành — **B (VIPIX hybrid) trước, A là đích nếu-token-cho-phép**
- **B:** cặp soi-lead (`lead-stale-auditor` + `lead-gap-auditor`) chạy **VÔ-ĐIỀU-KIỆN 2 đầu phiên-LOGIC** (bookend-hoá light); `light_every` hạ thành stats-only (GIỮ số, owner-authority, không xoá — đúng era-note VIPIX `:155`); **deep GIỮ counter** (`deep_every=15` nguyên); ring2-audit AUTO sau cặp (như hiện tại). `/pause`+`/tiep` **KHÔNG spawn vòng** (điểm-dừng-phải-RẺ, VIPIX `:76`).
- **Vì sao B trước A:** mọi ca hỏng đo được S144→S149 đều thuộc **light/vết** (0 ca do deep-chưa-tới-hạn) · B đổi schema ÍT nhất · A cần consent tăng-token riêng (hub có, SE chưa) + đảo consent-trio @S146 là quyết định owner tường minh, **không đảo bằng uỷ quyền**.
- 🔒 **Nhãn quyết định: OWNER-DELEGATED → lead-decided** (khuôn `hmw_width._ratified_by`) — anh veto thì đổi. **Trio (§2.1.9) GIỮ CONSENT** — không đụng (owner-held #12).
- **JUMP dải 3-4:** GIỮ NGUYÊN nghĩa dưới hình B (counter deep còn sống). KHÔNG tự-retire. Kèm ràng M-1 hub: **CẤM wipe-tally-khi-audit-chạy**.

### M1 — `scripts/session-scaffold.ps1` (tailor từ hub `session_scaffold.py` 169 dòng)
2 mode khớp tách-đôi @S146: **`-New`** (cấp `<N>=max+1` — CHỈ session-start gọi) ⟂ **`-Ensure`** (idempotent, tạo-nếu-thiếu — pause/tiep gọi). ts = `git log -1 --format=%cI` (không wall-clock). Template 3-block {STOCK-map · FLOW append-only · STOCK-touched}. CẤM đè `_context` tồn tại. → C10 có nguồn đo **LATENESS** (so ts-scaffold vs ts-đầu-phiên).

### M2 — `scripts/session-counter-tick.ps1` (cơ-khí-hoá `_contract` SẴN CÓ)
Input `{session,head}` → thực thi đúng contract (OR-guard idempotent · squash-benign classify 3 nhánh · fail-loud lùi/missing · append history). **GIỮ schema `class_repeat` NGUYÊN.** 🔴 **Ghi file ATOMIC** (temp + `Move-Item -Force`, khuôn hub `_save_atomic` h17:174-184 — file giữ owner-evidence, crash-mid-write = wipe không chủ đích). session-start/tiep gọi script thay prose.

**🔴 FIX-1 (CRITICAL W2) — hoà giải M2 × M-1 × M6 trên `class_repeat`:** consecutive-semantics-có-reset × cấm-wipe × bookend-2-audit/phiên = bất-khả-đồng-thời (giữ reset thì audit bookend đầu wipe dải treo {4,3,3} = đúng prose-ma hub `session-end:183`; cấm reset thì đổi nghĩa ngầm). Hoà giải 3 vế:
1. **Đơn-vị tally = phiên-LOGIC:** 2 audit bookend (@start+@end) của cùng 1 phiên gộp thành **MỘT quyết định/class/phiên** — fire nếu fire ở ≥1 đầu; reset chỉ khi clean ở **CẢ HAI** đầu; áp đúng 1 lần (khớp đơn-vị sID hub h17:285-288).
2. **Reset tối đa 1 lần/phiên** — thi hành procedural trong M3 (đọc `last_audit`/history), **KHÔNG chạy ở phiên land-M6 đầu tiên**.
3. **Freeze dải treo tường minh:** khi M6 land, `counts` hiện tại {gap-owner-specifics 4 · gap-decision-sunk 3 · gap-carry-dropped 3 + view-residual-asym∈{0,3}} **ĐÓNG BĂNG** (ghi note `_frozen_until_owner` cạnh map — map vẫn chỉ chứa SỐ) cho tới khi **anh xử câu JUMP dải 3-4**. Máy mới KHÔNG được reset nợ cũ — nợ này của owner, không của máy.

### M3 — `scripts/h24-signal-write.ps1`
Ghi tally sau audit: input = bảng `FLAG→class` từ vai → update `class_repeat` + `last_audit` **NGAY khi cặp trả**. Max-1-quyết-định/class/phiên = **PROCEDURAL** (check `last_audit`/history trước khi ghi — 🔴 W2 bắt: chữ "structural" cũ SAI schema, counts-map là số trần không tự chặn được gì; đừng để chữ đánh lừa implementer). Class phải ∈ enum ĐÓNG — ngoài enum ⇒ exit≠0. Atomic-save như M2.

### M4 — FLAG-khuôn + detector C11
Buộc mỗi vai H24 ghi `## FLAG-N — \`class\` — SEV` vào `runs/<id>/sub-*.md` ngay khi có FLAG (khuôn `sub-lead-view-S146.md` đã dùng tốt — vòng S148 bỏ khuôn mất 2/9 FLAG). C11 (INFORM-only) soi run-folder H24 thiếu class-tag.

### M5 — closeout-sentinel (tailor VIPIX `:153`)
Positive-control **lịch sử THẬT**: chạy trên S146-S148 phải FLAG (closeout thiếu ghi số), S140/S143 phải PASS.

### M6 — bookend-hoá call-site (theo hình B)
`session-start §2.1.8`: cặp soi-lead spawn vô-điều-kiện (bỏ cổng OVERDUE cho light; giữ OVERDUE deep) + PIN đích-danh run-folder cho ring2-audit (cấm glob-latest — carve-out §A1: song-song/glob = chấm bản cũ = **báo PASS sai, tệ hơn không chấm**). `session-end §L.b(j)` đối xứng.

### M7 — eval USE-side: wire `applied-eval-nokey.ps1` (đang ghost-wire, selftest 3/3 PASS)
Call-site @session-end (sau verdict, ngoài cửa sổ đo) + nhãn `APPLIED/DORMANT(≠MISS)/chờ-judge` vào luật sống + caveat "% = FLOOR không ceiling" **NẰM TRONG payload** + negative-control giữ fail-closed. Đóng DEFER C14-2.4.

### M8 (optional, sau cùng) — V5 counter
Máy đếm "1 nhãn đã-đo bị chặn/cho qua trong phiên" (row-18). Rẻ nhất: reviewer-gate ghi 1 dòng vào run-folder khi measured-label gate fire; detector đếm.

### M9 (phục hồi từ invest C-V2(4) — W2 bắt spec v1 CẮT MẤT) — luật diary-seed on-behalf
GAP-3 đã tái **×4** (S124→S132 · S137→S140 · S146→S148 · ring2-audit rỗng @S149): vai chạy xong mà diary không ai seed ⇒ lần sau vào mù. **Luật:** mỗi lần vai INFORM-only chạy có kết quả VERIFY được → lead APPEND diary on-behalf **TRONG CÙNG PHIÊN** (khuôn B3, tiền lệ retro-harvest S132 + seed ring2-audit @S149). Wire thành 1 dòng bắt buộc trong `session-end` harvest-gate + C11 soi run-folder-có-sub-MD-mà-diary-vai-0-delta.

### Thứ tự land (W2 sửa: M4 TRƯỚC M6 — M3 cần vai đưa FLAG-class làm input; land M6 trước M4 = vòng bookend đầu lặp đúng lỗi S148 mất class-tag):
**M1+M2+M3 (bộ máy) → M4 (khuôn FLAG+C11) → M6 (call-site) → M5 (sentinel) → M7 → M9 → M8.** K1-K5 không chờ gì (đã chọn B).

## ③ Checklist

| # | Vai | Deliverable | Acceptance ĐO ĐƯỢC |
|---|---|---|---|
| K0 | ✅ em-main | rename 5 vai | residual 0 · TOTAL 46 · node-check OK — **DONE @S149** |
| K1 | implementer (hmw) | M1 scaffold-CLI | `-Ensure` ×2 = idempotent **exit 0 no-op** (khuôn hub `:144-151` — 🔴 W2 bắt v1 tự-mâu-thuẫn: lần 2 của -Ensure LUÔN rơi ca _context-tồn-tại, không thể vừa idempotent vừa exit≠0) · **`-New` collision** (`<N>` đã tồn tại) → **exit≠0 + không ghi** · `-New` khi max=3 → tạo `session-4` · **+ vết-chữ-owner** (phục hồi invest-K1): quyết định owner liên quan phải có ≥1 hit trên bề-mặt bền (MARKS/ledger), không chỉ nhãn |
| K2 | implementer | M2 tick-CLI | fault-inject 4 ca: cùng-label→NO-OP · HEAD-mới+label-mới→+1 · counter-lùi→exit≠0 FAIL-LOUD · squash-benign→history+1 dòng đi tiếp · **+ atomic:** kill-giữa-ghi (mô phỏng: ghi temp rồi bỏ move) → file gốc NGUYÊN VẸN |
| K3 | implementer | M3 signal-CLI | input 2 FLAG cùng class CÙNG phiên → tally +1 đúng 1 (procedural check) · class ngoài enum → exit≠0 · **reset bị chặn khi `_frozen_until_owner` hiện diện** |
| K4 | implementer | M4 khuôn + C11 | inject run-folder có FLAG không class-tag → C11 FLAG; đủ tag → im · **+ C11 soi diary-0-delta (M9)** |
| K5 | implementer | M5 sentinel | 🔴 predicate = **delta BẤT KỲ dưới `agent-memory/<role>/**`** (W2 đo đĩa: closeout S140 `b146e2b` chỉ chạm `archive/*.gist.md`, KHÔNG MEMORY.md — predicate MEMORY.md-only sẽ FLAG OAN S140). Ghi deviation-vs-VIPIX-`:153` tường minh. Positive-control lịch sử: **S146/S147/S148 FLAG (0-delta mọi-path)** · **S140 (archive-only) + S143 (đủ MEMORY.md) PASS** |
| K6 | em-main | M6 call-site (hình B) | grep **CẢ session-start VÀ session-end** (W2: v1 chỉ đo nửa deliverable): cặp soi-lead 0 điều-kiện OVERDUE-light · deep giữ `deep_every` · PIN path đích-danh hiện diện ở cả 2 đầu |
| K7 | implementer | M7 wire eval-use | call-site ≥1 trong session-end · selftest vẫn 3/3 · chạy thật 1 lượt ra nhãn {APPLIED/DORMANT} + caveat floor trong output |
| K8 | reviewer (W2) | gate spec này | verdict + falsify ≥3 TRƯỚC implement |
| K9 | em-main | STATUS/HANDOFF/engine-doc sync sau land | detector TOTAL không tăng · C10 vẫn im |

## §4b — RESIDUAL KHAI THẲNG (W2 minor — đích "chạy như sister" KHÔNG đạt trọn ngay cả sau M1-M9)
- **Trio vẫn CONSENT** trong khi CẢ 2 sister chạy trio vô-điều-kiện (AI_INFRA `session-end:170-172` · VIPIX `:80`) — GIỮ đúng owner-held #12, **không lờ**: đây là khoảng cách CÒN LẠI có chủ đích, anh chốt #12 thì đóng nốt.
- **Vết-skip trio ghost-wire** ([M4]-WAL `trio: skipped` — 0 commit toàn lịch sử) — M9+C11 phủ nhánh diary, nhánh vết-skip WAL vẫn sống; đóng khi anh chốt #12 (bookend-hoá trio thì luật vết-skip tự chết).
- **Lũy-kế garble ×27≠33** — sổ bền đã ghi sự-kiện S148/S149, tổng chốt @closeout (đúng bài học (c) của chính sổ).
- **`light_every=6` owner-ratified (`_owner_ratified` e50a4bd0) bị hạ thành stats-only dưới uỷ-quyền** — W2 đòi 1 câu tường minh: anh đã ratify 6/15/3 làm CADENCE; hình B giữ SỐ nhưng đổi VAI TRÒ của `light_every` (cadence→stats, khuôn era-note VIPIX `:155` "GIỮ làm stats owner-authority, KHÔNG xoá"). **Anh veto thì light quay lại counter-gate.**

## §4 — KHÔNG CHẮC (giữ từ W1, lead không xoá)
1. Token-cost hình B chưa có số — cặp soi-lead mỗi phiên ≈ 2 spawn (đo được sau 2-3 phiên; nếu vượt kỳ vọng anh → revisit).
2. VIPIX `session-end` chưa đọc trực tiếp (W1 khai) — M6 phía @end tailor từ AI_INFRA §4.6 + đối xứng @start.
3. Nghĩa "sai mã" của anh — em đọc = lỗi thủ tục session-model; nếu anh còn ý khác (mã nguồn?) thì nói.
4. Class-map 11⟂12 với hub: **DEFER có chủ đích** (không 1:1; tally đang arm; đổi key giữa chuỗi = gãy). Ghi trong MARKS chú-thích S149.
5. `_end` sai đơn-vị (#20 HANDOFF) — thuộc session-model nhưng là **owner-LUẬT điều kiện đóng** — vẫn chờ anh, M1 không tự quyết.
