Compare commits
7 Commits
5f6c3becfb
...
932d6078de
| Author | SHA1 | Date | |
|---|---|---|---|
| 932d6078de | |||
| 24483935cb | |||
| 6da7c8898d | |||
| 3a1bb25056 | |||
| de4f37930a | |||
| 95da1bdbf6 | |||
| 581544200b |
@ -1,12 +1,34 @@
|
|||||||
# WAL — auto-generated, không sửa tay
|
# WAL — auto-generated, không sửa tay
|
||||||
updated: — | session: — | branch: —
|
closing: S148 @20260724T1804
|
||||||
goal: (trống — không có mạch dở)
|
updated: 20260724T1630 | session: S148 | branch: main
|
||||||
|
goal: /tiep nối S147 → re-stamp HANDOFF → wire /check-email 4 cửa → STAGE-2 10 thư fan-out → migrate session-model sang FORM HUB
|
||||||
|
|
||||||
chain:
|
chain:
|
||||||
(rỗng)
|
[x] /tiep §0 Sàn-3 5/5 · verify KHỚP 3/3 · H24 tick 21→22 CLEAN · NHIP-NO light 5/6 deep 5/15 ok
|
||||||
|
[x] re-stamp HANDOFF: #1 ĐÓNG (trio đã chạy @S144) · #3 anh chốt (a) + 6→15 vai · #2 đổi trục sang sự-kiện-phiên · +4 mục mới (13)–(16)
|
||||||
|
[x] wire `/check-email` 4 CỬA + 2 CHẾ-ĐỘ (DÒ ~5ms ở pause/tiep ⟂ KÉO ở bookend) — vá vi-phạm khoản-3 BINDING hub `goi-chot`
|
||||||
|
[x] sửa chẩn sai: `outbox/all` KHÔNG phải việc /check-email (đó là /adap-apply); kẽ THẬT ở NHỊP → DÒ 2 kênh + định-tuyến
|
||||||
|
[x] STAGE-2: 10 thư fan-out verify 2 tuyến 10/10 sạch → move `inbox/` → `inbox/ai_infra/`; backlog root = 0
|
||||||
|
[x] KHÔNG làm 2 việc (đúng): +17 dòng `_index` (sổ ĐÚNG — fan-out cố ý loại; 22/22 directed đủ) · copy 51 legacy (adap-apply đọc tại chỗ)
|
||||||
|
[x] **session-model → FORM HUB** (anh chốt "đối ứng đúng chính xác"): `_context-s-2.md` + `_pause-1.md` + `_tiep-1.md`; gỡ 2 file form cũ (chống đếm đôi)
|
||||||
|
[x] Sàn-3 ⑤ ORPHAN-L: DUAL-ACCEPT hub+legacy · `_end`/`closed.md` ĐÓNG TRỌN thư-mục (vá lệch doc-vs-máy sống từ S146) · fault-inject **10/10 hai chiều** + anti-Goodhart
|
||||||
|
[x] 4 lệnh đồng-bộ form (`pause §2.6` · `tiep §2.6+§0` · `session-start 0.8(a-bis)` · `session-end 6.3-bis` `closed.md`→`_end`)
|
||||||
|
|
||||||
next: (trống)
|
[x] **anh chốt "1,2 làm đi ko cần hỏi hub"** → port `/snapshot` + 2 script:
|
||||||
|
· `.claude/commands/snapshot.md` (port hub) · `.claude/templates/session-context-template.md`
|
||||||
|
· `scripts/session_scaffold.py` (near-verbatim, idempotent — test dry-run 2 ca)
|
||||||
|
· `scripts/session_ctx.py` **TRIMMED CÓ KHAI** (chỉ `machine-block`+`secrets-sweep`; KHÔNG port jsonl/overhead/cap-getter — chưa có caller)
|
||||||
|
· `_snapshot-1.md` THẬT ghi bằng chính lệnh vừa port (chống ghost-wire)
|
||||||
|
· secrets-sweep fault-inject 2 chiều CÓ RĂNG + **nổ THẬT lượt đầu = citation-trap** → sửa CHỮ, KHÔNG nới detector
|
||||||
|
· auto-snap @`/pause §2.6(D)` — đo TRƯỚC khi wire: ròng ~64ms
|
||||||
|
[x] carry ĐÓNG: #15 snapshot-cmd · #17 pause-autosnap · #16 **nửa** (STOCK xong · `session_ctx_kb` reader VẪN hở, cố ý)
|
||||||
|
|
||||||
verify: (trống)
|
next: (chờ anh) — commit hay chưa; 13 mục bảng số còn treo
|
||||||
|
|
||||||
carry: (sống ở docs/HANDOFF.md — 20 carry MỞ, đã re-stamp + gắn tag [carry:*] @S146)
|
verify:
|
||||||
|
for d in .claude/sessions/session-*/; do { [ -f "$d/_end" ] || [ -f "$d/closed.md" ]; } && continue; p=$(( $(ls "$d"_pause-*.md 2>/dev/null|wc -l) + $(ls "$d"pause-*.md 2>/dev/null|wc -l) )); [ "$p" -eq 0 ] && continue; r=$(( $(ls "$d"_tiep-*.md 2>/dev/null|wc -l) + $(ls "$d"resume-*.md 2>/dev/null|wc -l) )); [ "$p" -gt "$r" ] && echo "FLAG $d"; done # expect: rỗng
|
||||||
|
ls .claude/sessions/session-2/ # _context-s-2.md _pause-1.md _tiep-1.md
|
||||||
|
ls broadcasts/inbox/*.md # chỉ README.md (backlog 0)
|
||||||
|
git status --porcelain | wc -l # 14 (chưa commit — chờ anh)
|
||||||
|
|
||||||
|
carry: (sống ở docs/HANDOFF.md — 20 carry + bảng số 16 mục, bảng 16 mục, ĐÓNG 3 (#1 #2 #3) ⇒ còn **13** chờ anh: 4·5·6·7·8·9·10·11·12·13·14·15·16. carry(11) tools-whitelist thu hẹp còn vế chờ-hub)
|
||||||
|
|||||||
@ -24,5 +24,14 @@ H24 §2(1) vai-GAP — soi CÁI BỊ THIẾU trong cái LEAD surface (việc r
|
|||||||
|
|
||||||
- **S143 deep #1 [vào bằng `/tiep`, owner "OK làm hết đi"; 3 lane: reviewer + 2 vai H24]:** **3 FLAG + 3 INFORM.** ⭐ FLAG-1 MED-HIGH `gap-carry-dropped`: `[carry:session-model-adopt]` VẮNG khỏi khối `Carry MỞ re-stamp (13)` (HANDOFF:6) nhưng còn sống ở NEXT anh (:7 mục 8) + KHÔNG có dòng `✅ ĐÓNG`. **Số-học lộ ra: 13−1(đóng dangling-head)+2(🆕)=14, khai 13**; union distinct tag :6+:7 = 15 − dangling = **14 carry sống**. Nguy hiểm vì tổng KHÔNG ĐỔI (13→13) nên trông như đúng, và closeout re-stamp đọc TỪ khối carry mới nhất ⇒ mất hẳn lượt sau. **MÁY CORROBORATE mù:** H24-2 in `[ok] session-model-adopt streak=3` (detector grep tag trong NEXT-segment, KHÔNG đọc tư-cách thành-viên ledger) ⇒ chứng sống cho §2(1) "máy im là ĐÚNG". ⭐ FLAG-2 MED `gap-owner-specifics`: 2 lượt gật — lượt-1 "OK làm đi" 6 mục ghi ĐỦ (HANDOFF:5 + WAL:16/17), lượt-2 "OK làm hết đi" **4 mục chỉ neo được 2** (run.md:3 "2 việc"; WAL/HANDOFF/STATUS = 0 dòng; WAL mtime 12:31 < run-folder 12:55 ⇒ mạch H22 chưa có dòng nào cho lượt-2). ⭐ FLAG-3 MED-HIGH `gap-decision-sunk`: **tìm được NGUỒN CAM-KẾT gọn** = `spec-adap-dot-9-10:68` khối *"Chờ-anh (không block implement)"* 3 mục → grep 9 token × 4 bề-mặt owner (HANDOFF/STATUS/WAL/ACTIVE-MARKS) = **0/0/0/0**: (1) ranh refine⟂lead-omission ratify (ĐÃ WIRE `harness-refine.md:22-30` TRƯỚC khi ratify) · (2) 5-câu session-model chỉ 1/5 lên NEXT anh#8, `session_ctx_kb`/Q4 van-ngưỡng 0-hit · (3) consent-form trio dài hạn. **Đòn bẩy phân-biệt bỏ-sót⟂chủ-động-gác: ngưỡng song sinh `pull_warn_days` CÙNG PHIÊN được cấp carry#12 + NEXT anh#2 với đúng lý-lẽ "quyền anh", còn `session_ctx_kb` cùng hình thì 0 cả hai** ⇒ bất-đối-xứng = omission. INFORM: (1) carry-age FIRE 3 (luyke 7·freeze 9·hook 13 ≥M6) đều owner-held NEXT anh ⇒ INFORM; coverage-gap S140 còn nguyên (máy đo 6/14 carry) — repeat không báo mới. (2) `/tiep` KHÔNG có bước §2.1.6 ⇒ ngân-sách hot-feed **bất-khả-đo** phiên `/tiep`; backfill 210K owner-set S115 không vết ở 2 log closeout gần nhất. (3) 3/3 sub garble #53 phiên này = 0 hit đĩa, mà bề-mặt đang quảng-cáo "0-garble" (S142); sổ đếm class dừng "×20 qua S118" commit cuối 2026-07-15 ⇒ rủi ro biến mất CÓ TIỀN-LỆ; **KHÔNG xếp được vào enum ⇒ verbatim + xin owner mở enum, CẤM bịa**. Honest-zero: `gap-underfill` 0 có lý-do + ghi rõ ứng-viên "spawn-prompt mỏng vs 60K" đã cân-nhắc RỒI BÁC. class_repeat: carry-dropped 0→1 · owner-specifics 1→2 · decision-sunk 0→1, jump@3 KHÔNG chạm. Tag `[s143, deep-1, force-fire-som, count-unchanged-masks-drop, cho-anh-block-sunk, enum-extend-request]`
|
- **S143 deep #1 [vào bằng `/tiep`, owner "OK làm hết đi"; 3 lane: reviewer + 2 vai H24]:** **3 FLAG + 3 INFORM.** ⭐ FLAG-1 MED-HIGH `gap-carry-dropped`: `[carry:session-model-adopt]` VẮNG khỏi khối `Carry MỞ re-stamp (13)` (HANDOFF:6) nhưng còn sống ở NEXT anh (:7 mục 8) + KHÔNG có dòng `✅ ĐÓNG`. **Số-học lộ ra: 13−1(đóng dangling-head)+2(🆕)=14, khai 13**; union distinct tag :6+:7 = 15 − dangling = **14 carry sống**. Nguy hiểm vì tổng KHÔNG ĐỔI (13→13) nên trông như đúng, và closeout re-stamp đọc TỪ khối carry mới nhất ⇒ mất hẳn lượt sau. **MÁY CORROBORATE mù:** H24-2 in `[ok] session-model-adopt streak=3` (detector grep tag trong NEXT-segment, KHÔNG đọc tư-cách thành-viên ledger) ⇒ chứng sống cho §2(1) "máy im là ĐÚNG". ⭐ FLAG-2 MED `gap-owner-specifics`: 2 lượt gật — lượt-1 "OK làm đi" 6 mục ghi ĐỦ (HANDOFF:5 + WAL:16/17), lượt-2 "OK làm hết đi" **4 mục chỉ neo được 2** (run.md:3 "2 việc"; WAL/HANDOFF/STATUS = 0 dòng; WAL mtime 12:31 < run-folder 12:55 ⇒ mạch H22 chưa có dòng nào cho lượt-2). ⭐ FLAG-3 MED-HIGH `gap-decision-sunk`: **tìm được NGUỒN CAM-KẾT gọn** = `spec-adap-dot-9-10:68` khối *"Chờ-anh (không block implement)"* 3 mục → grep 9 token × 4 bề-mặt owner (HANDOFF/STATUS/WAL/ACTIVE-MARKS) = **0/0/0/0**: (1) ranh refine⟂lead-omission ratify (ĐÃ WIRE `harness-refine.md:22-30` TRƯỚC khi ratify) · (2) 5-câu session-model chỉ 1/5 lên NEXT anh#8, `session_ctx_kb`/Q4 van-ngưỡng 0-hit · (3) consent-form trio dài hạn. **Đòn bẩy phân-biệt bỏ-sót⟂chủ-động-gác: ngưỡng song sinh `pull_warn_days` CÙNG PHIÊN được cấp carry#12 + NEXT anh#2 với đúng lý-lẽ "quyền anh", còn `session_ctx_kb` cùng hình thì 0 cả hai** ⇒ bất-đối-xứng = omission. INFORM: (1) carry-age FIRE 3 (luyke 7·freeze 9·hook 13 ≥M6) đều owner-held NEXT anh ⇒ INFORM; coverage-gap S140 còn nguyên (máy đo 6/14 carry) — repeat không báo mới. (2) `/tiep` KHÔNG có bước §2.1.6 ⇒ ngân-sách hot-feed **bất-khả-đo** phiên `/tiep`; backfill 210K owner-set S115 không vết ở 2 log closeout gần nhất. (3) 3/3 sub garble #53 phiên này = 0 hit đĩa, mà bề-mặt đang quảng-cáo "0-garble" (S142); sổ đếm class dừng "×20 qua S118" commit cuối 2026-07-15 ⇒ rủi ro biến mất CÓ TIỀN-LỆ; **KHÔNG xếp được vào enum ⇒ verbatim + xin owner mở enum, CẤM bịa**. Honest-zero: `gap-underfill` 0 có lý-do + ghi rõ ứng-viên "spawn-prompt mỏng vs 60K" đã cân-nhắc RỒI BÁC. class_repeat: carry-dropped 0→1 · owner-specifics 1→2 · decision-sunk 0→1, jump@3 KHÔNG chạm. Tag `[s143, deep-1, force-fire-som, count-unchanged-masks-drop, cho-anh-block-sunk, enum-extend-request]`
|
||||||
|
|
||||||
|
## S146 audit #4 — CHƯA CÓ ENTRY (GAP-3 lần 3, con-trỏ tạm @S148)
|
||||||
|
|
||||||
|
- **S146 (2026-07-22/23) light force-fire P=8, chạy THẬT** — bằng-chứng đĩa `.claude/workflows/runs/2026-07-22-S145-apply-hub-answers/sub-lead-omission-S146.md` (20.043B) + `sub-lead-view-S146.md` + `sub-h24-audit-S146.md`; HANDOFF:10 khai "3 vai, cả 3 garble #53, 7 FLAG → vá hết". **Vai tao ra 4 FLAG**: `gap-owner-specifics` (tally 2→**3 = CHẠM JUMP**) · `gap-incident-unrecorded` (fire lần đầu từ khi owner mở enum @S143) · `gap-decision-sunk` (1→2) · `gap-carry-dropped` (1→2); carry-aged 0-fire (3 hit đều owner-held ⇒ INFORM) · underfill 0 (bất-khả-đo). **Diary này KHÔNG có entry S146** ⇒ GAP-3 tái-diễn lần 3 (S137 → S140 phát-hiện; nay S146 → S148 phát-hiện). Đọc verbatim ở file trên trước khi kết-luận repeat. Tag `[s146, backfill-pointer, gap-3-lan-3]`
|
||||||
|
|
||||||
|
## S148 light-audit #5 (2026-07-24, counter 22, force-fire P=1 closeout gộp; light 5/6 chưa tới hạn tự-nhiên)
|
||||||
|
|
||||||
|
- **S148 [phiên rất dài, 9 chỉ-thị owner nối nhau; vào bằng `/tiep`]: 4 FLAG + 4 INFORM + 2 honest-zero.** ⭐ FLAG-1 MED-HIGH `gap-decision-sunk` — **bảng OWNER-GATED `O-1…O-7`** (`spec-adap-dot-11-22-07-2026-v2.md:88-97`, dựng @S144): grep 8 token × 5 bề-mặt owner (HANDOFF/STATUS/WAL/ACTIVE-MARKS/migration-todos) **+ toàn bộ `docs/changelog/sessions/`** ⇒ **O-2** (posture trục-sâu + trần tổng-lượt) **O-3** (gộp hay tách vai-KIỂM 3 vòng còn thiếu — "quyền anh") **O-7** (trần width `hmw.js:115`=16 soft; "số = owner-SỐ, throw-hay-LOUD-skip = owner-LUẬT") = **0/0/0/0/0 + 0 sessions**. Đòn-bẩy bất-đối-xứng (chống đọc nhầm thành owner-giữ): CÙNG bảng đó O-4→NEXT anh#10, O-5→NEXT anh#14 (mới lên @S148, **muộn 4 nhãn**), O-1+O-6 đã chốt số vào `memory-budget.json` ⇒ **4/7 có đường về owner, 3/7 câm hoàn toàn**. Im **5 nhãn phiên** (S144→S148). Đây là **repeat cấu-trúc** của FLAG-3@S143 (khối "Chờ-anh" `spec-adap-dot-9-10:68`): vá lần trước là **kéo tay 3 mục lên NEXT anh**, KHÔNG dựng nghi-thức quét bảng owner-gated ⇒ bảng MỚI sinh @S144 chìm y hệt. ⭐ FLAG-2 MED `gap-carry-dropped` — chỉ-thị (6) owner "OK làm đi" **3 việc**, lead làm 1 (STAGE-2 10 thư) + **TỪ CHỐI 2** (+17 dòng `_index` · copy 51 file legacy) có lý-do; vết DUY-NHẤT ở `.claude/WAL.md` dòng `[x] KHÔNG làm 2 việc (đúng)…`, **0 hit HANDOFF/STATUS/session-log**. `/session-end §6.4` **reset WAL** ⇒ cả việc owner-giao lẫn lý-do-từ-chối **bốc hơi** — đúng cơ-chế mà HANDOFF:13 (bắt @S146) dựng khối carry để chống. ⭐ FLAG-3 MED-HIGH `gap-decision-sunk` — **verdict JUMP của chính vai tao @S146 chìm**: `sub-lead-omission-S146.md:131` in "gap-owner-specifics 2→**3** 🔴 CHẠM JUMP … quyết kéo nhịp là của em-main/owner", nhưng `.claude/governance/.session-counter.json` **không có entry S146**: `history[]` nhảy S145→S147→S148, `last_audit` vẫn 17/17, `class_repeat.gap-owner-specifics` vẫn **2**. ⇒ ghi-chú tick S148 kết-luận *"cao nhất = 2 < 3 ⇒ không jump"* **đọc từ sổ tiền-S146**; jump ĐÃ fire mà không ai biết. (Số 2-vs-3 = `view-stale-count` → lead-view; **cái của tao = quyết-định "có kéo nhịp không" không tồn tại ở bất-kỳ sổ nào**.) ⭐ FLAG-4 xem dòng kế. Tag `[s148, owner-gated-table-sunk-repeat, refusal-only-in-wal, jump-verdict-sunk]`
|
||||||
|
- **S148 (tiếp) — FLAG-4 + INFORM + honest-zero + số đo jump.** ⭐ FLAG-4 MED-HIGH `gap-owner-specifics`: chỉ-thị (4) owner nói *"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**"*. Verbatim CÓ được chép (HANDOFF:17 mục(2) ×1 · `check-email.md` ×2 · `tiep.md` ×1) ⇒ **KHÔNG phải mất chữ**; cái mất là **PHẠM-VI**: câu đó là một **định-nghĩa đơn-vị phiên**, mà `docs/governance/session-model-se-draft.md` = **0 hit** (đây đúng là bản anh sắp được hỏi duyệt VC-1/2/3 = NEXT anh#8) và `session-end.md §6.3-bis` = **0 hit** (bước ghi `_end` **FROZEN ghi-một-lần** cho `<N>` đang mở, **không có điều-kiện "phiên-LOGIC thực sự khép"** dù chính header trích manifest câu đó) ⇒ mỗi cửa-sổ closeout đóng băng phiên-logic ⇒ mô-hình anh vừa phát-biểu **không thể thành hiện-thực**; NEXT anh#11 vẫn liệt "map N↔L" như **câu hỏi MỞ** dù anh vừa trả lời một phần. Ghi thành quyết-định **nhịp-email**, mất vế **session-model**. **INFORM:** (1) carry-age đọc detector H24-2 (KHÔNG tự tính): 66 segment/19 carry-line, FIRE 3 = `uat-s134-luyke` 7 · `uat-s133-budget-freeze` 9 · `hook-vs-budget-cap` 13 (≥M6), **đều owner-held NEXT anh#4/#5/#7 ⇒ INFORM**. 🔴 Datum MỚI: **y HỆT bộ ba 7/9/13 của S143** ⇒ qua **5 nhãn phiên** thước-tuổi **đứng yên** — coverage-gap (S140 INFORM-2) chưa vá, nay có bằng-chứng thước không nhích. (2) Số-học carry **SẠCH**: union distinct line12+16+17 = **21** = 14 sống + 6 mới + 1 đã-đóng(`dangling-head`) ⇒ khai "TỔNG 20" ĐÚNG; @S148 đóng #15+#17, #16 nửa ⇒ **18 sống**; **không carry nào biến mất không tiếng động** (khác S143). (3) 10 thư fan-out tồn 5 ngày: 4 thư BINDING đã có C14-per-khoản @S144, **5/6 thư còn lại** (`cost-lens`·`depth-axis`·`depth-cost`·`danh-gia-3-goc`·`eval-cua-eval`) = **0 hit** trên 5 sổ bền (chỉ có vết trong run-folder = artifact), thư thứ-6 `auto-toan-vong` có vết thật (memory-budget ×2); `_index` **cố-ý loại fan-out** ⇒ không có dòng sổ nào ⇒ tín-hiệu "đã xử" duy nhất = **move thư-mục + 'backlog root = 0'**. KHÔNG nâng thành FLAG (chưa có bằng-chứng 5 thư đó chứa khoản BINDING) — INFORM + đề-nghị check rẻ. (4) `_end` **chưa từng ghi** (disk: chỉ `session-1/closed.md` legacy) ⇒ tao **BÁC** ứng-viên flag: `session-end §6.3-bis:373` sẽ ghi ngay closeout này. **Honest-zero:** `gap-incident-unrecorded` **0** — garble S146×3 + S147×3 **CÓ** vết bền (error-ledger nêu đích-danh + HANDOFF:5/:10); tally `×25 qua S143` đứng yên = **số cũ ⇒ view-* turf**, không phải turf tao (ranh S143 ghi rõ). `gap-underfill` **0 bất-khả-đo** — `/tiep` vẫn **0 bước %-print ngân-sách** (grep `2.1.6|%-print|tier1|ngân-sách` = 0) ⇒ repeat S143, không báo mới. 🔴 **SỐ ĐO jump (không phải đề-nghị)** — sổ `.session-counter.json` đứng ở giá-trị tiền-S146; **đo lại từ verbatim S146 + phiên này**: `gap-decision-sunk` S143→S146→S148 = **3 CHẠM** · `gap-owner-specifics` S140→S143→S146→S148 = **4 VƯỢT** · `gap-carry-dropped` S143→S146→S148 = **3 CHẠM** · `gap-incident-unrecorded` S146 fire → S148 không = reset 0 · `gap-carry-aged` INFORM không tính. jump=3 ⇒ **3 class chạm/vượt**; quyết kéo nhịp là của em-main/owner. Tag `[s148b, session-model-specific-narrowed, age-metric-frozen-5-labels, carry-arith-clean, jump-3-class]`
|
||||||
|
|
||||||
## 🔄 Curate trigger
|
## 🔄 Curate trigger
|
||||||
- Hook-cap >17.1KB → archive L2 `archive/<period>.md` (move-not-cut + seal-verify) + `_INDEX.md` pointer. Entry ≤1.5K.
|
- Hook-cap >17.1KB → archive L2 `archive/<period>.md` (move-not-cut + seal-verify) + `_INDEX.md` pointer. Entry ≤1.5K.
|
||||||
|
|||||||
@ -15,5 +15,4 @@ H24 §2(1) vai-STALE — soi VIEW LỆCH SOURCE của cái LEAD surface. Class
|
|||||||
- **S140 (2026-07-18) light-audit #3 [counter 14 · force-fire-debt P=3 wal:pause S139 · owner-consent]:** Machine baseline TOTAL 45 (=S139, 0 flag mới) — chỉ soi ngữ-nghĩa. **1 FLAG (view-stale-status, LOW):** `HANDOFF.md:8` NEXT-em còn liệt "spawn-probe reviewer 5-nhãn … nâng `624c378d` verified-pending→executed-runtime" như việc PHẢI-LÀM, nhưng SOURCE = adap-report `624c378d`:9 ĐÃ nâng **executed-runtime @S140** (probe agentId a56dcf6da0425e86c, 17s, 0-garble). To-do xong mid-session, chờ closeout clear. class_repeat view-stale-status 1(S137)→2 (jump@3 chưa chạm). **VERIFIED-CLEAN (chống false-alarm):** (a) report `624c378d`:9 tự-thân=executed-runtime ĐÚNG = nguồn-chân-lý nấc; (b) `_index.md:48`="processed" = email-layer KHÔNG phải adap-nấc → 0 stale; (c) `HANDOFF:5`+`STATUS:462` "624c378d=verified-pending" = narrative-recap S138-S139 đóng-băng-đúng-thời-điểm → KHÔNG flag (trap#3 frozen); (d) **3b model-flip S140→Fable**: canonical `STATUS §Sub-agents:450` dừng enumerate ở flip-8/S107 CÓ CHỦ-ĐÍCH (S106 anti-churn) ⇒ 0 re-stamp; 3 derived (agents/README:5 · session-start:37/41 · session-end:113) point-not-enumerate, 0 stale-model literal → NO FLAG. **Lesson:** nấc-adap advance ở phiên KẾ (S140) trong khi narrative-recap kẹt ở phiên GHI (S139) = staleness sống ở forward-pointer (NEXT-em), KHÔNG ở recap; report tự-thân là nguồn-chân-lý nấc, đừng flag recap. Tag `[s140, light#3, view-stale-status-1, nac-advance-vs-recap, model-flip-no-restamp]`
|
- **S140 (2026-07-18) light-audit #3 [counter 14 · force-fire-debt P=3 wal:pause S139 · owner-consent]:** Machine baseline TOTAL 45 (=S139, 0 flag mới) — chỉ soi ngữ-nghĩa. **1 FLAG (view-stale-status, LOW):** `HANDOFF.md:8` NEXT-em còn liệt "spawn-probe reviewer 5-nhãn … nâng `624c378d` verified-pending→executed-runtime" như việc PHẢI-LÀM, nhưng SOURCE = adap-report `624c378d`:9 ĐÃ nâng **executed-runtime @S140** (probe agentId a56dcf6da0425e86c, 17s, 0-garble). To-do xong mid-session, chờ closeout clear. class_repeat view-stale-status 1(S137)→2 (jump@3 chưa chạm). **VERIFIED-CLEAN (chống false-alarm):** (a) report `624c378d`:9 tự-thân=executed-runtime ĐÚNG = nguồn-chân-lý nấc; (b) `_index.md:48`="processed" = email-layer KHÔNG phải adap-nấc → 0 stale; (c) `HANDOFF:5`+`STATUS:462` "624c378d=verified-pending" = narrative-recap S138-S139 đóng-băng-đúng-thời-điểm → KHÔNG flag (trap#3 frozen); (d) **3b model-flip S140→Fable**: canonical `STATUS §Sub-agents:450` dừng enumerate ở flip-8/S107 CÓ CHỦ-ĐÍCH (S106 anti-churn) ⇒ 0 re-stamp; 3 derived (agents/README:5 · session-start:37/41 · session-end:113) point-not-enumerate, 0 stale-model literal → NO FLAG. **Lesson:** nấc-adap advance ở phiên KẾ (S140) trong khi narrative-recap kẹt ở phiên GHI (S139) = staleness sống ở forward-pointer (NEXT-em), KHÔNG ở recap; report tự-thân là nguồn-chân-lý nấc, đừng flag recap. Tag `[s140, light#3, view-stale-status-1, nac-advance-vs-recap, model-flip-no-restamp]`
|
||||||
- **S143 (2026-07-22) DEEP-audit [counter 17 · ngưỡng 18 ⇒ FORCE-FIRE SỚM 1 NHỊP theo direction owner, KHÔNG tới-hạn tự-nhiên]** `[#53 garble ×2 → APPEND on-behalf bởi em-main sau VERIFY, B3; vai chưa tự ghi được]` — nguồn verbatim `runs/2026-07-22-S143-closeout-audit/sub-lead-view-1.md`. Machine baseline TOTAL **47** (45→46→47; +1 sau closeout S143). **3 FLAG, cả 3 cùng class `view-residual-asym`** — đều là **dư-lượng sửa-một-phía của CHÍNH phiên đó**: (1) `STATUS.md:450` ô canonical còn *"NO Write/Edit (chặn-bằng-thiếu-tool)"* trong khi `:462` cùng file + memory `feedback_monitor_residual_write_containment` đã lật (commit `3f4310f` vá memory, quên ô canonical); (2) `agents/README.md:190` còn khai "NO Write/Edit" như sự-thật tool-grant; (3) `agents/README.md:27` dòng **tự xưng "Roster THẬT"** liệt 14 vai, thiếu đúng 3 trio — `git show 2757e41` = **0 hunk** chạm dòng này. 🔴 **Lesson lớn nhất (reviewer bắt thêm site thứ 4 `:225` cùng lớp):** sweep của wave đặt acceptance = grep theo **CON SỐ** (`roster 14|14/14|14 folder|14 vai`) → 0 hit → tuyên bố sạch; nhưng 2 site nặng nhất **liệt kê TÊN, không chứa số nào** ⇒ lọt lưới nguyên wave. **"0 hit" chỉ chứng minh pattern không khớp, KHÔNG chứng minh hết drift — acceptance phải ĐẾM PHẦN TỬ rồi so canonical.** Cả 4 site đã vá `36cefcc`. class_repeat view-residual-asym 0→1 (jump@3 chưa chạm); view-stale-status không tái-hiện → reset 0. Tag `[s143, deep-force-fire-som, view-residual-asym-3, enum-ten-lot-grep-so, sua-mot-phia]`
|
- **S143 (2026-07-22) DEEP-audit [counter 17 · ngưỡng 18 ⇒ FORCE-FIRE SỚM 1 NHỊP theo direction owner, KHÔNG tới-hạn tự-nhiên]** `[#53 garble ×2 → APPEND on-behalf bởi em-main sau VERIFY, B3; vai chưa tự ghi được]` — nguồn verbatim `runs/2026-07-22-S143-closeout-audit/sub-lead-view-1.md`. Machine baseline TOTAL **47** (45→46→47; +1 sau closeout S143). **3 FLAG, cả 3 cùng class `view-residual-asym`** — đều là **dư-lượng sửa-một-phía của CHÍNH phiên đó**: (1) `STATUS.md:450` ô canonical còn *"NO Write/Edit (chặn-bằng-thiếu-tool)"* trong khi `:462` cùng file + memory `feedback_monitor_residual_write_containment` đã lật (commit `3f4310f` vá memory, quên ô canonical); (2) `agents/README.md:190` còn khai "NO Write/Edit" như sự-thật tool-grant; (3) `agents/README.md:27` dòng **tự xưng "Roster THẬT"** liệt 14 vai, thiếu đúng 3 trio — `git show 2757e41` = **0 hunk** chạm dòng này. 🔴 **Lesson lớn nhất (reviewer bắt thêm site thứ 4 `:225` cùng lớp):** sweep của wave đặt acceptance = grep theo **CON SỐ** (`roster 14|14/14|14 folder|14 vai`) → 0 hit → tuyên bố sạch; nhưng 2 site nặng nhất **liệt kê TÊN, không chứa số nào** ⇒ lọt lưới nguyên wave. **"0 hit" chỉ chứng minh pattern không khớp, KHÔNG chứng minh hết drift — acceptance phải ĐẾM PHẦN TỬ rồi so canonical.** Cả 4 site đã vá `36cefcc`. class_repeat view-residual-asym 0→1 (jump@3 chưa chạm); view-stale-status không tái-hiện → reset 0. Tag `[s143, deep-force-fire-som, view-residual-asym-3, enum-ten-lot-grep-so, sua-mot-phia]`
|
||||||
|
|
||||||
## 🔄 Curate trigger
|
- **S148 (2026-07-24) light-audit #4 [counter 22 · light 5/6 CHƯA tới hạn ⇒ FORCE-FIRE theo P=1 closeout-gộp, owner-direction — KHÔNG phải nhịp tự nhiên]** `[diary ghi TRONG lúc làm, anti-#53]` — Machine baseline TOTAL **46** (S143=47 → 46; canonical resolve mig=67 test=528 gotcha=83 table=89 menu=54 policy=216). **5 FLAG.** 🔴 **Ca nặng nhất = CANONICAL-POISON:** `STATUS.md:448` row `| Tests | **528 PASS** | 45 Domain + 483 Infra` NHƯNG `STATUS.md:6` cùng file + `changelog/sessions/2026-07-23-1730-S147…:38` đều ghi **532 (45D+487I, was 483I → +4)** ⇒ closeout S147 vá header quên ô canonical; hệ-quả: detector đọc canonical=528 nên **mọi flag C2/B3 test đo bằng thước sai**, `[OK] canonical matches disk` chỉ cross-check mig+gotcha, **KHÔNG** cross-check test ⇒ mù đúng chỗ. Cặp **BẤT-ĐỐI-XỨNG NGƯỢC CHIỀU** cùng 1 cặp file: `STATUS:6` ghi "gotcha 82" trong khi `STATUS:449`=83 VÀ `docs/gotchas.md` max anchor `### 83.`=83 ⇒ một file, hai row, mỗi row stale MỘT chiều khác nhau. **Lesson:** khi canonical-row và header-line cùng sống trong 1 file, closeout dễ vá 1-trong-2 → *đừng giả định canonical luôn đúng chỉ vì nó tên là canonical*; và **cross-check của máy phủ tới đâu thì mới tin tới đó** (mig+gotcha có, test/table/menu/policy KHÔNG). Tag `[s148, light#4, canonical-poison-test-count, header-vs-canonical-row, cross-check-coverage]`
|
||||||
- Hook-cap >17.1KB → archive L2 `archive/<period>.md` (move-not-cut + seal-verify) + `_INDEX.md` pointer. Entry ≤1.5K.
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ metadata:
|
|||||||
node_type: memory
|
node_type: memory
|
||||||
type: feedback
|
type: feedback
|
||||||
originSessionId: c0d6d8d1-8e0e-46bf-ac36-ab0f45d2629f
|
originSessionId: c0d6d8d1-8e0e-46bf-ac36-ab0f45d2629f
|
||||||
|
modified: 2026-07-24T10:21:02.939Z
|
||||||
---
|
---
|
||||||
|
|
||||||
3 bài học integrity từ S100 H18-adopt (2026-07-02):
|
3 bài học integrity từ S100 H18-adopt (2026-07-02):
|
||||||
@ -15,6 +16,8 @@ metadata:
|
|||||||
|
|
||||||
4. **Sibling-test 2 CHIỀU (S125, 2026-07-16):** mismatch hash có nhánh thứ 3 ngoài tamper/EOL — **VERIFIER của MÌNH hỏng**. Discriminator: chạy verifier trên sibling known-good. Sibling MATCH ⇒ phép đúng, file bệnh (ca S100 frontier-assessment) · sibling CŨNG FAIL ⇒ **verifier bệnh** (ca S125: PS 5.1 `Get-Content -Raw` decode UTF-8-no-BOM bằng ANSI → mojibake → false-TAMPER trên broadcast hub SẠCH; đối chứng `stamp_verify.py` hub → exit-0). Fix gốc: hash CHỈ từ bytes (`ReadAllBytes` + UTF8 decode PIN) — CẤM `Get-Content -Raw` cho hash; đã vá `check-email.md`/`send-email.md` S125.
|
4. **Sibling-test 2 CHIỀU (S125, 2026-07-16):** mismatch hash có nhánh thứ 3 ngoài tamper/EOL — **VERIFIER của MÌNH hỏng**. Discriminator: chạy verifier trên sibling known-good. Sibling MATCH ⇒ phép đúng, file bệnh (ca S100 frontier-assessment) · sibling CŨNG FAIL ⇒ **verifier bệnh** (ca S125: PS 5.1 `Get-Content -Raw` decode UTF-8-no-BOM bằng ANSI → mojibake → false-TAMPER trên broadcast hub SẠCH; đối chứng `stamp_verify.py` hub → exit-0). Fix gốc: hash CHỈ từ bytes (`ReadAllBytes` + UTF8 decode PIN) — CẤM `Get-Content -Raw` cho hash; đã vá `check-email.md`/`send-email.md` S125.
|
||||||
|
|
||||||
|
5. **🔴 Ghost-wire class (c) — CLAIM-OF-FIX: doc khai "đã vá" một kẽ CHƯA vá, và kẽ đó KHÔNG TỒN TẠI ở chỗ nó chỉ (S148, 2026-07-24).** `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`"*. Lead **tin bản tóm-tắt** → sửa `check-email.md` STAGE 1 đọc thêm `outbox/all`. **Cả hai vế đều sai:** (i) grep `outbox/all check-email.md` = **0 hit** ⇒ chưa hề bịt, chỉ được TUYÊN BỐ; (ii) `outbox/all` **chưa bao giờ** là việc của `/check-email` — 2 kênh 2 tool 2 sổ (`outbox/se`→`/check-email`→`_index` ⟂ `outbox/all`→`/adap-apply`→ **KHÔNG** vào `_index`, khai ở `_index.md` header dòng 7). Kiểm ngược bằng máy: **22/22** thư `outbox/se` đều có dòng index ⇒ **tool vốn không thủng**. ⇒ lead **vá một tool không hỏng, theo một lời khai không đo**. 🔴 **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**. Cùng lượt còn 1 báo-cáo sai cùng gốc: lead khai *"`_index` thiếu 17 dòng"* trong khi cả 17 là fan-out ⇒ **sổ đang đúng**, chỉ là lead áp nhầm luật cho kênh.
|
||||||
|
|
||||||
**Why:** stamp-then-edit + fabricated-citation là lỗi im lặng — chỉ lộ khi RE-COMPUTE đối chứng nguồn gốc; một làn chỉ kiểm "tóm-tắt trung-thành bản-thô" sẽ mù khi bản-thô bịa từ đầu.
|
**Why:** stamp-then-edit + fabricated-citation là lỗi im lặng — chỉ lộ khi RE-COMPUTE đối chứng nguồn gốc; một làn chỉ kiểm "tóm-tắt trung-thành bản-thô" sẽ mù khi bản-thô bịa từ đầu.
|
||||||
|
|
||||||
**How to apply:** mọi broadcast/email cross-project → re-compute `SHA256(body)` canonical trước khi áp; mismatch → **sibling-test 2-chiều TRƯỚC**: sibling-fail ⇒ sửa verifier của MÌNH, sibling-match ⇒ HELD + báo nguồn (không suy diễn "chắc CRLF", cũng không hô tamper khi chưa loại trừ tool). Mọi report → chỉ cite run-id/số ĐÃ tồn tại; chưa chạy = placeholder tường minh. Đổi config-consumer → grep key-name toàn scripts/ xem có ai đọc thật không. Liên quan: [[faultinjection-proves-teeth]], [[canonical-spec-over-broadcast]], [[agent-return-garble-recover]].
|
**How to apply:** mọi broadcast/email cross-project → re-compute `SHA256(body)` canonical trước khi áp; mismatch → **sibling-test 2-chiều TRƯỚC**: sibling-fail ⇒ sửa verifier của MÌNH, sibling-match ⇒ HELD + báo nguồn (không suy diễn "chắc CRLF", cũng không hô tamper khi chưa loại trừ tool). Mọi report → chỉ cite run-id/số ĐÃ tồn tại; chưa chạy = placeholder tường minh. Đổi config-consumer → grep key-name toàn scripts/ xem có ai đọc thật không. Liên quan: [[faultinjection-proves-teeth]], [[canonical-spec-over-broadcast]], [[agent-return-garble-recover]].
|
||||||
|
|||||||
@ -5,7 +5,7 @@ metadata:
|
|||||||
node_type: memory
|
node_type: memory
|
||||||
type: feedback
|
type: feedback
|
||||||
originSessionId: cc5c42e6-f9aa-404c-adf6-26079c40d118
|
originSessionId: cc5c42e6-f9aa-404c-adf6-26079c40d118
|
||||||
modified: 2026-07-22T05:34:19.739Z
|
modified: 2026-07-24T09:10:28.062Z
|
||||||
---
|
---
|
||||||
|
|
||||||
At S50 (2026-06-07 session-end), the 2 INFORM-only monitor subs (tooling-auditor H1 + harvest-curator H2) — briefed **propose-only**, and which **reported "wrote nothing"** — were nonetheless the only plausible authors of ~7 canonical/agent-memory file writes done outside em-main: `error-ledger.md` (2 guard promotions + #57 coords), 3 `adap-reports` (nac→verified-runtime), 4 `agent-memory/*` Recent-activity, and parts of `STATUS.md` (Recently-Done block + In-Progress flip + RAG-line reconcile). mtimes clustered in the 00:00–00:05 monitor window. em-main `git diff` at the commit-gate caught every line → all accurate / benign / 0-mojibake / chunk 2415 (no RAG corruption) → adopted per AS-10 keep-if-correct. Logged blameless as **E-006** in the error-ledger.
|
At S50 (2026-06-07 session-end), the 2 INFORM-only monitor subs (tooling-auditor H1 + harvest-curator H2) — briefed **propose-only**, and which **reported "wrote nothing"** — were nonetheless the only plausible authors of ~7 canonical/agent-memory file writes done outside em-main: `error-ledger.md` (2 guard promotions + #57 coords), 3 `adap-reports` (nac→verified-runtime), 4 `agent-memory/*` Recent-activity, and parts of `STATUS.md` (Recently-Done block + In-Progress flip + RAG-line reconcile). mtimes clustered in the 00:00–00:05 monitor window. em-main `git diff` at the commit-gate caught every line → all accurate / benign / 0-mojibake / chunk 2415 (no RAG corruption) → adopted per AS-10 keep-if-correct. Logged blameless as **E-006** in the error-ledger.
|
||||||
@ -14,4 +14,6 @@ At S50 (2026-06-07 session-end), the 2 INFORM-only monitor subs (tooling-auditor
|
|||||||
|
|
||||||
**⚠️ S143 (2026-07-22) — premise correction, measured:** the sentence below assumed `Write` had been *removed* from monitor tool-grants, leaving only a Bash residual. **That premise is false at runtime.** Measured on 6 read-only roles (3× `harness-*` trio, 2× H24 auditors, `reviewer`; `tooling-auditor`/`harvest-curator`/`investigator-codebase` same shape): none declare `Write`/`Edit` in their frontmatter `tools:` — yet the **runtime roster still grants `Write, Edit`**, appended at the **end** of the tool list. The tell is positional: `implementer-backend` declares `Edit, Write` at slots 2-3 and its runtime list preserves that file order, so the other six are being **appended at spawn time**, not read from file. ⇒ a frontmatter whitelist is a **statement of intent, not an enforcement mechanism**; "chặn-bằng-thiếu-tool" in any spec is an overclaim (G-015). The residual channel is therefore wider than Bash. Mechanism unknown (hypothesis: `memory: project` needs diary writes — **unverified**, do not assert). Same two-layer shape as [[feedback_permission_grant_two_layers]]: declared-layer ⟂ granted-layer are independent, and verifying one proves nothing about the other. Reported upward in `broadcasts/outbox/ai_infra/2026-07-22-se-to-ai_infra-bao-nac-wave-dot-9-10.md` §3(b).
|
**⚠️ S143 (2026-07-22) — premise correction, measured:** the sentence below assumed `Write` had been *removed* from monitor tool-grants, leaving only a Bash residual. **That premise is false at runtime.** Measured on 6 read-only roles (3× `harness-*` trio, 2× H24 auditors, `reviewer`; `tooling-auditor`/`harvest-curator`/`investigator-codebase` same shape): none declare `Write`/`Edit` in their frontmatter `tools:` — yet the **runtime roster still grants `Write, Edit`**, appended at the **end** of the tool list. The tell is positional: `implementer-backend` declares `Edit, Write` at slots 2-3 and its runtime list preserves that file order, so the other six are being **appended at spawn time**, not read from file. ⇒ a frontmatter whitelist is a **statement of intent, not an enforcement mechanism**; "chặn-bằng-thiếu-tool" in any spec is an overclaim (G-015). The residual channel is therefore wider than Bash. Mechanism unknown (hypothesis: `memory: project` needs diary writes — **unverified**, do not assert). Same two-layer shape as [[feedback_permission_grant_two_layers]]: declared-layer ⟂ granted-layer are independent, and verifying one proves nothing about the other. Reported upward in `broadcasts/outbox/ai_infra/2026-07-22-se-to-ai_infra-bao-nac-wave-dot-9-10.md` §3(b).
|
||||||
|
|
||||||
**How to apply:** Before ANY `/session-end` commit where monitor/sub agents ran, ALWAYS `git status` + `git diff` + chunk-count and **review every non-em-main line** — adopt-if-correct (AS-10) or revert; never blind-commit. If a sub's self-report ("wrote nothing") contradicts git-diff → **Fidelity flag** (escalate reviewer). Recommend to anh/AI_INFRA: harden monitor tool-grant (Write removal leaves Bash residual → consider a hook blocking sub-Bash-write to tracked paths) — but that is a charter-v2 infra decision. Links: [[feedback_store_memory_rebootstrap_protection]] · [[feedback_harness_123_adoption]] · [[feedback_session_end_memory_write_verify]].
|
**🔴 S148 (2026-07-24) — RE-MEASURED live, count is 15 not 6:** the "6 roles" above was an S143-era undercount (S143 itself already revised it to 9 mid-entry). Fresh count from disk + this session's runtime registry: **20 agent files − 5 legitimate write-specialists (`implementer-backend`, `implementer-frontend`, `frontend-designer`, `office-document`, `test-specialist`) = 15 read-only roles that declare NO `Write`/`Edit` in frontmatter `tools:` — and the runtime grants `Write, Edit` to all 15.** Two-sided proof: `.claude/agents/reviewer.md:7` declares `[Read, Grep, Glob, Bash, mcp__rag-unified__*]` while the session's agent listing shows `…, Write, Edit`; `harness-eval`'s own description string says *"KHÔNG store_memory, KHÔNG Write/Edit"* and it is granted both. 🔸 **The number grows with the roster, it is not a worsening condition** — don't read a rising count as a regression. 🔴 **Quote a count here only if you just measured it** — this line has now been wrong twice (6 → 9 → 15) precisely because it was re-cited from memory instead of re-counted.
|
||||||
|
|
||||||
|
**How to apply:** Before ANY `/session-end` commit where monitor/sub agents ran, ALWAYS `git status` + `git diff` + chunk-count and **review every non-em-main line** — adopt-if-correct (AS-10) or revert; never blind-commit. If a sub's self-report ("wrote nothing") contradicts git-diff → **Fidelity flag** (escalate reviewer). 🔒 **DO NOT re-propose hardening — anh decided @S148 (2026-07-24): option (a), keep as-is, NO `PreToolUse` hook blocking sub-writes to tracked paths.** So the frontmatter whitelist stays **documentation of intent**, and `git diff` at the commit-gate is the *only* real containment — it catches **after** the write, never **before**. Re-raise only if anh reopens it or the hub returns a mechanism answer (`[carry:tools-whitelist-no-teeth]` is now narrowed to the hub-confirmation leg alone). Anh's framing was *"có j audit sau"* — accept the residual risk now, catch it in audit later; that is a deliberate trade, not an oversight to fix behind his back. Links: [[feedback_store_memory_rebootstrap_protection]] · [[feedback_harness_123_adoption]] · [[feedback_session_end_memory_write_verify]].
|
||||||
|
|||||||
@ -9,10 +9,58 @@ argument-hint: <from_project | all>
|
|||||||
## Tham số
|
## Tham số
|
||||||
- `$1` = from_project (BẮT BUỘC) ∈ 6 others, hoặc `all` = quét cả 6.
|
- `$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 đó.
|
||||||
|
|
||||||
|
**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)
|
## Quy trình 2-STAGE (audit qua folder)
|
||||||
**STAGE 1 — Nhận (đọc → inbox root, PENDING):**
|
**STAGE 1 — Nhận (đọc → inbox root, PENDING):**
|
||||||
1. Validate `$1`.
|
1. Validate `$1`.
|
||||||
2. READ `<from>/broadcasts/outbox/se/*.md` (message gửi cho se).
|
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]
|
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. **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.
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,33 @@ Thực-hiện **tuần-tự 5 bước** sau; trong lúc chạy **KHÔNG nhận v
|
|||||||
|
|
||||||
## 2.6 Ghi context-block vào thư-mục phiên-LOGIC (S146 — lane CỘNG-DỒN, cặp với `/tiep §2.6`)
|
## 2.6 Ghi context-block vào thư-mục phiên-LOGIC (S146 — lane CỘNG-DỒN, cặp với `/tiep §2.6`)
|
||||||
|
|
||||||
- **Append MỘT khối mới** vào `.claude/sessions/session-<N>/pause-S<nn>-<yyyyMMddTHHmm>.md` (`<N>` = phiên-LOGIC **đang mở** — xem [`session-start.md`](session-start.md) BƯỚC 0.8).
|
🔴 **FORM HUB (owner chốt @S148 "đối ứng đúng chính xác như hub") — TÁCH marker ⟂ narrative, KHÔNG gộp 1 file như form SE cũ:**
|
||||||
|
|
||||||
|
**(A) Marker `_pause-<i>.md`** — `<i>` = số TUẦN TỰ trong thư-mục (`max(_pause-*)+1`), **KHÔNG** nhãn `S<nn>`, **KHÔNG** timestamp trong tên. Đúng **5 trường, ~200B**, không thêm bớt:
|
||||||
|
```
|
||||||
|
ts: <ISO-8601 +07:00>
|
||||||
|
head-sha: <full sha, git rev-parse HEAD>
|
||||||
|
window-ordinal: <thứ mấy trong phiên-logic>
|
||||||
|
jsonl-hint: <project-dir>/<session-uuid>
|
||||||
|
account-label: none
|
||||||
|
```
|
||||||
|
|
||||||
|
**(B) Narrative → APPEND vào `_context-s-<N>.md`** (một file DUY NHẤT/phiên-logic, cộng dồn) — thêm đúng 1 entry `### PAUSE-<k> <ts>` dưới `FLOW-START`:
|
||||||
|
- 🔴 **Dòng đầu entry = `> anh: <tin-nhắn anh VERBATIM>`** — chép **nguyên văn**, CẤM paraphrase. Không có tin-nhắn ⇒ ghi `(THIẾU — lý do)`, **CẤM dựng lại từ trí nhớ**.
|
||||||
|
- Rồi 3 mục cũ: **(1) quyết-định đã CHỐT** · **(2) delta còn SỐNG** · **(3) con-trỏ**.
|
||||||
|
- 🔴 **FLOW append-only, entry cũ IMMUTABLE** — CẤM rewrite, CẤM tự-tóm (chống self-summary lossy). Vượt `session_ctx_kb` ⇒ distill **SECTION CŨ** thành pointer, KHÔNG sửa entry verbatim.
|
||||||
|
|
||||||
|
**(C) Máy-derive `§(c) STOCK-touched`** — `python scripts/session_ctx.py machine-block --session <N> --json` → điền bảng §(c) của `_context-s-<N>.md`. **KHÔNG điền tay** (template ràng "máy-derive @pause/snapshot").
|
||||||
|
🔸 **Khai giới-hạn:** `changed_files` = `git diff anchor..HEAD` ⇒ **chỉ phần ĐÃ COMMIT**; việc còn dirty không hiện. Đừng đọc thành "toàn bộ việc đã làm".
|
||||||
|
|
||||||
|
**(D) AUTO-SNAPSHOT — chạy `/snapshot` §2→§4 ngay trước bước 3** *(đóng `[carry:pause-autosnap]` #17, anh chốt @S148)*:
|
||||||
|
- ✅ **Đo trước khi wire, đúng câu hub bắt hỏi** (`goi-chot` §3 — *"có làm điểm dừng đắt lên không"* phải hỏi TRƯỚC khi bàn giá-trị): `machine-block` **~140ms** · `secrets-sweep` **~64ms** (3 lượt, tb).
|
||||||
|
- 🔴 **Chi-phí RÒNG của auto-snap chỉ là ~64ms + 1 write**, KHÔNG phải 204ms: `machine-block` **vốn đã phải chạy** ở (C) cho §(c) STOCK-touched. `/pause` cũng vốn đã commit sẵn ở bước 4.
|
||||||
|
- 🔸 **Ranh giữ khai:** hub **KHÔNG** ràng 1 pause = 1 snapshot (đo đĩa hub: `session-102` pause=3/snap=5 · `session-107` pause=2/snap=1). SE chọn auto-snap-tại-pause là **quyết-định SE**, không phải floor hub — ai thấy đắt thì gỡ, đã có số để cãi.
|
||||||
|
|
||||||
|
🧊 **Form SE cũ `pause-S<nn>-<ts>.md` (gộp marker+narrative) = LEGACY, CẤM viết mới.** Sàn-3 ⑤ vẫn **nhận** nó (dual-accept, `tiep.md §0`) vì `session-1` còn dùng — đúng luật retire: *gỡ nhánh legacy khi tập di-sản RỖNG, giữ khi CÒN người thụ-hưởng*.
|
||||||
|
|
||||||
|
- `<N>` = phiên-LOGIC **đang mở** — xem [`session-start.md`](session-start.md) BƯỚC 0.8.
|
||||||
- 🔴 **Scaffold idempotent (owner chốt @S146 "giống hub"):** thư-mục chưa có ⇒ **TẠO**; đã có ⇒ **DÙNG LẠI, CẤM đè**. Chạy lại nhiều lần vô hại.
|
- 🔴 **Scaffold idempotent (owner chốt @S146 "giống hub"):** thư-mục chưa có ⇒ **TẠO**; đã có ⇒ **DÙNG LẠI, CẤM đè**. Chạy lại nhiều lần vô hại.
|
||||||
- 🔴 **NHƯNG `/pause` KHÔNG BAO GIỜ tự tăng `<N>`** — cấp-số là **độc-quyền `/session-start`** (BƯỚC 0.8, canonical; B1 — mục này chỉ TRỎ). `/pause` chỉ tạo thư-mục cho số **đang mở**. Không có số nào đang mở (vào thẳng bằng `/tiep` rồi `/pause`, chưa từng `/session-start`) ⇒ dùng `max+1` **và ghi 1 dòng khai** trong khối: `N-cap-ngoai-session-start: <N> (ly-do: <...>)` — để `<N>` không bao giờ xuất-hiện mà không ai biết nó ở đâu ra.
|
- 🔴 **NHƯNG `/pause` KHÔNG BAO GIỜ tự tăng `<N>`** — cấp-số là **độc-quyền `/session-start`** (BƯỚC 0.8, canonical; B1 — mục này chỉ TRỎ). `/pause` chỉ tạo thư-mục cho số **đang mở**. Không có số nào đang mở (vào thẳng bằng `/tiep` rồi `/pause`, chưa từng `/session-start`) ⇒ dùng `max+1` **và ghi 1 dòng khai** trong khối: `N-cap-ngoai-session-start: <N> (ly-do: <...>)` — để `<N>` không bao giờ xuất-hiện mà không ai biết nó ở đâu ra.
|
||||||
- 🔴 **ACCUMULATE — CẤM ghi đè, CẤM sửa khối cũ.** Mỗi `/pause` = **một file mới**. (Ghi đè = mất chính thứ mà lane này sinh ra để giữ.)
|
- 🔴 **ACCUMULATE — CẤM ghi đè, CẤM sửa khối cũ.** Mỗi `/pause` = **một file mới**. (Ghi đè = mất chính thứ mà lane này sinh ra để giữ.)
|
||||||
@ -31,6 +57,14 @@ Thực-hiện **tuần-tự 5 bước** sau; trong lúc chạy **KHÔNG nhận v
|
|||||||
- **CẤM secret** (thư-mục này sẽ được commit — cùng kỷ-luật WAL bước 3).
|
- **CẤM secret** (thư-mục này sẽ được commit — cùng kỷ-luật WAL bước 3).
|
||||||
- 🔸 Hook `wal-flush.ps1` đã phủ `.claude/sessions/` (path thứ-4, S146) ⇒ khối này **tự vào `wal:` commit** ở turn-boundary. Vẫn **PHẢI add đích-danh** ở bước 4 (đừng dựa vào hook để chốt điểm dừng — hook là lưới, không phải nghi-thức).
|
- 🔸 Hook `wal-flush.ps1` đã phủ `.claude/sessions/` (path thứ-4, S146) ⇒ khối này **tự vào `wal:` commit** ở turn-boundary. Vẫn **PHẢI add đích-danh** ở bước 4 (đừng dựa vào hook để chốt điểm dừng — hook là lưới, không phải nghi-thức).
|
||||||
|
|
||||||
|
## 2.7 Kéo thư cross-project (cửa RA 2/2 — owner chốt S148)
|
||||||
|
|
||||||
|
**DÒ 2 kênh** (`outbox/se` + `outbox/all` × 6 repo) — **TRƯỚC** khi ghi WAL (bước 3), để `thu-moi: se=X all=Y` kịp vào `carry:`/context-map nếu có.
|
||||||
|
🔴 **CHỈ list + so id. KHÔNG copy · KHÔNG hash · KHÔNG python** — `/pause` là **cửa dừng**, ràng-buộc BINDING của hub (`goi-chot` §3) cấm làm nó đắt lên. Kéo thật = việc của bookend.
|
||||||
|
|
||||||
|
> 🔗 **Luật nhịp đầy-đủ = canonical [`check-email.md`](check-email.md) §"Nhịp chạy — 4 CỬA PHIÊN".** 🔴 **B1 — CHỈ TRỎ + GỌI, CẤM chép luật.**
|
||||||
|
> 🔴 **KHÔNG chặn điểm dừng:** lỗi ⇒ `check-email loi (khong chan)` → đi tiếp bước 3. `/pause` tồn-tại để **dừng an-toàn**; một bước kéo thư hỏng **không được phép** giữ anh lại.
|
||||||
|
|
||||||
## 3. Cập-nhật `.claude/WAL.md` đúng schema
|
## 3. Cập-nhật `.claude/WAL.md` đúng schema
|
||||||
- **`chain:`** — đầy-đủ mọi mục trạng-thái (`[x]` đã-xong · `[!]` đang-dở · `[ ]` chưa-làm), **KÈM BẰNG-CHỨNG** là một lệnh / đường-dẫn / hash chứng-minh trạng-thái đó (KHÔNG mô-tả suông).
|
- **`chain:`** — đầy-đủ mọi mục trạng-thái (`[x]` đã-xong · `[!]` đang-dở · `[ ]` chưa-làm), **KÈM BẰNG-CHỨNG** là một lệnh / đường-dẫn / hash chứng-minh trạng-thái đó (KHÔNG mô-tả suông).
|
||||||
- **`next:`** — đúng **một mệnh-lệnh cụ-thể**: làm gì tiếp theo.
|
- **`next:`** — đúng **một mệnh-lệnh cụ-thể**: làm gì tiếp theo.
|
||||||
|
|||||||
@ -21,6 +21,14 @@ Em main PHẢI echo **TOÀN BỘ nội dung command body này** (đầy đủ Ph
|
|||||||
> **Vì sao ở BƯỚC 0, không muộn hơn:** phiên bị cắt **giữa lúc đóng** là ca nguy-hiểm nhất — WAL đã flush một phần, chưa push, trông như sạch. Đặt dấu TRƯỚC mọi flush ⇒ phiên kế **thấy `closing:` treo** và biết là bị cắt (Sàn-3 bậc-MẠNH ③, `tiep.md` §0.b).
|
> **Vì sao ở BƯỚC 0, không muộn hơn:** phiên bị cắt **giữa lúc đóng** là ca nguy-hiểm nhất — WAL đã flush một phần, chưa push, trông như sạch. Đặt dấu TRƯỚC mọi flush ⇒ phiên kế **thấy `closing:` treo** và biết là bị cắt (Sàn-3 bậc-MẠNH ③, `tiep.md` §0.b).
|
||||||
> **Net-zero:** §6.4 vốn **LUÔN chạy** ⇒ thêm 1 dòng xoá = 0 chi-phí. Acceptance: chạy no-op trọn-vẹn ⇒ `grep -c '^closing:' .claude/WAL.md` = **0**; cắt giữa chừng ⇒ phiên kế **thấy** dấu.
|
> **Net-zero:** §6.4 vốn **LUÔN chạy** ⇒ thêm 1 dòng xoá = 0 chi-phí. Acceptance: chạy no-op trọn-vẹn ⇒ `grep -c '^closing:' .claude/WAL.md` = **0**; cắt giữa chừng ⇒ phiên kế **thấy** dấu.
|
||||||
|
|
||||||
|
## 📋 BƯỚC 0.5 — Kéo thư cross-project (cửa RA 1/2 — owner chốt S148)
|
||||||
|
|
||||||
|
**DÒ 2 kênh** rồi **KÉO đầy-đủ** theo định-tuyến (`se>0` → `/check-email all` · `all>0` → `/adap-apply`) — **TRƯỚC Phase 1 FLUSH**.
|
||||||
|
|
||||||
|
> 🔗 **Luật nhịp đầy-đủ = canonical [`check-email.md`](check-email.md) §"Nhịp chạy — 4 CỬA PHIÊN".** 🔴 **B1 — CHỈ TRỎ + GỌI, CẤM chép luật.**
|
||||||
|
> 🔴 **Vì sao TRƯỚC flush, không sau:** closeout **ghi sổ** (STATUS · HANDOFF · session-log · carry). Thư về sau khi sổ đã ghi thì **lỡ mất kỳ này** và nằm chờ tới cửa vào kế. Kéo trước ⇒ thư mới kịp vào đúng bản ghi của phiên.
|
||||||
|
> 🔴 **KHÔNG chặn closeout:** lỗi ⇒ `check-email loi (khong chan)` → đi tiếp Phase 1. Sàn-2 sentinel ở BƯỚC 0 đã đặt TRƯỚC bước này ⇒ cắt giữa chừng vẫn phát-hiện được.
|
||||||
|
|
||||||
## Phase 1 — FLUSH (sub-agent memory)
|
## Phase 1 — FLUSH (sub-agent memory)
|
||||||
|
|
||||||
**Điều kiện:** Chỉ xử lý con đã spawn trong session. KHÔNG spawn mới chỉ để flush (agent đã update MEMORY khi return).
|
**Điều kiện:** Chỉ xử lý con đã spawn trong session. KHÔNG spawn mới chỉ để flush (agent đã update MEMORY khi return).
|
||||||
@ -360,13 +368,16 @@ git push origin main # → git.baocaogiaoduc.vn/vietrep
|
|||||||
|
|
||||||
### 6.3-bis 🔒 Chốt-kết `_end` — đóng băng phiên-LOGIC (owner chốt @S146 "giống hub")
|
### 6.3-bis 🔒 Chốt-kết `_end` — đóng băng phiên-LOGIC (owner chốt @S146 "giống hub")
|
||||||
|
|
||||||
> Floor manifest `101e69d6` §1: dấu-mốc thứ-4 = **"Chốt-kết (`_end`) — dấu đóng băng khi phiên-LOGIC thực sự khép lại"**. SE form = `closed.md`. Chân này **trước S146 CHƯA wire** ⇒ cân-sổ ORPHAN-L chỉ có nửa vào, không có nửa khoá (kêu oan ca *"pause rồi đóng thẳng không qua `/tiep`"*). Nay đóng.
|
> Floor manifest `101e69d6` §1: dấu-mốc thứ-4 = **"Chốt-kết (`_end`) — dấu đóng băng khi phiên-LOGIC thực sự khép lại"**. 🔴 **SE form = `_end` kể từ S148** (owner chốt *"đối ứng đúng chính xác như hub"*); form cũ `closed.md` = **LEGACY, CẤM viết mới** — `session-1` còn dùng nên Sàn-3 vẫn nhận. Chân này **trước S146 CHƯA wire** ⇒ cân-sổ ORPHAN-L chỉ có nửa vào, không có nửa khoá (kêu oan ca *"pause rồi đóng thẳng không qua `/tiep`"*). Nay đóng.
|
||||||
|
|
||||||
- **Ghi `.claude/sessions/session-<N>/closed.md`** cho `<N>` đang mở — **FROZEN, ghi MỘT lần, CẤM sửa về sau**. Nội dung tối-thiểu **4 trường**:
|
- **Ghi `.claude/sessions/session-<N>/_end`** cho `<N>` đang mở — 🔴 **TÊN `_end`, KHÔNG đuôi `.md`** (form hub, owner chốt @S148 *"đối ứng đúng chính xác"*). **FROZEN, ghi MỘT lần, CẤM sửa về sau**. Khuôn `key: value`, tối-thiểu:
|
||||||
`phien-logic: L<N>` · `cua-so: S<a>..S<b>` (các nhãn vật-lý thuộc phiên-logic này) · `closeout-commit: <sha>` · `ket-qua: <1-3 dòng arc đã đóng>`.
|
`summary-frozen-s<N>:` (1 dòng arc đã đóng) · `pointer:` (session-log/SUMMARY) · `carry:` (`a · b · c`) · `pending-anh:` · `pointers:` (run-folder) · `h24-tick: counter=<n>` · `markers: _pause=<p> · _tiep=<t> · _snapshot=<s>`.
|
||||||
- **Cân-sổ (khoá vòng ORPHAN-L):** sau khi ghi, **mọi `pause-*.md` trong thư-mục coi như ĐÃ ĐỐI-ỨNG** — `closed.md` đóng vai đối-ứng cho khối `pause` cuối chưa có `resume-*`. ⇒ [`tiep.md §0`](tiep.md) block **⑤ ORPHAN-L** hết kêu oan.
|
🔴 **Trường `markers:` không phải trang-trí** — nó là **bản chụp cân-sổ tại lúc đóng**; sau khi đóng, detector bỏ qua thư-mục nên đây là **chứng duy nhất** còn lại về số lần dừng/nối.
|
||||||
- 🔴 **Idempotent:** `closed.md` đã tồn-tại ⇒ **NO-OP, CẤM ghi đè** (phiên-logic đã khép; closeout chạy lại không được "mở lại rồi khép lại").
|
🧊 Form SE cũ = `closed.md` (4 trường prose) — **LEGACY, CẤM viết mới**; `session-1` còn dùng nên Sàn-3 vẫn nhận (dual-accept).
|
||||||
- 🔴 **Thư-mục `session-<N>/` KHÔNG tồn-tại ⇒ NO-OP im-lặng** — phiên này không mở phiên-logic nào (vd vào thẳng bằng `/tiep`, chưa từng `/session-start`). **CẤM tự tạo thư-mục chỉ để ghi `closed.md`** — tạo-rồi-đóng-ngay là **sổ rỗng giả**, đúng loại ĐẠT-ảo mà fail-safe NO-OP khắp harness đang cấm.
|
- **Cân-sổ (khoá vòng ORPHAN-L):** ghi xong ⇒ **thư-mục ĐÓNG TRỌN, MỌI pause coi như đã đối-ứng** — [`tiep.md §0`](tiep.md) ⑤ **bỏ qua hẳn** thư-mục đã chốt-kết.
|
||||||
|
🔴 **Vá @S148 (fault-inject bắt):** bản cũ code `c=1` rồi so `p > r + c` ⇒ chỉ tha **ĐÚNG MỘT** pause chưa khớp ⇒ phiên đã đóng mà có **≥2** pause dư vẫn **KÊU OAN** — lệch đúng câu doc này vẫn luôn nói ("mọi pause"). Lệch sống từ S146, không lộ vì SE mới có `p=1`.
|
||||||
|
- 🔴 **Idempotent:** `_end` (hoặc `closed.md` legacy) đã tồn-tại ⇒ **NO-OP, CẤM ghi đè** (phiên-logic đã khép; closeout chạy lại không được "mở lại rồi khép lại").
|
||||||
|
- 🔴 **Thư-mục `session-<N>/` KHÔNG tồn-tại ⇒ NO-OP im-lặng** — phiên này không mở phiên-logic nào (vd vào thẳng bằng `/tiep`, chưa từng `/session-start`). **CẤM tự tạo thư-mục chỉ để ghi `_end`** — tạo-rồi-đóng-ngay là **sổ rỗng giả**, đúng loại ĐẠT-ảo mà fail-safe NO-OP khắp harness đang cấm.
|
||||||
- **Add đích-danh** ở §5.1 (thư-mục phiên nằm trong hook-4-path nên hook cũng nuốt, nhưng **đừng dựa hook để chốt** — cùng lý-lẽ `pause.md §2.6`).
|
- **Add đích-danh** ở §5.1 (thư-mục phiên nằm trong hook-4-path nên hook cũng nuốt, nhưng **đừng dựa hook để chốt** — cùng lý-lẽ `pause.md §2.6`).
|
||||||
🔸 **Meld-forward (floor hub, miếng nền thứ-3) — CHƯA kiểm tại SE:** hub ràng *"commit mang thư-mục phiên được **nhập-tiến về trước** khi squash, KHÔNG bị bỏ rơi"*. §5.0/§5.2 của SE squash `wal:`-trailing bằng `reset --soft` ⇒ nội-dung **ở lại INDEX** nên **về lý là không mất**; nhưng **chưa có phép đo riêng** cho `.claude/sessions/`. ⇒ khai **CHƯA-ĐO**, không claim kín.
|
🔸 **Meld-forward (floor hub, miếng nền thứ-3) — CHƯA kiểm tại SE:** hub ràng *"commit mang thư-mục phiên được **nhập-tiến về trước** khi squash, KHÔNG bị bỏ rơi"*. §5.0/§5.2 của SE squash `wal:`-trailing bằng `reset --soft` ⇒ nội-dung **ở lại INDEX** nên **về lý là không mất**; nhưng **chưa có phép đo riêng** cho `.claude/sessions/`. ⇒ khai **CHƯA-ĐO**, không claim kín.
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,20 @@ Em main đọc `.claude/WAL.md` (sổ mạch-việc-dở H22 — ghi-đè ≤40
|
|||||||
- 🔴 **Ai cấp `<N>` (khác "ai tạo thư-mục" — đừng lẫn):** **CHỈ `/session-start`** mới **MỞ SỐ MỚI** (`max(<N> hiện có) + 1`). `/pause` · `/tiep` **KHÔNG BAO GIỜ tự tăng `<N>`** — chúng chỉ **tạo thư-mục cho `<N>` ĐANG MỞ** nếu nó chưa có trên đĩa (ca "cửa đầu chưa kịp scaffold"). Không có `<N>` nào đang mở ⇒ dùng `<N> = max+1` **và ghi 1 dòng khai** trong khối đó là số được cấp ngoài `/session-start`.
|
- 🔴 **Ai cấp `<N>` (khác "ai tạo thư-mục" — đừng lẫn):** **CHỈ `/session-start`** mới **MỞ SỐ MỚI** (`max(<N> hiện có) + 1`). `/pause` · `/tiep` **KHÔNG BAO GIỜ tự tăng `<N>`** — chúng chỉ **tạo thư-mục cho `<N>` ĐANG MỞ** nếu nó chưa có trên đĩa (ca "cửa đầu chưa kịp scaffold"). Không có `<N>` nào đang mở ⇒ dùng `<N> = max+1` **và ghi 1 dòng khai** trong khối đó là số được cấp ngoài `/session-start`.
|
||||||
- 🧊 **Vá mâu-thuẫn @S146:** bản trước ghi *"Ai mở `<N>` mới: **CHỈ** `/session-start`"* trong khi [`pause.md §2.6`](pause.md) ghi *"chưa có thì đây là cửa đầu ⇒ **tạo** `session-<N>/`"* ⇒ **hai file nói ngược nhau về quyền tạo**. Gốc lỗi = **gộp hai khái niệm khác nhau** (*cấp SỐ* ⟂ *tạo THƯ-MỤC*) vào một câu. Nay tách đôi: **cấp số = độc-quyền `/session-start`** · **tạo thư-mục = idempotent, ai gặp trước thì tạo**. Hub chỉ ràng vế thứ hai.
|
- 🧊 **Vá mâu-thuẫn @S146:** bản trước ghi *"Ai mở `<N>` mới: **CHỈ** `/session-start`"* trong khi [`pause.md §2.6`](pause.md) ghi *"chưa có thì đây là cửa đầu ⇒ **tạo** `session-<N>/`"* ⇒ **hai file nói ngược nhau về quyền tạo**. Gốc lỗi = **gộp hai khái niệm khác nhau** (*cấp SỐ* ⟂ *tạo THƯ-MỤC*) vào một câu. Nay tách đôi: **cấp số = độc-quyền `/session-start`** · **tạo thư-mục = idempotent, ai gặp trước thì tạo**. Hub chỉ ràng vế thứ hai.
|
||||||
|
|
||||||
|
**(a-bis) 🔴 DANH-MỤC FILE trong thư-mục — form HUB, owner chốt @S148 (*"đối ứng đúng chính xác như này"*, ảnh `session-109`; đối-chứng đĩa hub `AI_INFRA/.claude/sessions/session-102..109`):**
|
||||||
|
|
||||||
|
| file | vai | ai ghi (canonical — B1, KHÔNG chép schema về đây) |
|
||||||
|
|---|---|---|
|
||||||
|
| `_context-s-<N>.md` | **narrative durable**, 1 file/phiên-logic · §(a) STOCK-map pointer + §(b) **FLOW append-only** (`### PAUSE-<k>` + dòng `> anh:` VERBATIM) · 🔴 CẤM rewrite/tự-tóm | append @[`pause.md §2.6`](pause.md) · đọc @[`tiep.md §2.6`](tiep.md) |
|
||||||
|
| `_pause-<i>.md` | **marker máy** ~200B, 5 trường (`ts`·`head-sha`·`window-ordinal`·`jsonl-hint`·`account-label`) | [`pause.md §2.6`](pause.md) |
|
||||||
|
| `_tiep-<i>.md` | marker máy, **cùng 5 trường** | [`tiep.md §2.6`](tiep.md) |
|
||||||
|
| `_snapshot-<i>.md` | chụp-nhanh không-dừng | ⏳ **CHƯA CÓ ở SE** — cần lệnh `/snapshot` `[carry:snapshot-cmd]` + `[carry:pause-autosnap]` |
|
||||||
|
| `_end` | **chốt-kết, KHÔNG đuôi `.md`** · `markers:` chụp cân-sổ lúc đóng | [`session-end.md §6.3-bis`](session-end.md) |
|
||||||
|
|
||||||
|
- 🔴 **`<i>` đánh số TUẦN TỰ** trong thư-mục (`max+1`) — **KHÔNG** nhãn `S<nn>`, **KHÔNG** timestamp trong tên. Thứ-tự đọc được từ tên, ts nằm *trong* file.
|
||||||
|
- 🔴 **TÁCH marker ⟂ narrative** là điểm khác lớn nhất so với form SE cũ (gộp cả hai vào `pause-S<nn>-<ts>.md`). Marker cho MÁY đọc, narrative cho NGƯỜI/phiên-sau đọc.
|
||||||
|
- 🧊 **Form cũ = LEGACY, CẤM viết mới**; Sàn-3 ⑤ vẫn **nhận** (dual-accept, [`tiep.md §0`](tiep.md)) vì `session-1` còn dùng — đúng luật retire *"giữ khi CÒN người thụ-hưởng"*.
|
||||||
|
|
||||||
**(b) Đo TRƯỚC khi tin — `.gitignore` (đo @S146, KHÔNG suy):**
|
**(b) Đo TRƯỚC khi tin — `.gitignore` (đo @S146, KHÔNG suy):**
|
||||||
```bash
|
```bash
|
||||||
git check-ignore -q .claude/sessions/session-1 ; echo "exit=$?" # → exit=1
|
git check-ignore -q .claude/sessions/session-1 ; echo "exit=$?" # → exit=1
|
||||||
@ -103,6 +117,13 @@ git check-ignore -q .claude/sessions/session-1 ; echo "exit=$?" # → exit=1
|
|||||||
- ✅ **`session_ctx_kb` (trần ngân-sách context-phiên) = 64 — OWNER CHỐT TƯỜNG-MINH @S146.** Canonical = [`memory-budget.json`](../agent-memory/memory-budget.json) → `session_ctx_kb` (+ `_session_ctx_kb_owner_set`); **B1 — KHÔNG chép số ra đây**, dòng này chỉ TRỎ. Đơn-vị **KB**, code đọc **nhân 1024**.
|
- ✅ **`session_ctx_kb` (trần ngân-sách context-phiên) = 64 — OWNER CHỐT TƯỜNG-MINH @S146.** Canonical = [`memory-budget.json`](../agent-memory/memory-budget.json) → `session_ctx_kb` (+ `_session_ctx_kb_owner_set`); **B1 — KHÔNG chép số ra đây**, dòng này chỉ TRỎ. Đơn-vị **KB**, code đọc **nhân 1024**.
|
||||||
🔴 **Vẫn là GHOST-WIRE, đừng đọc thành "đã wire":** đo @S146 **0 script đọc khoá** (hit duy-nhất trong `scripts/` là **comment** `nhip-no-probe.ps1:42`; đối-chứng `pull_warn_days` **có** reader thật `:190`). Có số ≠ có hành-vi. Ai wire sau phải **đọc khoá**, không hardcode.
|
🔴 **Vẫn là GHOST-WIRE, đừng đọc thành "đã wire":** đo @S146 **0 script đọc khoá** (hit duy-nhất trong `scripts/` là **comment** `nhip-no-probe.ps1:42`; đối-chứng `pull_warn_days` **có** reader thật `:190`). Có số ≠ có hành-vi. Ai wire sau phải **đọc khoá**, không hardcode.
|
||||||
|
|
||||||
|
## 📋 BƯỚC 0.9 — Kéo thư cross-project (cửa VÀO 1/2 — owner chốt S148)
|
||||||
|
|
||||||
|
**DÒ 2 kênh** rồi **KÉO đầy-đủ** theo định-tuyến: `se>0` → `/check-email all` · `all>0` → `/adap-apply`.
|
||||||
|
|
||||||
|
> 🔗 **Luật nhịp đầy-đủ (4 cửa · fail-soft · quan-hệ với `pull-cach`) = canonical [`check-email.md`](check-email.md) §"Nhịp chạy — 4 CỬA PHIÊN".** 🔴 **B1 — mục này CHỈ TRỎ + GỌI, CẤM chép luật sang đây.**
|
||||||
|
> 🔴 **KHÔNG chặn bootstrap:** không có thư ⇒ 1 dòng đi tiếp; lỗi ⇒ `check-email loi (khong chan)` rồi đi tiếp. Kéo **TRƯỚC Phase 1 READ** là cố ý — thư mới có thể đổi chính kế-hoạch phiên mà Phase 1 sắp dựng.
|
||||||
|
|
||||||
## Phase 1 — READ (load context)
|
## Phase 1 — READ (load context)
|
||||||
|
|
||||||
Đọc theo thứ tự, KHÔNG skip:
|
Đọc theo thứ tự, KHÔNG skip:
|
||||||
|
|||||||
70
.claude/commands/snapshot.md
Normal file
70
.claude/commands/snapshot.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
description: Checkpoint KHÔNG-dừng-phiên — ghi _snapshot chốt trạng-thái + commit, KHÔNG stop/bookend (session-model, adopt S148)
|
||||||
|
---
|
||||||
|
# /snapshot — chụp-nhanh không-dừng (SE port của hub `snapshot.md`, adopt S148 2026-07-24)
|
||||||
|
|
||||||
|
Checkpoint **NHẸ** giữa phiên (**≤1 turn**): **1 Write + 1 commit**. **KHÔNG stop · KHÔNG bookend · KHÔNG flush agent-memory · KHÔNG hỏi thêm.** Xong là làm việc tiếp ngay.
|
||||||
|
|
||||||
|
> 🔗 Cặp với `/pause` (dừng hẳn) và `/tiep` (nối lại). `/snapshot` **KHÔNG** phải điểm dừng — nó là **dấu mốc giữa đường**.
|
||||||
|
> 🧭 Đóng `[carry:snapshot-cmd]` (#15) — anh chốt @S148 *"làm đi không cần hỏi hub"*.
|
||||||
|
|
||||||
|
## 0. GUARD — thư-mục có thể CHƯA activate
|
||||||
|
Resolve sID `<N>`: đọc field `session:` trong `.claude/WAL.md` → mất thì lấy `.claude/sessions/session-*/` **mtime max** → vẫn mù thì **hỏi anh 1 dòng**.
|
||||||
|
🔴 `.claude/sessions/session-<N>/` **CHƯA tồn-tại** ⇒ **SKIP ÊM**: in đúng 1 dòng `sessions/ chua activate — /snapshot no-op` rồi DỪNG. **KHÔNG mkdir, KHÔNG chết.** *(Cấp số `<N>` là độc-quyền `/session-start` — [`session-start.md` BƯỚC 0.8](session-start.md).)*
|
||||||
|
|
||||||
|
## 1. KHI NÀO fire (3 trigger — AI tự phán)
|
||||||
|
- **(i)** Có quyết-định/kết-luận vừa chốt **chưa nằm file nào** (còn trong transcript).
|
||||||
|
- **(ii)** **NGAY TRƯỚC** một workflow-launch diện-WAL: `taskList ≥ 3` **hoặc** ước > 5 phút — chốt state trước khi fan-out.
|
||||||
|
- **(iii) accumulation-gate:** đếm commit **substantive** tích-luỹ, bỏ qua nhiễu hook.
|
||||||
|
- **anchor = `{subject·ts}` của mốc NON-`wal:` gần nhất** mà `_snapshot` TRƯỚC đã pin (đọc `anchor` trong `_snapshot-<k-1>.md`). 🔴 **CẤM lấy HEAD trần** — HEAD lúc snapshot thường là commit `wal:` do hook flush mỗi turn, và closeout-squash sẽ **rewrite chính sha đó** ⇒ neo vào nó là neo vào thứ sắp biến mất. Neo `{subject·ts}` sống sót squash.
|
||||||
|
- `count = git log --format=%s <anchor-sha>..HEAD | grep -vc '^wal:'`
|
||||||
|
- **fire khi `count ≥ K`.** `K` đọc **LIVE** từ `.claude/agent-memory/memory-budget.json` key `snapshot_trigger_k`.
|
||||||
|
🔸 **Khai thật @S148: key này CHƯA có trong file SE** ⇒ áp **default-if-absent = 6** đúng theo spec hub. Đây là **số của hub**, không phải anh chốt — anh muốn khác thì đặt key, đừng sửa số ở đây (B1).
|
||||||
|
- **fallback** (anchor không resolve được sau rewrite / chưa có `_snapshot` nào): `git log --since=<mtime(_snapshot-* mới nhất)>`; **0 `_snapshot` nào** ⇒ snapshot ĐẦU do trigger (i)/(ii) lái, **KHÔNG** do (iii) — chống đếm-quá lúc folder vừa sinh.
|
||||||
|
|
||||||
|
## 2. Ghi `_snapshot-<k>.md`
|
||||||
|
`k = (số file `_snapshot-*.md` hiện có trong `session-<N>/`) + 1`.
|
||||||
|
🔴 `_snapshot` **tự chứa essence** — **KHÔNG** double-write vào `_context` FLOW (FLOW = **@pause-only**).
|
||||||
|
|
||||||
|
Derive machine-block TRƯỚC: `python scripts/session_ctx.py machine-block --session <N> --json`
|
||||||
|
|
||||||
|
````
|
||||||
|
# _snapshot-<k> — SESSION-MODEL checkpoint (sID <N>)
|
||||||
|
|
||||||
|
ts: <ISO-8601 — ưu tiên git-anchored `git log -1 --format=%cI`, tránh wall-clock tuỳ tiện>
|
||||||
|
head-sha: <git rev-parse HEAD>
|
||||||
|
head-subject: <git log -1 --format=%s>
|
||||||
|
head-ts: <git log -1 --format=%cI>
|
||||||
|
label: <1 dòng — checkpoint này chốt cái gì>
|
||||||
|
snapshot-ordinal: <k>
|
||||||
|
|
||||||
|
## essence (≤3 dòng — chốt cái CHƯA nằm file)
|
||||||
|
- <dòng 1>
|
||||||
|
- <dòng 2>
|
||||||
|
- <dòng 3>
|
||||||
|
|
||||||
|
## machine-block
|
||||||
|
```json
|
||||||
|
<paste nguyên JSON của: python scripts/session_ctx.py machine-block --session N --json>
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
**Trường BẮT BUỘC đủ:** `ts` · `head-sha` · `head-subject` + `head-ts` · `label` · `snapshot-ordinal` · `essence ≤3 dòng` · `machine-block`.
|
||||||
|
🔴 `head-subject`+`head-ts` = **chống sha-rewrite-rot**: sau squash sha đổi, `{subject·ts}` vẫn resolve lại được.
|
||||||
|
🔸 **Giới-hạn giữ khai (đo @S148):** `machine-block.changed_files` derive từ `git diff anchor..HEAD` ⇒ **chỉ thấy phần ĐÃ COMMIT**. Việc đang dirty trong cây (vd `docs/` chưa commit) **KHÔNG** hiện ra. Giữ đúng ngữ-nghĩa hub để sau này re-pull bằng diff; đừng đọc `changed_files` thành "toàn bộ việc đã làm".
|
||||||
|
|
||||||
|
## 3. Secrets-sweep gate (TRƯỚC commit — BẮT BUỘC)
|
||||||
|
`python scripts/session_ctx.py secrets-sweep --session <N>`
|
||||||
|
- **exit 1 ⇒ CHẶN commit**: in `file:line` mọi hit, xử-lý/redact rồi mới commit.
|
||||||
|
- ✅ **Đã fault-inject @S148 2 chiều:** CHẶN đúng ca có `sk-…` · cho qua ca sạch · **0 dương-giả** với `ask-me`/`task-list` (token-anchored `\b`).
|
||||||
|
- ⚠️ **ACCEPTED-GAP khai thẳng:** sweep **pattern-bounded** (4 mẫu `voyage·sk-·gitea_pat·cfut_`) ⇒ **KHÔNG** phủ secret lớp khác (vd mật-khẩu DB trong tin-nhắn verbatim). Đây là **BLOCK bảo-thủ trước commit**, KHÔNG phải chứng-minh sạch tuyệt-đối.
|
||||||
|
|
||||||
|
## 4. Commit (1 commit)
|
||||||
|
- `git add .claude/sessions/session-<N>/_snapshot-<k>.md` — 🔴 **CHỈ file đích danh, CẤM `git add -A`/`.`** (rủi ro rò secret).
|
||||||
|
- `git commit -m "wal: snapshot s<N> _snapshot-<k>"` — ASCII-clean (tránh em-dash mangle dưới PowerShell). **KHÔNG `--no-verify`. KHÔNG push.**
|
||||||
|
- 🔸 **Meld-forward @closeout — CHƯA ĐO tại SE:** hub ràng commit mang `.claude/sessions/` phải được **nhập-tiến** vào mốc non-`wal:` liền sau khi squash, KHÔNG bị DROP như `wal:` thuần. SE squash bằng `reset --soft` ⇒ **về lý không mất**, nhưng **chưa có phép đo riêng** — trùng `[carry:meld-forward-unmeasured]` (#19). Đừng claim kín.
|
||||||
|
|
||||||
|
## 5. Xong
|
||||||
|
Báo **1 dòng**: `snapshot-<k> ghi @<ts> (count=<n>/K, trigger-<i|ii|iii>) — committed, tiếp việc`
|
||||||
|
rồi **1 dòng nhịp-nợ**: `powershell.exe -ExecutionPolicy Bypass -File scripts/nhip-no-probe.ps1` (lỗi → `probe-loi (khong chan)`).
|
||||||
|
🔴 **KHÔNG stop · KHÔNG bookend · KHÔNG DỪNG HẲN** — quay lại việc đang làm ngay.
|
||||||
@ -86,21 +86,32 @@ done
|
|||||||
git log --name-only --format='%s' origin/main..HEAD | grep -q '.claude/sessions/'
|
git log --name-only --format='%s' origin/main..HEAD | grep -q '.claude/sessions/'
|
||||||
|
|
||||||
# (b) cửa ĐĨA — git-independent, miễn-nhiễm hook (mirror ①: đọc đĩa, KHÔNG đọc git)
|
# (b) cửa ĐĨA — git-independent, miễn-nhiễm hook (mirror ①: đọc đĩa, KHÔNG đọc git)
|
||||||
# Cân-bằng-sổ: mỗi `pause-*` phải có ĐÚNG một đối-ứng (`resume-*` do /tiep ghi, hoặc closed.md do đóng-L).
|
# Cân-bằng-sổ: mỗi pause phải có ĐÚNG một đối-ứng (tiep do /tiep ghi, hoặc chốt-kết do đóng-L).
|
||||||
|
# 🔴 DUAL-ACCEPT 2 FORM (S148) — cùng khuôn dual-accept của ① ở trên:
|
||||||
|
# HUB (chuẩn từ S148, owner chốt "đối ứng đúng chính xác"): _pause-<i>.md · _tiep-<i>.md · _end (KHÔNG đuôi)
|
||||||
|
# LEGACY (di-sản ≤S147): pause-*.md · resume-*.md · closed.md
|
||||||
|
# 🔴 TÍNH-CHẤT CỨU MẠNG: glob `pause-*` KHÔNG khớp `_pause-1.md` (tên bắt đầu bằng `_`)
|
||||||
|
# ⇒ 2 form KHÔNG đè nhau ⇒ cộng thẳng là an-toàn, không đếm đôi. Đã fault-inject 2 chiều @S148.
|
||||||
for d in .claude/sessions/session-*/; do
|
for d in .claude/sessions/session-*/; do
|
||||||
[ -d "$d" ] || continue
|
[ -d "$d" ] || continue
|
||||||
p=$(ls "$d"pause-*.md 2>/dev/null | wc -l); [ "$p" -eq 0 ] && continue
|
# 🔴 CHỐT-KẾT ĐÓNG TRỌN THƯ-MỤC, không phải "+1" (vá @S148 — fault-inject bắt).
|
||||||
r=$(ls "$d"resume-*.md 2>/dev/null | wc -l)
|
# session-end.md §6.3-bis nói rõ: sau khi ghi chốt-kết thì MỌI pause "coi như ĐÃ ĐỐI-ỨNG".
|
||||||
c=0; [ -f "$d/closed.md" ] && c=1
|
# Bản cũ viết `c=1` rồi `p > r + c` ⇒ chỉ tha ĐÚNG MỘT pause chưa khớp ⇒ phiên đã đóng mà
|
||||||
[ "$p" -gt $((r + c)) ] && echo "ORPHAN-L: $d (pause=$p resume=$r closed=$c)"
|
# có ≥2 pause dư vẫn KÊU OAN. Doc và máy lệch nhau từ S146; dữ-liệu SE quá nhỏ (p=1) nên chưa lộ.
|
||||||
|
{ [ -f "$d/_end" ] || [ -f "$d/closed.md" ]; } && continue
|
||||||
|
p=$(( $(ls "$d"_pause-*.md 2>/dev/null | wc -l) + $(ls "$d"pause-*.md 2>/dev/null | wc -l) ))
|
||||||
|
[ "$p" -eq 0 ] && continue
|
||||||
|
r=$(( $(ls "$d"_tiep-*.md 2>/dev/null | wc -l) + $(ls "$d"resume-*.md 2>/dev/null | wc -l) ))
|
||||||
|
[ "$p" -gt "$r" ] && echo "ORPHAN-L: $d (pause=$p tiep=$r, chua chot-ket)"
|
||||||
done
|
done
|
||||||
```
|
```
|
||||||
|
|
||||||
- ✅ **Đối-ứng `resume-*` CÓ người ghi thật** — `/tiep` §2.6 dưới (cùng file này) ⇒ vòng `pause ↔ tiep` **tự đóng**, không phải cơ-chế treo.
|
- ✅ **Đối-ứng `_tiep-<i>.md` CÓ người ghi thật** — `/tiep` §2.6 dưới (cùng file này) ⇒ vòng `pause ↔ tiep` **tự đóng**, không phải cơ-chế treo. *(legacy `resume-*` vẫn được đếm — dual-accept ở máy trên.)*
|
||||||
- ✅ **`closed.md` ĐÃ WIRE @S146** (owner chốt *"giống hub"* — `_end` chốt-kết của manifest `101e69d6`): nghi-thức ghi nằm ở [`session-end.md`](session-end.md) **§6.3-bis** (FROZEN · 4 trường · idempotent NO-OP · NO-OP im-lặng nếu 0 thư-mục). ⇒ **cân-sổ nay ĐỦ CẢ HAI vế**: `pause` đối-ứng bằng `resume-*` (`/tiep §2.6`) **hoặc** `closed.md` (đóng-L) ⇒ ca *"pause rồi đóng thẳng không qua `/tiep`"* **hết kêu oan**.
|
- ✅ **Chốt-kết `_end` ĐÃ WIRE** (owner chốt @S146 *"giống hub"*, đổi tên `closed.md`→`_end` @S148 cho khớp form hub — manifest `101e69d6`): nghi-thức ghi ở [`session-end.md`](session-end.md) **§6.3-bis** (FROZEN · idempotent NO-OP · NO-OP im-lặng nếu 0 thư-mục). ⇒ **cân-sổ đủ CẢ HAI vế**: `pause` đối-ứng bằng `_tiep-<i>` (`/tiep §2.6`) **hoặc** `_end` (đóng-L) ⇒ ca *"pause rồi đóng thẳng không qua `/tiep`"* **hết kêu oan**.
|
||||||
|
🔴 **@S148 mạnh thêm một nấc:** `_end` nay **ĐÓNG TRỌN thư-mục** (detector `continue` hẳn), không còn là "+1". Fault-inject bắt: phiên đã đóng mà dư ≥2 pause thì bản cũ **vẫn KÊU OAN** — lệch đúng câu *"MỌI pause coi như đã đối-ứng"* mà `session-end §6.3-bis` vẫn luôn nói. Doc đúng, máy sai, sống từ S146.
|
||||||
🧊 *Nấc cũ (tới S145): "`closed.md` CHƯA wire — VC-2 còn chờ anh duyệt", kèm hệ-quả "chỉ ca pause-rồi-đóng-thẳng mới thiếu đối-ứng". **Cả hai nay SAI** — giữ 1 dòng làm vết.*
|
🧊 *Nấc cũ (tới S145): "`closed.md` CHƯA wire — VC-2 còn chờ anh duyệt", kèm hệ-quả "chỉ ca pause-rồi-đóng-thẳng mới thiếu đối-ứng". **Cả hai nay SAI** — giữ 1 dòng làm vết.*
|
||||||
🔴 **Bài học lấy từ chính chỗ này (H24 `lead-view-auditor` bắt @S146):** MÁY ở ngay trên (`:89` `:94` `:95`) **đã đọc `closed.md` thật** từ lúc block này ra đời, mà **PROSE vẫn khai "chưa wire"** ⇒ đây là **lật-ngược của ghost-wire**: **wired-but-declared-unwired** — và nó nằm đúng dưới nhãn *"chống ghost-wire H18"*. ⇒ **Ghost-wire soi được 2 CHIỀU**: khai-có-mà-không-chạy **và** chạy-thật-mà-khai-chưa.
|
🔴 **Bài học lấy từ chính chỗ này (H24 `lead-view-auditor` bắt @S146):** MÁY ở ngay trên (`:89` `:94` `:95`) **đã đọc `closed.md` thật** từ lúc block này ra đời, mà **PROSE vẫn khai "chưa wire"** ⇒ đây là **lật-ngược của ghost-wire**: **wired-but-declared-unwired** — và nó nằm đúng dưới nhãn *"chống ghost-wire H18"*. ⇒ **Ghost-wire soi được 2 CHIỀU**: khai-có-mà-không-chạy **và** chạy-thật-mà-khai-chưa.
|
||||||
- 🟢 **Hướng hỏng = AN-TOÀN:** quên ghi `resume-*` ⇒ sổ lệch ⇒ **KÊU ⇒ HỎI LẠI ANH**. Sai về phía *hỏi thừa*, không về phía *im lặng bỏ việc* — đúng thiên-hướng của Sàn-3.
|
- 🟢 **Hướng hỏng = AN-TOÀN:** quên ghi `_tiep-<i>.md` ⇒ sổ lệch ⇒ **KÊU ⇒ HỎI LẠI ANH**. Sai về phía *hỏi thừa*, không về phía *im lặng bỏ việc* — đúng thiên-hướng của Sàn-3.
|
||||||
|
|
||||||
### 🟡 BẬC TRUNG-BÌNH — nhiều file bẩn **NGOÀI** 4 path hook persist
|
### 🟡 BẬC TRUNG-BÌNH — nhiều file bẩn **NGOÀI** 4 path hook persist
|
||||||
|
|
||||||
@ -143,10 +154,20 @@ Tín-hiệu **YẾU NHẤT**, dùng cuối. 🔴 **`porcelain` rỗng KHÔNG ph
|
|||||||
- **Dòng-nợ (SAU tick — n-3):** gọi `powershell.exe -ExecutionPolicy Bypass -File scripts/nhip-no-probe.ps1` in dòng-nợ 4-vế (vế-1 nhịp-kiểm đọc post-tick). 🔴 **probe KHÔNG chặn điểm dừng**: lỗi → in `probe-loi (khong chan)` → đi tiếp.
|
- **Dòng-nợ (SAU tick — n-3):** gọi `powershell.exe -ExecutionPolicy Bypass -File scripts/nhip-no-probe.ps1` in dòng-nợ 4-vế (vế-1 nhịp-kiểm đọc post-tick). 🔴 **probe KHÔNG chặn điểm dừng**: lỗi → in `probe-loi (khong chan)` → đi tiếp.
|
||||||
> 🔗 **Predicate C7 đầy-đủ (probe được phép chạy ở điểm dừng) = canonical [`harness-11-engine.md`](../../docs/governance/harness-11-engine.md) §N.8.** 🔴 **B1 — dòng này CHỈ TRỎ, CẤM chép predicate sang đây** (chép 2 nơi = 2 nguồn sự-thật, đúng thứ B1 sinh ra để chặn).
|
> 🔗 **Predicate C7 đầy-đủ (probe được phép chạy ở điểm dừng) = canonical [`harness-11-engine.md`](../../docs/governance/harness-11-engine.md) §N.8.** 🔴 **B1 — dòng này CHỈ TRỎ, CẤM chép predicate sang đây** (chép 2 nơi = 2 nguồn sự-thật, đúng thứ B1 sinh ra để chặn).
|
||||||
|
|
||||||
## 2.6 Đọc context-map phiên-LOGIC + ghi biên-nhận `resume-*` (S146 — cặp với `/pause` bước 2.6)
|
## 2.5b Kéo thư cross-project (cửa VÀO 2/2 — owner chốt S148)
|
||||||
|
|
||||||
- **Đọc:** nếu có `.claude/sessions/session-<N>/` → đọc **TẤT CẢ** `pause-*.md` theo thứ-tự thời-gian = **bối-cảnh cộng-dồn** của phiên-logic (quyết-định đã chốt · delta còn sống · con-trỏ run/commit). 🔴 **Đây là lane CỘNG-DỒN, khác WAL** — WAL là sổ **mạch-sống ghi-đè ≤40 dòng** (liếc-một-cái-là-biết); context-map là **tích-luỹ, không ghi đè**. Đọc context-map **KHÔNG** thay việc chạy `verify:` — ground-truth vẫn thắng (§3).
|
**DÒ 2 kênh** (`outbox/se` + `outbox/all` × 6 repo) — **NGAY SAU dòng-nợ** (vế-4 `pull-cach` vừa in xong ⇒ đọc số rồi dò là đúng thứ-tự nhân-quả). In `thu-moi: se=X all=Y`.
|
||||||
- **Ghi biên-nhận — 🔴 THỰC-HIỆN SAU §3** (đọc ở đây, ghi sau khi reconcile xong; **bắt buộc**): tạo `.claude/sessions/session-<N>/resume-S<nn>-<yyyyMMddTHHmm>.md` — **1 khối ngắn**: nối từ `pause-*` nào · lệch gì so `chain:` (nếu có) · `next:` đang thực-thi.
|
🔴 **CHỈ list + so id. KHÔNG copy · KHÔNG hash · KHÔNG python** (đo @S148: dò ~5ms · kéo ~200–500ms/thư). `X|Y > 0` ⇒ nêu **1 dòng** rồi đi tiếp §2.6; **kéo thật để bookend làm** (`se`→`/check-email` · `all`→`/adap-apply`).
|
||||||
|
|
||||||
|
> 🔗 **Luật nhịp đầy-đủ = canonical [`check-email.md`](check-email.md) §"Nhịp chạy — 4 CỬA PHIÊN".** 🔴 **B1 — CHỈ TRỎ + GỌI, CẤM chép luật.**
|
||||||
|
> 🔴 **KHÔNG chặn recovery:** lỗi ⇒ `check-email loi (khong chan)` → đi tiếp §2.6. **Cửa này quan-trọng NHẤT trong 4** — *"1 session kéo 2-3 phiên"* nghĩa là các phiên GIỮA đều vào bằng `/tiep`, nên bỏ cửa này là bỏ phần lớn lưu-lượng.
|
||||||
|
|
||||||
|
## 2.6 Đọc `_context-s-<N>.md` + ghi marker `_tiep-<i>.md` (S146 · form hub @S148 — cặp với `/pause §2.6`)
|
||||||
|
|
||||||
|
- **Đọc (form HUB, chuẩn @S148):** có `.claude/sessions/session-<N>/` → đọc **`_context-s-<N>.md`** — đó là **bối-cảnh cộng-dồn** (§(a) STOCK-map pointer + §(b) FLOW append-only: mọi entry `### PAUSE-<k>` theo thứ-tự, kèm dòng `> anh:` verbatim). Marker `_pause-*.md`/`_tiep-*.md` là **5 trường máy**, đọc để biết `window-ordinal` + `head-sha`, KHÔNG chứa narrative.
|
||||||
|
🧊 **Legacy ≤S147:** thư-mục không có `_context-s-<N>.md` ⇒ đọc **TẤT CẢ** `pause-*.md` theo thứ-tự thời-gian (form cũ gộp marker+narrative). Nhận-để-đọc, **CẤM viết mới** kiểu đó. 🔴 **Đây là lane CỘNG-DỒN, khác WAL** — WAL là sổ **mạch-sống ghi-đè ≤40 dòng** (liếc-một-cái-là-biết); context-map là **tích-luỹ, không ghi đè**. Đọc context-map **KHÔNG** thay việc chạy `verify:` — ground-truth vẫn thắng (§3).
|
||||||
|
- **Ghi biên-nhận — 🔴 THỰC-HIỆN SAU §3** (đọc ở đây, ghi sau khi reconcile xong; **bắt buộc**): tạo **`_tiep-<i>.md`** (`<i>` = `max(_tiep-*)+1`) — đúng **5 trường ~200B**, y khuôn `_pause-<i>.md` (xem [`pause.md §2.6`](pause.md)): `ts` · `head-sha` · `window-ordinal` · `jsonl-hint` · `account-label`.
|
||||||
|
🔴 **Marker là MÁY, không phải bài luận** — kết-quả reconcile (lệch gì so `chain:`, `next:` đang chạy) thuộc về **`_context-s-<N>.md`**, không nhồi vào marker. *(Bản S148 đầu ghi `resume-S<nn>-<ts>.md` 2,5KB narrative — sai form, đã gỡ.)*
|
||||||
- 🔴 **Vì sao bắt buộc:** biên-nhận này là **đối-ứng cân-sổ** của tín-hiệu **ORPHAN-L ⑤** (§0). Thiếu nó ⇒ sổ lệch ⇒ lần sau **KÊU** ⇒ hỏi lại anh. Hỏng về phía *hỏi thừa* = an-toàn; nhưng ghi đủ thì sàn mới **im đúng**.
|
- 🔴 **Vì sao bắt buộc:** biên-nhận này là **đối-ứng cân-sổ** của tín-hiệu **ORPHAN-L ⑤** (§0). Thiếu nó ⇒ sổ lệch ⇒ lần sau **KÊU** ⇒ hỏi lại anh. Hỏng về phía *hỏi thừa* = an-toàn; nhưng ghi đủ thì sàn mới **im đúng**.
|
||||||
- 🔸 `session-<N>` **KHÔNG mở mới ở `/tiep`** — `/tiep` **nối** phiên-logic đang mở. Mở `<N>` mới = việc của `/session-start` (xem `session-start.md` BƯỚC 0.8).
|
- 🔸 `session-<N>` **KHÔNG mở mới ở `/tiep`** — `/tiep` **nối** phiên-logic đang mở. Mở `<N>` mới = việc của `/session-start` (xem `session-start.md` BƯỚC 0.8).
|
||||||
|
|
||||||
|
|||||||
@ -11,12 +11,12 @@
|
|||||||
},
|
},
|
||||||
"_tick_invariant_note": "Tick invariant (hub dede7ec5 Delta-1, verbatim): moi LAN-CHOT +1; mot cap dung-noi tang DUNG +1, khong +2, khong +0. SE form = tick-at-entry-gate idempotent-per-label (hub Delta-2 recovery-gate +1 = permitted form) - NET +1/session-label EQUIV hub +1/cap on CLOSED pairs; an OPEN pair is transiently +0 until its entry gate fires (hub blessed, 9a35405b block-1 phep dung-noi). Guard song-con = label-convention (session-start 2.1.8: new conversation = new S<nn> label, NEVER reuse). history[] is append-unbounded BY DESIGN => absence of a marker = never-happened (safe semantics); IF a FIFO cap is ever added, eviction MUST be handled explicitly (absence-vi-bi-day != absence-vi-chua-xay-ra - log-BOUNDED design-note dede7ec5).",
|
"_tick_invariant_note": "Tick invariant (hub dede7ec5 Delta-1, verbatim): moi LAN-CHOT +1; mot cap dung-noi tang DUNG +1, khong +2, khong +0. SE form = tick-at-entry-gate idempotent-per-label (hub Delta-2 recovery-gate +1 = permitted form) - NET +1/session-label EQUIV hub +1/cap on CLOSED pairs; an OPEN pair is transiently +0 until its entry gate fires (hub blessed, 9a35405b block-1 phep dung-noi). Guard song-con = label-convention (session-start 2.1.8: new conversation = new S<nn> label, NEVER reuse). history[] is append-unbounded BY DESIGN => absence of a marker = never-happened (safe semantics); IF a FIFO cap is ever added, eviction MUST be handled explicitly (absence-vi-bi-day != absence-vi-chua-xay-ra - log-BOUNDED design-note dede7ec5).",
|
||||||
"_seed_honesty": "Seeded UNTICKED on purpose. counter=0 and last_ticked_* = null mean 'no tick has ever happened', which is the truth at S121 - the ritual that performs the tick lands in W3. Seeding a fake first tick here would make the very first cadence reading a lie, and H24 exists to catch exactly that kind of invented number.",
|
"_seed_honesty": "Seeded UNTICKED on purpose. counter=0 and last_ticked_* = null mean 'no tick has ever happened', which is the truth at S121 - the ritual that performs the tick lands in W3. Seeding a fake first tick here would make the very first cadence reading a lie, and H24 exists to catch exactly that kind of invented number.",
|
||||||
"counter": 20,
|
"counter": 22,
|
||||||
"last_ticked_session": "S146",
|
"last_ticked_session": "S148",
|
||||||
"last_ticked_head": "474199b32fb0371d76aa2f1c43daa849f973f9fd",
|
"last_ticked_head": "581544200b4773db810808c063f4245fe54e004c",
|
||||||
"last_ticked_at": "2026-07-22",
|
"last_ticked_at": "2026-07-24",
|
||||||
"last_audit": {
|
"last_audit": {
|
||||||
"light_at_counter": 17,
|
"light_at_counter": 22,
|
||||||
"deep_at_counter": 17,
|
"deep_at_counter": 17,
|
||||||
"_note": "Counter value at which the last light/deep self-audit actually ran. S140 (2026-07-18): light-audit #3 at counter=14 = FORCE-FIRE DEBT PAID (closeout S139 gop P=3 pause => OVERDUE(light) INFORM; owner direction S140 'dong du 5 vong' = consent DP-3 => lead spawn ca CAP H24 dau phien). 2-vai coverage 0-garble, diary ghi TRONG luc lam (anti-#53). lead-view: 1 FLAG LOW view-stale-status (HANDOFF:8 NEXT-em con treo '624c378d verified-pending->executed' nhu to-do trong khi da executed-runtime @S140 sang) - xu @closeout re-stamp + 2 INFORM clean (model-flip S140 Fable = owner-choice KHONG can re-stamp canonical per anti-churn S106; 3 surface frozen dung). lead-omission: 1 FLAG MED gap-owner-specifics (direction session-model S140 VANG tracker - da xu TRONG PHIEN: draft session-model-se-draft.md + email hub + closeout them carry) + INFORM gap-carry-aged non-vacuous LAN DAU (hook-vs-budget-cap streak 9>=M6, owner-held) + INFORM route-H1 (cum 7-carry S117/S118 VO HINH voi carry-age detector - chi age carry re-tag trong NEXT segment; aging-measurement bo sot) + META diary lead-omission thieu entry S137 (GAP-3 tai) -> backfill @closeout. Prior: light #2 at counter=11 (S137, OVERDUE 8/6 paid). S143 (2026-07-22): DEEP-audit RAN at counter=17 - FORCE-FIRE SOM 1 NHIP theo direction owner (nguong tu-nhien la 18 = 3+15), KHONG phai toi-han tu-nhien. Deep bao ham light => set CA HAI light_at=deep_at=17 (tranh no ao phien sau). Chi tiet FLAG/class_repeat: xem history[] entry S143. Moc ke tiep tinh tu 17: light ~ counter 23; deep ~ counter 32."
|
"_note": "Counter value at which the last light/deep self-audit actually ran. S140 (2026-07-18): light-audit #3 at counter=14 = FORCE-FIRE DEBT PAID (closeout S139 gop P=3 pause => OVERDUE(light) INFORM; owner direction S140 'dong du 5 vong' = consent DP-3 => lead spawn ca CAP H24 dau phien). 2-vai coverage 0-garble, diary ghi TRONG luc lam (anti-#53). lead-view: 1 FLAG LOW view-stale-status (HANDOFF:8 NEXT-em con treo '624c378d verified-pending->executed' nhu to-do trong khi da executed-runtime @S140 sang) - xu @closeout re-stamp + 2 INFORM clean (model-flip S140 Fable = owner-choice KHONG can re-stamp canonical per anti-churn S106; 3 surface frozen dung). lead-omission: 1 FLAG MED gap-owner-specifics (direction session-model S140 VANG tracker - da xu TRONG PHIEN: draft session-model-se-draft.md + email hub + closeout them carry) + INFORM gap-carry-aged non-vacuous LAN DAU (hook-vs-budget-cap streak 9>=M6, owner-held) + INFORM route-H1 (cum 7-carry S117/S118 VO HINH voi carry-age detector - chi age carry re-tag trong NEXT segment; aging-measurement bo sot) + META diary lead-omission thieu entry S137 (GAP-3 tai) -> backfill @closeout. Prior: light #2 at counter=11 (S137, OVERDUE 8/6 paid). S143 (2026-07-22): DEEP-audit RAN at counter=17 - FORCE-FIRE SOM 1 NHIP theo direction owner (nguong tu-nhien la 18 = 3+15), KHONG phai toi-han tu-nhien. Deep bao ham light => set CA HAI light_at=deep_at=17 (tranh no ao phien sau). Chi tiet FLAG/class_repeat: xem history[] entry S143. Moc ke tiep tinh tu 17: light ~ counter 23; deep ~ counter 32."
|
||||||
},
|
},
|
||||||
@ -25,10 +25,11 @@
|
|||||||
"counts": {
|
"counts": {
|
||||||
"view-residual-asym": 1,
|
"view-residual-asym": 1,
|
||||||
"view-stale-count": 0,
|
"view-stale-count": 0,
|
||||||
"gap-carry-dropped": 1,
|
"gap-carry-dropped": 3,
|
||||||
"gap-decision-sunk": 1,
|
"gap-decision-sunk": 3,
|
||||||
"view-stale-status": 0,
|
"view-stale-status": 0,
|
||||||
"gap-owner-specifics": 2,
|
"_backfill_S148": "S146 audit CHAY THAT (force-fire P=8) nhung KHONG co entry trong history[] va class_repeat KHONG duoc cap-nhat — lead-omission-auditor bat @S148 (FLAG-3 gap-decision-sunk), lead verify doc-lap 2 nguon: (a) history[] nhay S145->S147, (b) sub-lead-omission-S146.md ghi nguyen-van 'tally 2 -> 3 CHAM JUMP (S140 x1 -> S143 x2 -> S146 x3)'. Tally duoi day DA VA cho khop chuoi that S140->S143->S146->S148. HE-QUA da xay ra: ghi-chu tick S148 ket-luan 'cao nhat = 2 < 3 => khong jump' — DOC TU SO TIEN-S146, sai. Jump da fire tu S146 ma khong ai biet; no duoc tra TINH-CO boi force-fire P=1 @S148 (ly-do khac).",
|
||||||
|
"gap-owner-specifics": 0,
|
||||||
"gap-carry-aged": 1,
|
"gap-carry-aged": 1,
|
||||||
"gap-incident-unrecorded": 0
|
"gap-incident-unrecorded": 0
|
||||||
}
|
}
|
||||||
@ -73,6 +74,26 @@
|
|||||||
"at": "2026-07-22",
|
"at": "2026-07-22",
|
||||||
"session": "S145",
|
"session": "S145",
|
||||||
"event": "CLEAN tick (KHONG squash-benign) qua /tiep resume mach S144. Nhan-phien MOI S145 theo label-convention S135 (conversation moi = nhan moi ke ca vao bang /tiep; reuse S144 se keo OR-guard NO-OP => phep-7 +0, cam). Tick S144->S145: counter 18->19, head d5656ab -> 95ef595. Phan-loai TRUOC khi tick tren last_ticked_head cu d5656ab: (a) counter doc 18 == luu 18 => KHONG lui; (b) git merge-base --is-ancestor d5656ab HEAD = exit 0 => CON REACHABLE (khac S144/S143 not-reachable-but-exists) => day la tick SACH binh-thuong, KHONG phai squash-benign, KHONG fail-loud. OVERDUE sau tick: light 19-17=2 < 6, deep 19-17=2 < 15 => ca hai CHUA toi han (moc ke tiep: light ~23, deep ~32). JUMP: class_repeat cao nhat gap-owner-specifics=2 < 3 => khong jump. => KHONG co H24 audit phien nay."
|
"event": "CLEAN tick (KHONG squash-benign) qua /tiep resume mach S144. Nhan-phien MOI S145 theo label-convention S135 (conversation moi = nhan moi ke ca vao bang /tiep; reuse S144 se keo OR-guard NO-OP => phep-7 +0, cam). Tick S144->S145: counter 18->19, head d5656ab -> 95ef595. Phan-loai TRUOC khi tick tren last_ticked_head cu d5656ab: (a) counter doc 18 == luu 18 => KHONG lui; (b) git merge-base --is-ancestor d5656ab HEAD = exit 0 => CON REACHABLE (khac S144/S143 not-reachable-but-exists) => day la tick SACH binh-thuong, KHONG phai squash-benign, KHONG fail-loud. OVERDUE sau tick: light 19-17=2 < 6, deep 19-17=2 < 15 => ca hai CHUA toi han (moc ke tiep: light ~23, deep ~32). JUMP: class_repeat cao nhat gap-owner-specifics=2 < 3 => khong jump. => KHONG co H24 audit phien nay."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"at": "2026-07-23",
|
||||||
|
"session": "S147",
|
||||||
|
"event": "squash-benign (product/UAT session, tick @/pause - tick DAU cua S147 vi vao bang /tiep dau phien KHONG tick, da defer). Tick S146->S147: counter 20->21, old last_ticked_head 474199b3 (S146) -> new 5f6c3be. Phan-loai TRUOC tick: (a) git cat-file -t 474199b3 = commit => object CON TON TAI; (b) git merge-base --is-ancestor 474199b3 HEAD = exit 1 => KHONG reachable; (c) counter doc 20 == luu 20 => KHONG lui. => SQUASH-BENIGN => ghi vet + DI TIEP, KHONG alarm owner. Nguyen-nhan: S147 code-push reset 5 wal:-commit + docs-closeout squash 1 wal: nen head luc tick S146 roi khoi lich su - drift KY-VONG, khong tamper; nhan-phien cu 'S146' con nguyen = corroborate 2 nguon. OVERDUE sau tick: light 21-17=4 < 6, deep 21-17=4 < 15 => ca hai CHUA toi han (moc ke: light ~23, deep ~32). JUMP: class_repeat cao nhat gap-owner-specifics=2 < 3 => khong jump. => KHONG co H24 audit phien nay."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"at": "2026-07-24",
|
||||||
|
"session": "S148",
|
||||||
|
"event": "CLEAN tick (KHONG squash-benign) qua /tiep noi mach S147. Nhan-phien MOI S148 theo label-convention S135 (conversation moi = nhan moi ke ca vao bang /tiep; reuse S147 se keo OR-guard session-clause NO-OP => tiep KHONG tick => phep-7 +0, cam). Tick S147->S148: counter 21->22, head 5f6c3be -> 5815442 (wal: pause local, chua push). Phan-loai TRUOC tick tren last_ticked_head cu 5f6c3be: (a) counter doc 21 == luu 21 => KHONG lui; (b) git cat-file -t 5f6c3be = commit => object CON TON TAI; (c) git merge-base --is-ancestor 5f6c3be HEAD = exit 0 => CON REACHABLE => tick SACH binh-thuong, KHONG squash-benign, KHONG fail-loud. Vi sao khac S147: S147 tick @/pause roi closeout squash nhac dau-tick; lan nay chua co closeout nao chay sau tick nen 5f6c3be van nam thang tren duong toi HEAD (HEAD = 5f6c3be + 1 commit wal: pause). OVERDUE sau tick: light 22-17=5 < 6, deep 22-17=5 < 15 => ca hai CHUA toi han (moc ke: light ~23 = NGAY PHIEN SAU, deep ~32). JUMP: class_repeat cao nhat gap-owner-specifics=2 < 3 => khong jump. => KHONG co H24 audit phien nay."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"at": "2026-07-22",
|
||||||
|
"session": "S146",
|
||||||
|
"event": "BACKFILL @S148 — entry nay BI THIEU suot S146->S148. H24 DA CHAY THAT @S146 (light force-fire P=8): 3 vai (lead-view + lead-omission + h24-audit), ca 3 garble #53, 7 FLAG -> va het. Bang-chung dia: runs/2026-07-22-S145-apply-hub-answers/sub-lead-{omission,view,h24-audit}-S146.md. Vai lead-omission ra 4 FLAG: gap-owner-specifics (2->3 CHAM JUMP) - gap-incident-unrecorded (fire lan dau tu khi owner mo enum @S143) - gap-decision-sunk (1->2) - gap-carry-dropped (1->2). 🔴 KHONG entry nay => last_audit va class_repeat dung yen => tick S147 VA S148 deu doc so tien-S146 => S148 ket-luan sai 'cao nhat 2 < 3 khong jump' trong khi JUMP DA CHAM tu S146. Phat-hien boi chinh lead-omission-auditor @S148 (FLAG-3), lead verify doc-lap 2 nguon truoc khi va. BAI HOC: vai H24 chay xong ma khong ai ghi so = audit do roi nhu chua do; nghi-thuc (j)(ii) phai ghi last_audit + class_repeat NGAY sau khi cap tra, khong doi closeout sau."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"at": "2026-07-24",
|
||||||
|
"session": "S148-force-fire",
|
||||||
|
"event": "H24 light-audit #5 CHAY THAT @counter 22 — FORCE-FIRE theo (j)(vi): P=1 wal:pause gop vao closeout (closeout-lien-truoc 5f6c3be) => OVERDUE(light) bat ke counter; light 5/6 CHUA toi han tu-nhien. AUTO, KHONG consent (owner @S146 '3 -> auto'). Ca 2 vai GARBLE #53 (so dem x25@S143 -> x27): lead-view GHI DIARY trong luc lam => vot tron tu dia 0-mat; lead-omission KHONG ghi (mtime con 13:10 phien truoc) => phai SendMessage-resume, resume co ghi dia roi moi tra. Phan-hoa nay dung y bai hoc S123: chan duoc #53 = ghi-dia-trong-luc-lam, khong phai prompt dung. KET QUA: lead-view 5 FLAG (nang nhat CANONICAL-POISON: STATUS:448 o canonical Tests ghi 528/483I trong khi STATUS:6 + session-log S147 ghi 532/487I; lead chay dotnet test tuoi => 45D+487I=532 THAT => o canonical sai, da va; kem cap bat-doi-xung NGUOC CHIEU: STATUS:6 'gotcha 82' vs row 83 vs gotchas.md anchor 83). lead-omission 4 FLAG (FLAG-1 bang OWNER-GATED O-1..O-7 spec-adap-dot-11-v2:88-97: O-2/O-3/O-7 = 0 hit tren 5 be-mat owner + 0 session-log, im 5 nhan phien, REPEAT cau-truc cua FLAG-3@S143; FLAG-2 2 viec owner-giao bi TU CHOI chi co vet trong WAL, 0 hit HANDOFF => §6.4 reset WAL se boc hoi; FLAG-3 verdict JUMP @S146 chim - chinh la ly-do backfill entry S146 o tren). last_audit light cap-nhat 17 -> 22. class_repeat va theo chuoi that: gap-decision-sunk 3 (CHAM JUMP) - gap-carry-dropped 3 (CHAM JUMP) - gap-owner-specifics 0 (S146=3 nhung S148 khong tai-hien, consecutive semantics)."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
63
.claude/sessions/session-2/_context-s-2.md
Normal file
63
.claude/sessions/session-2/_context-s-2.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# _context-s-2 — SESSION-MODEL narrative durable
|
||||||
|
|
||||||
|
<!-- SCAFFOLD-META: sID=2 | ts-moc=2026-07-23T17:47:37+07:00 | nguon-ts=git log -1 --format=%cI @ 5815442 | generator=NONE (viet tay @S148 — SE chua port scripts/session_scaffold.py) -->
|
||||||
|
|
||||||
|
> **sID (LOGIC-session) = 2.** 1 phiên-logic trải nhiều window vật-lý nối bằng `/pause` + `/tiep`. Window = 0-ID governance; **sID = đơn-vị LOGIC**. Folder pin: `.claude/sessions/session-2/`.
|
||||||
|
> ts-mốc khởi-tạo = **2026-07-23T17:47:37+07:00** (nguồn: `git log -1 --format=%cI @ 5815442` — mốc git-committer, KHÔNG phải wall-clock tuỳ-tiện).
|
||||||
|
>
|
||||||
|
> 🔴 **CẤM rewrite / tự-tóm block FLOW** (chống self-summary lossy). FLOW = append-only @`/pause`-only; vượt cap `session_ctx_kb` → distill SECTION CŨ thành pointer/gist, TUYỆT ĐỐI KHÔNG sửa entry verbatim đã ghi.
|
||||||
|
|
||||||
|
> 🧊 **KHAI THẬT — file này RETRO-CONVERT @S148 (2026-07-24), không sinh lúc phiên chạy.** SE trước đó dùng form riêng (`pause-S<nn>-<ts>.md` mang cả narrative). Owner chốt @S148 *"đối ứng đúng chính xác như hub"* ⇒ tách: **marker** → `_pause-<i>.md`/`_tiep-<i>.md` (5 trường) · **narrative** → file này. Nguồn narrative = `pause-S147-20260723T1744.md` + `resume-S148-...md` — 🔴 **cả hai ĐÃ GỠ khỏi thư-mục** (không phải "giữ tại chỗ" như bản đầu của dòng này viết): để lại thì **cùng một sự-kiện bị Sàn-3 đếm HAI lần** (`p=2 r=2` thay vì `p=1 r=1`) — vô-tình cân nên trông ổn, nhưng là cân giả. **Vết thật nằm ở git history**, không cần bản sao trong cây làm việc.
|
||||||
|
> 🔴 **Trường không tái-dựng được thì KHAI, KHÔNG BỊA:** `_pause-1.jsonl-hint` = `unknown-retro-converted-S148` (uuid transcript cửa-sổ S147 không còn truy được); tin-nhắn VERBATIM của anh ở PAUSE-1 **không được ghi lại lúc đó** ⇒ mục `> anh:` dưới ghi rõ là **THIẾU**, không dựng lại từ trí nhớ.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## (a) STOCK-map — reference-not-copy
|
||||||
|
|
||||||
|
> Bảng pointer tới nguồn durable. **KHÔNG copy nội-dung** (chống drift).
|
||||||
|
|
||||||
|
| Tên | Path | 1-dòng |
|
||||||
|
|---|---|---|
|
||||||
|
| WAL | `.claude/WAL.md` | mạch-việc-dở máy-state (H-22) — nối bằng `/tiep` |
|
||||||
|
| AI-context | `CLAUDE.md` | AI agent context SOLUTION_ERP (scope + quick-rules) |
|
||||||
|
| Trạng-thái hiện-tại | `docs/STATUS.md` | canonical mọi con-số (mig · bảng · test · roster) |
|
||||||
|
| Bàn-giao + backlog | `docs/HANDOFF.md` | brief 5 phút + bảng số chờ-anh + carry |
|
||||||
|
| Sổ đếm H24 | `.claude/governance/.session-counter.json` | counter + nhịp lead-self-audit |
|
||||||
|
| Sổ thư cross-project | `broadcasts/_index.md` | INBOUND directed (`outbox/se`) — fan-out `outbox/all` KHÔNG vào đây |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## (b) FLOW — append-only @pause-only
|
||||||
|
|
||||||
|
> 🔴 **CẤM rewrite FLOW.** Mỗi `/pause` APPEND đúng 1 entry. Entry cũ = immutable. FLOW = SOURCE durable của "đang-đến-đâu"; bảng-đầu-việc = VIEW derive từ đây.
|
||||||
|
|
||||||
|
FLOW-START
|
||||||
|
|
||||||
|
### PAUSE-1 2026-07-23T17:44:00+07:00
|
||||||
|
|
||||||
|
> anh: **(THIẾU — không ghi lại lúc đó.** Form SE cũ không có trường verbatim; retro-convert @S148 CẤM dựng lại từ trí nhớ. Từ PAUSE-2 trở đi bắt buộc chép nguyên văn.**)**
|
||||||
|
|
||||||
|
**Quyết-định đã CHỐT trong cửa này (S147 — product/UAT):**
|
||||||
|
- **① Bug đính-kèm "Bảng so sánh" khi phiếu Trả lại:** gate nút xoá/tải theo `(isAdmin||isDrafter) && isEditablePhase(phase)` THAY `readOnly` màn-hình; cắm `:2013` KHÔNG `:421` (tránh HoSoLink bleed); descope `SupplierAttachmentsCell` (giữ Mig28 F3 carve-out); KHÔNG thêm BE guard (giữ S78). Cả 2 app.
|
||||||
|
- **② Chuẩn-hoá mã dự-án:** owner chốt "chỉ cắt đầu/cuối" cho LƯU (Trim); lead thêm kiểm-trùng bỏ-dấu-cách chặn tái-phát (KHÔNG đổi cách lưu). +4 test guard.
|
||||||
|
- **② Gom dự-án trùng trên PROD:** giữ bản no-space, ẩn mềm bản dấu-cách; owner chọn (B) *"có sẵn đường SQL máy vào điều chỉnh luôn"* → qua `ssh vietreport-vps` integrated-auth `-E` (không chạm password). Owner dặn *"sau này sẽ chạy tối ưu kỹ lại chỗ này"* = first-pass, KHÔNG phải tối-ưu cuối.
|
||||||
|
- **Push deploy:** owner *"OK làm đi"* → 2 commit + push, CI #407 PASS.
|
||||||
|
|
||||||
|
**Delta còn SỐNG:**
|
||||||
|
- 🟢 KHÔNG có mạch dở. Cả 2 việc DONE + deploy live + verified 2-nguồn + closeout pushed.
|
||||||
|
- ⏳ UAT nghiệm-thu ① (bạn kia mở phiếu **Trả lại** → màn "Danh sách" → "Bảng so sánh giá" → nút X + tải lên hiện lại).
|
||||||
|
- ⏳ ② tối-ưu kỹ lại chuyện gom dự-án — owner hẹn sau (future, KHÔNG phải việc đang dở).
|
||||||
|
- 🔵 20 carry governance S146 + NEXT items VẪN MỞ.
|
||||||
|
|
||||||
|
**Con-trỏ:** code `7d39d8d` (① FE 2-app) + `4510cea` (② BE+test) · closeout docs `5f6c3be` · script gom `docs/changelog/data-fixes/2026-07-23-merge-duplicate-projects.sql` · log `docs/changelog/sessions/2026-07-23-1730-S147-pe-attach-fix-project-dedup.md` · bundle admin `B2j1LQ-v` / user `C3wbJegk` · state Mig 67 · 89 bảng · 532 test.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### TIEP-1 2026-07-24T00:10:00+07:00 *(cửa-sổ 2 — nhãn phiên S148)*
|
||||||
|
|
||||||
|
> 🔸 Ghi ở đây để FLOW liền mạch; marker máy ở `_tiep-1.md`. Hub form không đòi entry TIEP trong FLOW — **SE thêm có chủ đích** vì `/tiep` là nơi ground-truth-reconcile xảy ra, và kết-quả reconcile là thứ cửa sau cần đọc.
|
||||||
|
|
||||||
|
- Sàn-3 5/5: ⑤ ORPHAN-L kêu đúng (bàn-giao pause→tiep), đóng bằng biên-nhận.
|
||||||
|
- `verify:` **KHỚP 3/3, 0 lệch** (`rev-list 0 1` · origin `5f6c3be` · eoffice 200) ⇒ KHÔNG sửa WAL.
|
||||||
|
- H24 tick S147→S148: counter **21→22 CLEAN** (`5f6c3be` còn reachable, exit 0 — khác `squash-benign` của S147). `NHIP-NO: light 5/6 · deep 5/15 ok`.
|
||||||
|
- Việc cửa này: re-stamp HANDOFF khớp đĩa (#1 ĐÓNG · #3 chốt-(a) · #2 đổi trục) · wire `/check-email` 4 cửa 2 chế-độ · STAGE-2 10 thư fan-out · migrate session-model sang form hub.
|
||||||
8
.claude/sessions/session-2/_end
Normal file
8
.claude/sessions/session-2/_end
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
summary-frozen-s2: ### SE — session-2 (2026-07-23→24 · 2-window logic-session {pause-1 @S147 · tiep-1 @S148 · snapshot-1} — S147 product/UAT ship-prod → /pause → S148 /tiep: re-stamp HANDOFF + /check-email 4-cửa-2-chế-độ + STAGE-2 10 thư fan-out + PORT session-model FORM HUB + Sàn-3 dual-accept + port /snapshot & 2 script + H24 force-fire 9-FLAG → /session-end)
|
||||||
|
pointer: docs/changelog/sessions/2026-07-24-1800-S148-session-model-form-hub.md
|
||||||
|
carry: session-model-adopt · context-stock(nửa — session_ctx_kb vẫn ghost-wire) · tiep-window-crash(#18 CHƯA wire) · meld-forward-unmeasured · bookend-5-5 · snapshot-cmd(ĐÓNG) · pause-autosnap(ĐÓNG) · tools-whitelist-no-teeth(thu hẹp còn vế chờ-hub) · pull-warn-threshold(đổi trục) · hook-vs-budget-cap · carry-age-vacuous · uat-s117 · uat-s133-budget-freeze · uat-s134-luyke · pe-phanquyen · bvaau · binh-le-decision · tra-bui-relogin · account-trung · hub-review-wave-1807
|
||||||
|
pending-anh: 16 mục đánh số trong HANDOFF (#4-#19; #1 #2 #3 ĐÓNG @S148) — nổi bật: #14 nhãn model lead (settings=Opus từ 07-20 vs STATUS kể Fable 5) · #15 ngưỡng "điểm-dừng RẺ" (owner-SỐ, lead đã đo hộ 5ms/200-500ms) · #16 khuôn nhãn spawn ĐẾN HẠN (phủ 1/4 loại) · #17 O-2 trục-sâu · #18 O-3 gộp-hay-tách vai-KIỂM · #19 O-7 trần width=16
|
||||||
|
pointers: .claude/workflows/runs/2026-07-24-S148-h24-force-fire/ (cặp H24 force-fire P=1, 9 FLAG) · .claude/workflows/runs/2026-07-22-S144-adap-dot-11/ (bảng owner-gated O-1..O-7) · .claude/workflows/runs/2026-07-22-S144-trio-first-run/
|
||||||
|
h24-tick: counter=22 · last_audit light=22 deep=17 · backfill entry S146 (JUMP đã chạm từ S146, phát hiện @S148)
|
||||||
|
markers: _pause=1 · _tiep=1 · _snapshot=1 (S147 pause 17:44 → S148 tiep 00:10 nối; snapshot-1 ghi @17:32 chốt port session-model)
|
||||||
|
honest-caveat: KHÔNG adapt đủ. Form session-model xong nhưng #18 tiep-window-crash CHƯA wire · session_ctx_kb CHƯA có reader · meld-forward CHƯA ĐO · C14 còn 6 khoản BLOCKED/DEFER (1.3/1.4 nhãn spawn ĐẾN HẠN chưa áp · 2.3 · 2.4 · 3.1-sâu/3.2/3.3) · 3 khoản owner-gated O-2/O-3/O-7 câm 5 nhãn nay mới kéo lên bảng số. Đây là _end ĐẦU TIÊN SE ghi thật (trước đó chỉ có form legacy closed.md @session-1).
|
||||||
5
.claude/sessions/session-2/_pause-1.md
Normal file
5
.claude/sessions/session-2/_pause-1.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
ts: 2026-07-23T17:44:00+07:00
|
||||||
|
head-sha: 5f6c3becfb4ce958c7edad7d9f1058cb7289491e
|
||||||
|
window-ordinal: 1
|
||||||
|
jsonl-hint: unknown-retro-converted-S148
|
||||||
|
account-label: none
|
||||||
34
.claude/sessions/session-2/_snapshot-1.md
Normal file
34
.claude/sessions/session-2/_snapshot-1.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# _snapshot-1 — SESSION-MODEL checkpoint (sID 2)
|
||||||
|
|
||||||
|
ts: 2026-07-24T17:32:19+07:00
|
||||||
|
head-sha: 3a1bb2505631eefe062303775c35ef2f17440a82
|
||||||
|
head-subject: wal: flush 20260724T1732
|
||||||
|
head-ts: 2026-07-24T17:32:19+07:00
|
||||||
|
label: session-model port trọn form hub + /snapshot + 2 script (anh chốt "1,2 làm đi ko cần hỏi hub")
|
||||||
|
snapshot-ordinal: 1
|
||||||
|
|
||||||
|
## essence (≤3 dòng — chốt cái CHƯA nằm file)
|
||||||
|
- Port XONG form hub: `_context-s-2.md` (STOCK+FLOW+STOCK-touched) · `_pause-1`/`_tiep-1` marker 5-trường · `_end` thay `closed.md`; 4 lệnh đồng-bộ; Sàn-3 ⑤ DUAL-ACCEPT hub+legacy, fault-inject 10/10 hai chiều + bắt được bug `c=1` có sẵn từ S146 (chốt-kết nay ĐÓNG TRỌN thư-mục).
|
||||||
|
- Port XONG 2 script hub: `session_scaffold.py` (near-verbatim, idempotent) + `session_ctx.py` **TRIMMED CÓ KHAI** (chỉ `machine-block` + `secrets-sweep`; KHÔNG port jsonl/overhead/cap-getter vì SE chưa có caller — port không caller = ghost-wire). secrets-sweep fault-inject 2 chiều CÓ RĂNG (chặn đúng mẫu-1 trong 4 Category-5, 0 dương-giả với chuỗi chứa cùng 2 ký-tự nhưng khác token). 🔴 Gate NỔ THẬT ngay lượt dùng đầu: bản nháp dòng này viết literal mẫu đó ⇒ bị CHẶN — **citation-trap**, xử bằng cách đổi CHỮ, tuyệt đối không nới detector.
|
||||||
|
- Đây là `_snapshot` ĐẦU TIÊN của SE — viết bằng chính `/snapshot` vừa port, để lệnh không thành ghost-wire. Auto-snap tại `/pause` wire kèm, chi-phí ròng đo được **~64ms** (machine-block ~140ms vốn đã phải chạy cho §(c)).
|
||||||
|
|
||||||
|
## machine-block
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"session": 2,
|
||||||
|
"anchor": {
|
||||||
|
"subject": "[CLAUDE] Docs: S147 closeout — PE attach-fix (Trả lại) + project-dedup ship-prod",
|
||||||
|
"ts": "2026-07-23T17:37:59+07:00"
|
||||||
|
},
|
||||||
|
"anchor_from_fallback_since": false,
|
||||||
|
"changed_files": [
|
||||||
|
".claude/WAL.md",
|
||||||
|
".claude/governance/.session-counter.json",
|
||||||
|
".claude/sessions/session-2/_context-s-2.md",
|
||||||
|
".claude/sessions/session-2/_pause-1.md",
|
||||||
|
".claude/sessions/session-2/_tiep-1.md"
|
||||||
|
],
|
||||||
|
"changed_count": 5,
|
||||||
|
"run_id": null
|
||||||
|
}
|
||||||
|
```
|
||||||
5
.claude/sessions/session-2/_tiep-1.md
Normal file
5
.claude/sessions/session-2/_tiep-1.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
ts: 2026-07-24T00:10:00+07:00
|
||||||
|
head-sha: 581544200b4773db810808c063f4245fe54e004c
|
||||||
|
window-ordinal: 2
|
||||||
|
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/30188142-8e93-45b6-a7f0-5b4ab078e36e
|
||||||
|
account-label: none
|
||||||
57
.claude/templates/session-context-template.md
Normal file
57
.claude/templates/session-context-template.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# _context-s-{{N}} — SESSION-MODEL narrative durable
|
||||||
|
|
||||||
|
<!-- SCAFFOLD-META: sID={{N}} | ts-moc={{TS}} | nguon-ts={{TS_SOURCE}} | generator=scripts/session_scaffold.py -->
|
||||||
|
|
||||||
|
> **sID (LOGIC-session) = {{N}}.** 1 phiên-logic (bootstrap → work → sweep) trải nhiều window vật-lý nối bằng `/pause`+`/tiep`. Window = 0-ID governance; **sID = đơn-vị LOGIC**. Folder pin: `.claude/sessions/session-{{N}}/`.
|
||||||
|
> ts-mốc khởi-tạo = **{{TS}}** (nguồn: `{{TS_SOURCE}}`) — mốc git-committer, KHÔNG phải wall-clock tuỳ-tiện.
|
||||||
|
>
|
||||||
|
> 🔴 **CẤM rewrite / tự-tóm block FLOW** (chống self-summary lossy). FLOW = append-only @`/pause`-only; vượt cap `session_ctx_kb` → distill SECTION CŨ thành pointer/gist, TUYỆT ĐỐI KHÔNG sửa entry verbatim đã ghi.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## (a) STOCK-map — reference-not-copy
|
||||||
|
|
||||||
|
> Bảng pointer tới nguồn durable. **KHÔNG copy nội-dung** (chống drift). Điền @bootstrap; row session-specific append dưới các row stable.
|
||||||
|
|
||||||
|
| Tên | Path | 1-dòng |
|
||||||
|
|---|---|---|
|
||||||
|
| WAL | `.claude/WAL.md` | mạch-việc-dở máy-state (H-22) — nối bằng `/tiep` |
|
||||||
|
| AI-context | `CLAUDE.md` | AI agent context SOLUTION_ERP (scope + quick-rules) |
|
||||||
|
| Trạng-thái | `docs/STATUS.md` | canonical mọi con-số (mig · bảng · test · roster) |
|
||||||
|
| Bàn-giao | `docs/HANDOFF.md` | brief 5 phút + bảng số chờ-anh + carry |
|
||||||
|
| Sổ đếm H24 | `.claude/governance/.session-counter.json` | counter + nhịp lead-self-audit |
|
||||||
|
| Thư cross-project | `broadcasts/_index.md` | INBOUND directed (`outbox/se`) — fan-out `outbox/all` KHÔNG vào đây |
|
||||||
|
| _(session-specific)_ | _(path)_ | _(1-dòng — append @bootstrap phiên này)_ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## (b) FLOW — append-only @pause-only
|
||||||
|
|
||||||
|
> 🔴 **CẤM rewrite FLOW.** Mỗi `/pause` APPEND đúng 1 entry theo SCHEMA dưới (đặt DƯỚI dòng `FLOW-START`). Entry cũ = immutable. FLOW = SOURCE durable của "đang-đến-đâu"; bảng-đầu-việc = VIEW derive từ đây (single-source).
|
||||||
|
|
||||||
|
<!-- ENTRY-SCHEMA (guidance, KHONG phai entry that — /pause command dien; parser real-entry match `^### PAUSE-\d+`, placeholder `<k>` khong false-match):
|
||||||
|
|
||||||
|
### PAUSE-<k> <ts ISO-8601>
|
||||||
|
|
||||||
|
> anh: <tin-nhan anh VERBATIM — copy nguyen-van, KHONG paraphrase>
|
||||||
|
|
||||||
|
**(1) quyet-dinh da CHOT** / **(2) delta con SONG** / **(3) con-tro**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "machine_block": "python scripts/session_ctx.py machine-block --session <N> --json" }
|
||||||
|
```
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- FLOW-START — entries append bên dưới dòng này, mới nhất ở CUỐI -->
|
||||||
|
|
||||||
|
_(chưa có PAUSE — entry đầu append @`/pause` đầu tiên của phiên)_
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## (c) STOCK-touched — máy-derive
|
||||||
|
|
||||||
|
> Bảng file-đã-đụng trong phiên, **máy-derive** từ `git diff --name-only <anchor>..HEAD` @pause/snapshot. KHÔNG điền tay.
|
||||||
|
|
||||||
|
| File | Δ | Ghi-chú |
|
||||||
|
|---|---|---|
|
||||||
|
| _(máy-derive @pause/snapshot)_ | | |
|
||||||
13
.claude/workflows/runs/2026-07-24-S148-h24-force-fire/run.md
Normal file
13
.claude/workflows/runs/2026-07-24-S148-h24-force-fire/run.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# run — S148 H24 force-fire (closeout gộp P=1)
|
||||||
|
|
||||||
|
## Vì sao chạy
|
||||||
|
§L.b(j)(vi): `P=1` (`wal: pause` gộp vào closeout này, closeout-liền-trước = `5f6c3be`) ⇒ **OVERDUE(light) bất kể counter** ⇒ spawn cặp H24 NGAY, **KHÔNG consent** (owner chốt @S146 "3 → auto").
|
||||||
|
Counter tại thời điểm chạy: **22** · light 5/6 · deep 5/15 (chưa tới nhịp tự nhiên — đây là **force-fire**, không phải tới hạn).
|
||||||
|
|
||||||
|
## Stages
|
||||||
|
- [!] W1 lead-view-auditor
|
||||||
|
- [!] W2 lead-omission-auditor
|
||||||
|
- [ ] W3 h24-audit (vai KIỂM, SAU cặp)
|
||||||
|
|
||||||
|
## taskList snapshot
|
||||||
|
Soi LEAD trong phiên S148 (một phiên rất dài, nhiều bề mặt governance bị sửa).
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,72 @@
|
|||||||
|
# S148 — session-model port form hub + /check-email 4 cửa + Sàn-3 dual-accept
|
||||||
|
|
||||||
|
**Ngày:** 2026-07-24 · **Vào phiên bằng:** `/tiep` (nối S147) · **Lead:** Opus 4.8
|
||||||
|
**Loại:** governance-only — 0 prod-code, 0 migration, bundle FROZEN.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Arc phiên
|
||||||
|
|
||||||
|
`/tiep` sạch → giải-thích 3 mục chờ-anh → **phát hiện #1 đã xong từ S144** → owner chốt #3=(a) → owner **đổi trục #2** (sự-kiện-phiên thay ngưỡng-ngày) → wire `/check-email` 4 cửa → `/check-email AI_INFRA` **lộ 10 thư fan-out tồn 5 ngày** → STAGE-2 → owner chỉ form hub → **migrate session-model** → owner "1,2 làm đi" → **port `/snapshot` + 2 script** → commit `977ba18` → `/session-end`.
|
||||||
|
|
||||||
|
## Việc đã đóng
|
||||||
|
|
||||||
|
| # | việc | bằng chứng |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | Re-stamp `HANDOFF` bảng số | #1 ĐÓNG (trio chạy @S144, `runs/2026-07-22-S144-trio-first-run/` + `8b6df0a`) · #2 đổi trục · #3 owner (a) · +4 mục (13)–(16) |
|
||||||
|
| 2 | `/check-email` **4 CỬA + 2 CHẾ-ĐỘ** | canonical 1 nhà + 4 con-trỏ (B1). DÒ ~5ms ở `pause`/`tiep` ⟂ KÉO ở bookend — vá vi-phạm **khoản-3 BINDING** hub `goi-chot` |
|
||||||
|
| 3 | STAGE-2 10 thư fan-out | verify 2 tuyến **10/10** (whole-file + `stamp_verify` exit 0) → `inbox/ai_infra/`; backlog root = 0 |
|
||||||
|
| 4 | **session-model → FORM HUB** | `_context-s-2.md` · `_pause-1.md` · `_tiep-1.md` · `_snapshot-1.md` · `closed.md`→`_end`; 4 lệnh đồng-bộ |
|
||||||
|
| 5 | Sàn-3 ⑤ ORPHAN-L | DUAL-ACCEPT hub+legacy · fault-inject **10/10 hai chiều** + anti-Goodhart |
|
||||||
|
| 6 | Port `/snapshot` + 2 script | `session_scaffold.py` near-verbatim · `session_ctx.py` **TRIMMED CÓ KHAI** |
|
||||||
|
|
||||||
|
## 🔴 Bốn lỗi tự bắt trong phiên (giữ vết)
|
||||||
|
|
||||||
|
1. **Vi phạm ràng buộc BINDING 20 phút sau khi tạo ra nó** — cắm PULL đầy đủ vào `/pause`+`/tiep` (cửa dừng-nối) trong khi hub `goi-chot` §3 cấm làm chúng đắt. Hub bắt **đo wall-clock** → đo → tách 2 chế-độ.
|
||||||
|
2. **Vá một tool không hỏng theo một lời khai không đo** — `C14:21` khai *"kẽ đã bịt"*; grep = **0 hit** ⇒ chưa hề bịt, VÀ `outbox/all` chưa bao giờ là việc của `/check-email` (đó là `/adap-apply`). Kiểm ngược: **22/22** thư directed có dòng index ⇒ tool vốn không thủng. **Kẽ THẬT ở NHỊP.**
|
||||||
|
3. **Báo cáo sai "sổ `_index` thiếu 17 dòng"** — cả 17 là fan-out, sổ **cố ý loại** (header dòng 7). Lead áp nhầm luật cho kênh.
|
||||||
|
4. **Cân giả tự tạo** — giữ cả 2 form trong `session-2` làm "vết" ⇒ cùng sự kiện bị đếm 2 lần (`p=2 r=2`), **vô tình cân nên trông ổn**. Đã gỡ; vết thật nằm ở git history.
|
||||||
|
|
||||||
|
## Bug có sẵn được fault-inject moi ra
|
||||||
|
|
||||||
|
**Sàn-3 chốt-kết `c=1`** (sống từ S146): code cộng `+1` rồi so `p > r + c` ⇒ chỉ tha **đúng một** pause; phiên đã đóng mà dư ≥2 pause vẫn **KÊU OAN** — lệch đúng câu `session-end §6.3-bis` vẫn luôn nói *"mọi pause coi như đã đối-ứng"*. Không lộ vì SE mới có `p=1`. Vá: chốt-kết **ĐÓNG TRỌN thư-mục**.
|
||||||
|
|
||||||
|
## H24 force-fire (P=1)
|
||||||
|
|
||||||
|
`P=1` `wal: pause` gộp vào closeout ⇒ **OVERDUE(light) bất kể counter** ⇒ spawn cặp H24 **AUTO, không consent** (owner @S146). Run: `runs/2026-07-24-S148-h24-force-fire/`.
|
||||||
|
|
||||||
|
🔴 **Cả 2 vai garble #53** (sổ đếm ×25 qua S143 → **×27**). Phân hoá đúng bài học S123:
|
||||||
|
- `lead-view-auditor` **ghi diary TRONG lúc làm** ⇒ **vớt trọn từ đĩa**, 0 mất dữ liệu.
|
||||||
|
- `lead-omission-auditor` **KHÔNG ghi** (mtime còn 13:10 phiên trước) ⇒ phải **SendMessage-resume**.
|
||||||
|
⇒ Bằng chứng thứ N cho: **chặn được #53 = ghi-đĩa-trong-lúc-làm**, không phải prompt đúng.
|
||||||
|
|
||||||
|
### FLAG nặng nhất — CANONICAL-POISON (lead verify 3 nguồn độc lập)
|
||||||
|
|
||||||
|
`docs/STATUS.md:448` ô canonical Tests ghi **528 (45D+483I)** trong khi `STATUS:6` **và** session-log S147 đều ghi **532 (45D+487I)** ⇒ closeout S147 vá header mà **quên ô canonical**.
|
||||||
|
**Hệ quả:** detector đọc canonical=528 ⇒ mọi flag C2/B3 về test đo bằng **thước sai**; và `[OK] canonical matches disk` chỉ cross-check **mig+gotcha**, **KHÔNG** cross-check test ⇒ mù đúng chỗ.
|
||||||
|
**Cặp bất-đối-xứng NGƯỢC CHIỀU cùng file:** `STATUS:6` ghi "gotcha 82" trong khi row=83 và `gotchas.md` anchor max=**83**.
|
||||||
|
⇒ **Một file, hai row, mỗi row stale một chiều khác nhau.** Cả hai đã vá @S148.
|
||||||
|
**Bài:** *đừng giả định canonical luôn đúng chỉ vì nó tên là canonical*; và **cross-check của máy phủ tới đâu thì mới tin tới đó**.
|
||||||
|
|
||||||
|
✅ **Chốt bằng MÁY, không bằng sổ** — `dotnet test SolutionErp.slnx` chạy tươi @S148:
|
||||||
|
```
|
||||||
|
Passed! - Failed: 0, Passed: 45, Total: 45 — SolutionErp.Domain.Tests.dll
|
||||||
|
Passed! - Failed: 0, Passed: 487, Total: 487 — SolutionErp.Infrastructure.Tests.dll
|
||||||
|
```
|
||||||
|
⇒ **532 = 45D + 487I, 0 fail / 0 skip.** Ô canonical `528/483I` **sai thật**; con số vá vào không phải "2-trong-3 sổ đồng ý" mà là **máy vừa in**.
|
||||||
|
|
||||||
|
## memory-triple
|
||||||
|
|
||||||
|
```
|
||||||
|
memory-triple: do=scripts/measure-agent-memory.ps1 · exit 0 (l1_over_30kb=false)
|
||||||
|
memory-triple: de-xuat=scripts/memory-archive-gate.ps1 DRY · exit 0 (A7 GATE PASS 253/253 pointer)
|
||||||
|
memory-triple: kiem=trio KHÔNG chạy (consent-gated, phiên đã rất dài — skip có vết)
|
||||||
|
memory-triple: do-record=governance-detectors TOTAL=46
|
||||||
|
memory-triple: do-record=NHIP-NO: kiem light 5/6 deep 5/15 ok | tran-bo-nho 0 over-cap | run-chua-gom 0 | pull-cach 2 ngay
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nấc trung thực — CHƯA đủ (trả lời câu owner hỏi cuối phiên)
|
||||||
|
|
||||||
|
Owner hỏi *"adapt đủ các vòng và session-model rồi chứ nhỉ?"* → **CHƯA**:
|
||||||
|
- **session-model:** form ✅ · `_end` **lần đầu ghi ở chính closeout này** · **#18 `tiep-window-crash` CHƯA wire** (`grep _snapshot tiep.md`=0) · `session_ctx_kb` **vẫn ghost-wire** (cố ý không port cap-getter) · meld-forward **CHƯA ĐO** · #20 bookend 5/5 treo
|
||||||
|
- **các vòng (C14):** 1.3/1.4 nhãn spawn **ĐẾN HẠN chưa áp** (phủ 1/4 loại) · 2.3 BLOCKED thực-thi · 2.4 chưa có máy · 3.1-sâu/3.2/3.3 chưa có trục sâu · 4.1 + 4.3 **chờ chữ ký owner** (= mục #14/#15)
|
||||||
220
scripts/session_ctx.py
Normal file
220
scripts/session_ctx.py
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""session_ctx.py -- session-model derive helpers (SE port, S148 2026-07-24).
|
||||||
|
|
||||||
|
SE PORT of AI_INFRA scripts/session_ctx.py -- 🔴 TRIMMED ON PURPOSE, KHAI RO:
|
||||||
|
hub's original (~26 KB) also carries jsonl transcript parsing, anh-message containment
|
||||||
|
verification, token-overhead accounting and a context-cap getter. SE ports only the TWO
|
||||||
|
capabilities its rituals actually call:
|
||||||
|
|
||||||
|
machine-block -> derive {anchor, changed_files, run_id} for /snapshot + /pause
|
||||||
|
secrets-sweep -> pre-commit Category-5 gate over a session dir
|
||||||
|
|
||||||
|
NOT ported (do NOT claim these exist here): verify-containment / overhead / cap-getter /
|
||||||
|
window-jsonl resolution. Porting them without a caller would be ghost-wire -- the exact
|
||||||
|
class SE keeps getting bitten by. Add one ONLY when a ritual actually needs it.
|
||||||
|
|
||||||
|
Fidelity pin: field semantics + CLI shape follow hub so a future hub change can be
|
||||||
|
re-pulled by diff. Behaviour differences from hub are marked `SE-DELTA`.
|
||||||
|
|
||||||
|
stdlib-only . Python 3.11+ . UTF-8 no-BOM . LF . ASCII-only source.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
DEFAULT_SESSIONS_ROOT = ROOT / ".claude" / "sessions"
|
||||||
|
|
||||||
|
# Commits authored by the Stop-hook (wal-flush.ps1) -- never a valid anchor.
|
||||||
|
_WAL_SUBJECT_RE = re.compile(r'^wal:')
|
||||||
|
# runId as written into WAL by the hmw run-trace convention.
|
||||||
|
_RUNID_RE = re.compile(r'\b(wf_[A-Za-z0-9_-]+)')
|
||||||
|
|
||||||
|
# Category-5 secret prefixes. ACCEPTED-GAP: pattern-bounded, token-anchored -- this is a
|
||||||
|
# conservative pre-commit BLOCK, NOT a proof of cleanliness (a DB password in an anh-msg
|
||||||
|
# verbatim would pass). Say so; do not sell it as complete.
|
||||||
|
SECRET_PATTERNS = ('voyage', 'sk-', 'gitea_pat', 'cfut_')
|
||||||
|
_SECRET_RES = [(p, re.compile(r'\b' + re.escape(p), re.I)) for p in SECRET_PATTERNS]
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# git helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def _git(args, repo_root):
|
||||||
|
"""Run `git -C <repo_root> <args>`; return stdout. Fail-loud: a bad range is a real
|
||||||
|
error for a derive that must be reproducible."""
|
||||||
|
try:
|
||||||
|
r = subprocess.run(['git', '-C', str(repo_root)] + list(args),
|
||||||
|
capture_output=True, text=True, encoding='utf-8', errors='replace')
|
||||||
|
except (OSError, subprocess.SubprocessError) as e:
|
||||||
|
raise SystemExit(f"[session_ctx] git failed to launch: {e}")
|
||||||
|
if r.returncode != 0:
|
||||||
|
raise SystemExit(f"[session_ctx] git {' '.join(args)} -> rc={r.returncode}: {r.stderr.strip()}")
|
||||||
|
return r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_log_line(line):
|
||||||
|
parts = line.split('\x1f')
|
||||||
|
return {'sha': parts[0], 'subject': parts[1], 'ts': parts[2]} if len(parts) == 3 else None
|
||||||
|
|
||||||
|
|
||||||
|
def find_anchor(repo_root, max_scan=100):
|
||||||
|
"""Nearest NON-wal named commit walking git log from HEAD -> {sha, subject, ts} or None.
|
||||||
|
|
||||||
|
Why not HEAD: the Stop-hook auto-commits `wal:` at every turn boundary, and closeout
|
||||||
|
squash rewrites those shas. Anchoring on a named commit survives the rewrite; anchoring
|
||||||
|
on HEAD rots (sha AND subject/ts both move)."""
|
||||||
|
out = _git(['log', f'-n{max_scan}', '--format=%H%x1f%s%x1f%cI'], repo_root)
|
||||||
|
for line in out.splitlines():
|
||||||
|
rec = _parse_log_line(line)
|
||||||
|
if rec is None or _WAL_SUBJECT_RE.match(rec['subject']):
|
||||||
|
continue
|
||||||
|
return rec
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_ref(ref, repo_root):
|
||||||
|
"""Resolve an explicit anchor ref (sha/tag/HEAD~n) to {sha, subject, ts}."""
|
||||||
|
out = _git(['log', '-n1', '--format=%H%x1f%s%x1f%cI', ref], repo_root).strip()
|
||||||
|
return _parse_log_line(out.splitlines()[0]) if out else None
|
||||||
|
|
||||||
|
|
||||||
|
def _iso_utc(epoch):
|
||||||
|
return datetime.datetime.fromtimestamp(epoch, datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
|
|
||||||
|
|
||||||
|
def last_snapshot_mtime(session_dir):
|
||||||
|
"""mtime of the most recent _snapshot-* file (fallback --since anchor). None if absent."""
|
||||||
|
snaps = [s for s in Path(session_dir).glob('_snapshot-*') if s.is_file()]
|
||||||
|
return max(s.stat().st_mtime for s in snaps) if snaps else None
|
||||||
|
|
||||||
|
|
||||||
|
def live_run_id(repo_root=None, wal_path=None):
|
||||||
|
"""Live runId from .claude/WAL.md (LAST match = most-recently-appended). None if absent."""
|
||||||
|
wal = Path(wal_path) if wal_path else (Path(repo_root or ROOT) / ".claude" / "WAL.md")
|
||||||
|
if not wal.exists():
|
||||||
|
return None
|
||||||
|
matches = _RUNID_RE.findall(wal.read_text(encoding='utf-8', errors='replace'))
|
||||||
|
return matches[-1] if matches else None
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# (a) machine-block
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def machine_block(session_n, sessions_root=None, repo_root=None, anchor=None):
|
||||||
|
"""Derive {session, anchor{subject,ts}, changed_files, changed_count, run_id}.
|
||||||
|
|
||||||
|
`anchor` = explicit ref override (pin it for reproducibility); default = nearest non-wal.
|
||||||
|
Anchor is identified by {subject, ts}, NOT sha -- sha does not survive closeout squash."""
|
||||||
|
repo_root = Path(repo_root or ROOT)
|
||||||
|
sessions_root = Path(sessions_root) if sessions_root else DEFAULT_SESSIONS_ROOT
|
||||||
|
session_dir = sessions_root / f"session-{session_n}"
|
||||||
|
|
||||||
|
a = _resolve_ref(anchor, repo_root) if anchor is not None else find_anchor(repo_root)
|
||||||
|
used_fallback = False
|
||||||
|
if a is not None:
|
||||||
|
files_out = _git(['diff', '--name-only', f'{a["sha"]}..HEAD'], repo_root)
|
||||||
|
anchor_id = {'subject': a['subject'], 'ts': a['ts']}
|
||||||
|
else:
|
||||||
|
used_fallback = True
|
||||||
|
mt = last_snapshot_mtime(session_dir)
|
||||||
|
files_out = (_git(['log', f'--since={_iso_utc(mt)}', '--name-only', '--format='], repo_root)
|
||||||
|
if mt is not None else '')
|
||||||
|
anchor_id = {'subject': None, 'ts': None}
|
||||||
|
|
||||||
|
changed = sorted({f.strip() for f in files_out.splitlines() if f.strip()})
|
||||||
|
return {
|
||||||
|
'session': session_n,
|
||||||
|
'anchor': anchor_id,
|
||||||
|
'anchor_from_fallback_since': used_fallback,
|
||||||
|
'changed_files': changed,
|
||||||
|
'changed_count': len(changed),
|
||||||
|
'run_id': live_run_id(repo_root),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def render_machine_block(mb):
|
||||||
|
"""Deterministic text rendering for embedding into a _context FLOW entry."""
|
||||||
|
a = mb['anchor']
|
||||||
|
lines = ['<!-- machine-block: scripts/session_ctx.py machine-block (script-derive) -->']
|
||||||
|
lines.append(f'anchor: "{a["subject"]}" @ {a["ts"]}' if a['subject'] is not None
|
||||||
|
else 'anchor: (fallback --since mtime of last _snapshot-*)')
|
||||||
|
lines.append(f'runId: {mb["run_id"] or "(none)"}')
|
||||||
|
lines.append(f'changed-files ({mb["changed_count"]}, git diff --name-only anchor..HEAD):')
|
||||||
|
lines.extend(f' {f}' for f in mb['changed_files'])
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# (b) secrets-sweep
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def secrets_sweep(session_dir):
|
||||||
|
"""Scan the WHOLE write-set of a session dir for Category-5 patterns.
|
||||||
|
Returns list of hits {file, line, pattern, snippet}. See ACCEPTED-GAP at module top."""
|
||||||
|
session_dir = Path(session_dir)
|
||||||
|
hits = []
|
||||||
|
if not session_dir.exists():
|
||||||
|
return hits
|
||||||
|
for p in sorted(session_dir.rglob('*')):
|
||||||
|
if not p.is_file():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
text = p.read_text(encoding='utf-8', errors='replace')
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
for lineno, line in enumerate(text.splitlines(), 1):
|
||||||
|
for pat, rx in _SECRET_RES:
|
||||||
|
if rx.search(line):
|
||||||
|
hits.append({'file': str(p), 'line': lineno, 'pattern': pat,
|
||||||
|
'snippet': line.strip()[:120]})
|
||||||
|
return hits
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# CLI
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def main(argv=None):
|
||||||
|
ap = argparse.ArgumentParser(prog='session_ctx.py',
|
||||||
|
description='session-model derive helpers (SE port, trimmed).')
|
||||||
|
sub = ap.add_subparsers(dest='cmd', required=True)
|
||||||
|
|
||||||
|
mb = sub.add_parser('machine-block', help='derive anchor + changed-files + runId')
|
||||||
|
mb.add_argument('--session', type=int, required=True, metavar='N')
|
||||||
|
mb.add_argument('--anchor', default=None, help='explicit anchor ref (default: nearest non-wal)')
|
||||||
|
mb.add_argument('--json', action='store_true', help='emit JSON (default: rendered text)')
|
||||||
|
|
||||||
|
ss = sub.add_parser('secrets-sweep', help='Category-5 pre-commit gate over a session dir')
|
||||||
|
ss.add_argument('--session', type=int, required=True, metavar='N')
|
||||||
|
|
||||||
|
args = ap.parse_args(argv)
|
||||||
|
|
||||||
|
if args.cmd == 'machine-block':
|
||||||
|
block = machine_block(args.session, anchor=args.anchor)
|
||||||
|
print(json.dumps(block, ensure_ascii=False, indent=2) if args.json
|
||||||
|
else render_machine_block(block))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if args.cmd == 'secrets-sweep':
|
||||||
|
session_dir = DEFAULT_SESSIONS_ROOT / f"session-{args.session}"
|
||||||
|
hits = secrets_sweep(session_dir)
|
||||||
|
if not hits:
|
||||||
|
print(f"[secrets-sweep] session-{args.session}: 0 hit "
|
||||||
|
f"({len(SECRET_PATTERNS)} pattern, pattern-bounded -- KHONG phai chung-minh sach)")
|
||||||
|
return 0
|
||||||
|
# SE-DELTA: hub prints hits then exits 1; same contract, message localised.
|
||||||
|
print(f"[secrets-sweep] session-{args.session}: {len(hits)} HIT -- CHAN commit", file=sys.stderr)
|
||||||
|
for h in hits:
|
||||||
|
print(f" {h['file']}:{h['line']} [{h['pattern']}] {h['snippet']}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
raise SystemExit(main())
|
||||||
154
scripts/session_scaffold.py
Normal file
154
scripts/session_scaffold.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""session_scaffold.py -- scaffold 1 logic-session folder + _context skeleton.
|
||||||
|
|
||||||
|
SE PORT of AI_INFRA scripts/session_scaffold.py (adopted S148, 2026-07-24, owner
|
||||||
|
"doi ung dung chinh xac nhu hub"). Near-verbatim: the logic is repo-agnostic; only
|
||||||
|
the template CONTENT differs (SE STOCK-map rows). Kept stdlib-only + same CLI so a
|
||||||
|
future hub change can be re-pulled by diff instead of re-derived.
|
||||||
|
|
||||||
|
Tach LOGIC-session khoi VAT-LY window: tao `.claude/sessions/session-<N>/` +
|
||||||
|
`_context-s-<N>.md` tu template `.claude/templates/session-context-template.md`.
|
||||||
|
|
||||||
|
Design pins:
|
||||||
|
- path HARD-PIN: `.claude/sessions/session-<N>/` (KHONG configurable -- uniform cross-repo).
|
||||||
|
- ts-moc = `git log -1 --format=%cI` (committer ISO-8601 cua HEAD), KHONG datetime.now
|
||||||
|
tuy-tien; nguon-ts ghi thang vao file (audit). Fallback datetime.now CHI khi git down,
|
||||||
|
tag ro "FALLBACK".
|
||||||
|
- Idempotent: folder ton tai -> bao + KHONG de `_context` (chi tao neu thieu).
|
||||||
|
- Cap so <N> KHONG phai viec cua script nay -- caller truyen vao. Doc-quyen cap so =
|
||||||
|
/session-start (session-start.md BUOC 0.8); /pause va /tiep chi tao folder cho <N> dang mo.
|
||||||
|
|
||||||
|
stdlib-only . Python 3.11+ . UTF-8 no-BOM . LF.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
SESSIONS_SUBPATH: tuple[str, ...] = (".claude", "sessions")
|
||||||
|
TEMPLATE_SUBPATH: tuple[str, ...] = (".claude", "templates", "session-context-template.md")
|
||||||
|
|
||||||
|
|
||||||
|
def repo_root() -> Path:
|
||||||
|
"""Repo root via `git rev-parse --show-toplevel`; fallback = parent-of-scripts/."""
|
||||||
|
try:
|
||||||
|
out = subprocess.run(
|
||||||
|
["git", "rev-parse", "--show-toplevel"],
|
||||||
|
capture_output=True, text=True, check=True,
|
||||||
|
)
|
||||||
|
root = out.stdout.strip()
|
||||||
|
if root:
|
||||||
|
return Path(root)
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
||||||
|
pass
|
||||||
|
return Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def head_ts() -> tuple[str, str]:
|
||||||
|
"""Return (ts, source). Prefer HEAD committer ISO-8601, tagged with short-sha for audit."""
|
||||||
|
try:
|
||||||
|
out = subprocess.run(
|
||||||
|
["git", "log", "-1", "--format=%cI%x09%h"],
|
||||||
|
capture_output=True, text=True, check=True,
|
||||||
|
).stdout.strip()
|
||||||
|
if out:
|
||||||
|
ts, _, sha = out.partition("\t")
|
||||||
|
ts, sha = ts.strip(), sha.strip()
|
||||||
|
if ts:
|
||||||
|
return ts, f"git log -1 --format=%cI @ HEAD {sha}"
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
||||||
|
pass
|
||||||
|
return (
|
||||||
|
datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||||
|
"datetime.now(UTC) FALLBACK (git unavailable -- non-deterministic)",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def render(template_text: str, n: int, ts: str, ts_source: str) -> str:
|
||||||
|
"""Fill placeholders with str.replace (NOT str.format) so literal `{`/`}` in the
|
||||||
|
template's JSON schema example survive untouched."""
|
||||||
|
return (
|
||||||
|
template_text
|
||||||
|
.replace("{{N}}", str(n))
|
||||||
|
.replace("{{TS}}", ts)
|
||||||
|
.replace("{{TS_SOURCE}}", ts_source)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _rel(p: Path, root: Path) -> str:
|
||||||
|
try:
|
||||||
|
return p.relative_to(root).as_posix()
|
||||||
|
except ValueError:
|
||||||
|
return str(p)
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
ap = argparse.ArgumentParser(
|
||||||
|
prog="session_scaffold.py",
|
||||||
|
description="Scaffold 1 logic-session folder + _context skeleton "
|
||||||
|
"(.claude/sessions/session-<N>/). Idempotent; safe to re-run.",
|
||||||
|
)
|
||||||
|
ap.add_argument("--session", type=int, required=True, metavar="N",
|
||||||
|
help="logic-session ID N (folder = session-<N>, regex ^session-\\d+$)")
|
||||||
|
ap.add_argument("--dry-run", action="store_true", help="print planned actions, write NOTHING")
|
||||||
|
args = ap.parse_args(argv)
|
||||||
|
|
||||||
|
n: int = args.session
|
||||||
|
if n < 0:
|
||||||
|
print(f"ERROR: --session must be a non-negative integer (got {n})", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
root = repo_root()
|
||||||
|
session_dir = root.joinpath(*SESSIONS_SUBPATH) / f"session-{n}"
|
||||||
|
context_path = session_dir / f"_context-s-{n}.md"
|
||||||
|
template_path = root.joinpath(*TEMPLATE_SUBPATH)
|
||||||
|
|
||||||
|
if not template_path.is_file():
|
||||||
|
print(f"ERROR: template not found: {template_path}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
ts, ts_source = head_ts()
|
||||||
|
folder_exists = session_dir.exists()
|
||||||
|
context_exists = context_path.exists()
|
||||||
|
|
||||||
|
if args.dry_run:
|
||||||
|
print(f"[dry-run] session N = {n}")
|
||||||
|
print(f"[dry-run] ts (moc) = {ts}")
|
||||||
|
print(f"[dry-run] ts-source = {ts_source}")
|
||||||
|
print(f"[dry-run] template = {_rel(template_path, root)}")
|
||||||
|
print(f"[dry-run] session folder = {_rel(session_dir, root)} "
|
||||||
|
f"({'EXISTS' if folder_exists else 'would mkdir'})")
|
||||||
|
print(f"[dry-run] context file = {_rel(context_path, root)} "
|
||||||
|
f"({'EXISTS -> would SKIP (idempotent)' if context_exists else 'would write'})")
|
||||||
|
print("[dry-run] NOTHING written.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
created_folder = False
|
||||||
|
if not folder_exists:
|
||||||
|
session_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
created_folder = True
|
||||||
|
|
||||||
|
if context_exists:
|
||||||
|
print(f"[idempotent] {_rel(context_path, root)} EXISTS -- NOT overwriting.")
|
||||||
|
if created_folder:
|
||||||
|
print(f"[note] folder {_rel(session_dir, root)} was missing -> created "
|
||||||
|
f"(unusual: context present without folder).")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
template_text = template_path.read_text(encoding="utf-8")
|
||||||
|
rendered = render(template_text, n, ts, ts_source)
|
||||||
|
with open(context_path, "w", encoding="utf-8", newline="\n") as fh:
|
||||||
|
fh.write(rendered)
|
||||||
|
|
||||||
|
print(f"[created] folder = {_rel(session_dir, root)} ({'new' if created_folder else 'existed'})")
|
||||||
|
print(f"[created] context = {_rel(context_path, root)}")
|
||||||
|
print(f"[created] ts(moc) = {ts} (source: {ts_source})")
|
||||||
|
print("[note] NOT committed (commit theo nghi-thuc /pause | /snapshot | /session-end).")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user