20 KiB
runs/ — Run-trace convention (Harness-10 · cấu trúc PHẲNG)
Mục đích: mỗi workflow fan-out (RUN-TRACE mode) ghi lại 1 dấu-vết hoàn-chỉnh trong
runs/<run-id>/git TRACKED — plan + per-sub detail + bản-gom. (🧊 sổ_ledger.md2-nhịp RETIRED H18-B S100 — đo bắt-thật 0/15 lifetime + mode-A coverage 0/8; orphan-authority = folder-scan L1/L2 dưới.) TRACKED nghĩa là mọi write trong run-folder hiện tronggit diff→ audit trực-tiếp, không cần tin lời agent return. Adopt AI_INFRA Harness-10 (anh 06-18) + DELTAh10-flat-detector-refine(06-18). Convention cha:../README.md.🆕 REFINE 06-18 — cấu trúc PHẲNG. Trước đây mỗi run-folder có 2 thư mục con (
sub-md/+harvest/). NAY mọi vết tích nằm phẳng cùng MỘT cấp trongruns/<run-id>/; phân biệt bản-thô (raw, per-sub) vs bản-đã-soát (verified, gom) bằng TÊN file, KHÔNG bằng thư mục con. Lý do: engine (hmw.jsJS-sandbox no-fs) chỉ tạo artifact ở một cấp một cách tự nhiên — bỏ thư-mục-con sâu thì xoá luôn một điểm-hay-quên ngay tại gốc (không còn thư-mục-con-để-quên-dựng).
run-id = YYYY-MM-DD-h<NN>-<slug> (vd 2026-06-18-harness-audit-invest). Nhiều run cùng ngày → slug phân-biệt stage (-invest / -implement / -review).
C1 — Cấu trúc PHẲNG (mỗi runs/<run-id>/ — file cùng MỘT cấp)
runs/<run-id>/
├── run.md ← (1) PLAN — em main @P1: meta + mục-tiêu + agents-table + guards + status OPEN→CLOSE
├── sub-<role>-<i>.md ← (2) PER-SUB raw — 1 file/sub/turn, prefix `sub-` (vd sub-investigator-codebase-0.md)
├── sub-<role>-<i>.md (fan-out cùng-role → đánh số -0 / -1 …)
└── <stage>-synthesis.md ← (3) GOM verified — em main: bản-gom 1 turn, suffix `-synthesis.md` (vd invest-synthesis.md)
Phân-biệt raw vs verified bằng TÊN, KHÔNG bằng subfolder:
| Loại | Quy-ước TÊN | Ai ghi | Nội-dung |
|---|---|---|---|
| PLAN | run.md (cố định) |
em main @P1 | nguồn-sự-thật của run: workflow run-id (evidence B3 wf_…), adap/mandate, checkpoint, opened, input-spec (nếu nối stage trước), agents-table (# · role · task), guards áp cho sub, output-path, status OPEN→CLOSE. |
| PER-SUB (raw) | prefix sub- → sub-<role>-<i>.md |
write-sub tự ghi @P2 · read-only sub → em main scribe @P3 | full working detail 1 sub. 1 sub-MD / role / turn (cùng-role → -0/-1). Read-only sub (CHỈ Bash) KHÔNG Bash-write MD (mojibake) → trả findings+subMdPath, em main single-writer. |
| GOM (verified) | suffix -synthesis.md → <stage>-synthesis.md |
em main per-turn (C4) | gom sub-*+findings → 5-trục integrity → build-spec/synthesis. |
🟢 Quy-tắc nhận-diện: file bắt đầu bằng
sub-= bản-thô (per-sub); file kết bằng-synthesis.md= bản-đã-soát (gom).run.md= plan. Không cần mở file/không cần subfolder để biết loại — đọc TÊN là đủ. (Khớp../hmw.jsinject path: engine ghi-directruns/<run-id>/sub-<role>-<i>.md, KHÔNGsub-md/….)Live dogfood:
2026-06-18-harness-audit-invest/=run.md+audit-synthesis.mdCHỈ (KHÔNG subfolder, KHÔNG rawsub-audit-*.md) — vì 1 auditor fail-no-StructuredOutput + 2 truncated → em main self-gate ground-truth từ đĩa, không có raw-sub để scribe (xemaudit-synthesis.md:4). Ví-dụ tênsub-<role>-<i>.mdlà minh-hoạ QUY-TẮC-ĐẶT-TÊN, KHÔNG phải artifact bắt-buộc mỗi run. Run2026-06-18-harness-fix-implement/mới có đủ raw (sub-impl-sleepcmd.md+sub-impl-runsreadme.md+implement-synthesis.md) = full flat set điển-hình.
C2 — Scaffold run.md ở OPEN (em main @P1, TRƯỚC khi invoke Workflow)
hmw.js chạy JS-sandbox no-filesystem → KHÔNG tự tạo folder/file. Em main PHẢI Write @P1:
- Tạo run-folder + PLAN:
runs/<run-id>/run.md(điền plan đầy-đủ). 🆕 KHÔNG cầnmkdir sub-md//harvest//.gitkeep— filesub-*và*-synthesis.mdsẽ sinh ra phẳng cùng cấp trong cùng folder đó (engine + em main ghi 1 cấp). Ghi OPEN-beat vào— 🧊 retired H18-B S100 (KHÔNG ghi beat mới; ledger frozen giữ lịch-sử. Orphan-authority = folder-scan L1/L2).runs/_ledger.md- (nối stage) trỏ
input spec:trongrun.mdsang<stage>-synthesis.mdcủa run trước (vd implement đọcinvest-synthesis.md).
🔴 C2 là fragile-point. Quên scaffold = run chạy nhưng KHÔNG có dấu-vết = lỗ-hổng âm-thầm (không lỗi, không cảnh-báo — chỉ thiếu file). 3-layer (C5) là lưới giảm-thiểu, KHÔNG khoá-cứng. Xem C7. 🆕 Cấu trúc phẳng bỏ 1 trong 2 điểm-hay-quên (không còn subfolder-to-forget); dư-lượng còn lại = vẫn phải tự ghi
<stage>-synthesis.mdmỗi run (close-gate C5/L3 bắt nếu thiếu).
taskList snapshot (H22 — ghi TRƯỚC launch)
Sàn WAL-cho-workflow (Harness-22 S111) — chống đốt-lại-token + mất-memory khi chết GIỮA workflow. Điều-kiện áp: run WAL-hóa = ≥3 task HOẶC ước chạy >5 phút (khớp ../README.md FLIP-policy) → BẮT BUỘC RUN-TRACE + 2 vật-liệu dưới ghi xuống đĩa TRƯỚC/NGAY-SAU launch:
- Section
## taskList snapshottrongrun.md— ghi TRƯỚC khi phóng. Mỗirun.mdPHẢI có section này liệt-kê từng task sắp phóng: (role · label · prompt-gist 1-dòng) — đủ vật-liệu để/tieprelaunch-cắt-gọt các task CÒN LẠI mà KHÔNG cần transcript cũ. (= "snapshot tham-số" mục ⑤ broadcast H22: ghi {danh-sách-task · spec} xuống đĩa trước launch.) - Dòng WAL
wf:(5 trường) — ghi NGAY SAU launch vào.claude/WAL.md, lead điềnrunIdkhi engine trả về:wf:<mục-đích> run=<run-folder> runId=<id|pending> args=<snapshot-ref> done=<k>/<N> harvested=<yes|no|partial>—run=trỏruns/<run-id>/;args=trỏ section## taskList snapshottrongrun.md(KHÔNG nhét spec dài vào WAL);done=<k>/<N>+harvested=partialcập-nhật khi harvest-liền mỗi task xong. - 🔴 memory-pack KHÔNG snapshot (X6): re-derive TƯƠI lúc
/tiep— snapshot memory-pack cũ sẽ lỗi-thời sau khi đã harvest phần đã-xong.
C3 — Git-tracked: VERIFY 2 nấc tách-bạch (chỗ hay nhầm)
Run-folder PHẢI git TRACKED (re-include qua .gitignore:83 !.claude/**, last-match-wins). Verify ĐỦ 2 nấc — đừng dừng ở nấc 1:
# Nấc (i) — GỠ-KHỎI-IGNORE (tracked-eligible): exit != 0 = KHÔNG bị ignore
git check-ignore .claude/workflows/runs ; echo "exit=$?" # SE: exit=1 ✓ (không ignore)
# Nấc (ii) — THẬT-SỰ-COMMIT: liệt-kê ra file = đã `git add`/commit
git ls-files .claude/workflows/runs | wc -l # SE: 22 ✓ (non-empty = đã commit)
- Nấc (i)
check-ignoreexit != 0 = thư-mục KHÔNG nằm trong ignore (tracked-eligible). ⚠️ Mới là đủ-điều-kiện-track, CHƯA chắc đã commit. - Nấc (ii)
ls-filesnon-empty = thật-sự có file trong index (đãgit add/commit). 🔴 eligible ≠ committed: một foldercheck-ignoreexit!=0 NHƯNGls-filesrỗng = chưa hề commit (bằng-chứng sống tại AI_INFRA chính trường-hợp này). PHẢI chạy CẢ 2 lệnh. - 🔴 ĐÚNG PATH mới đáng tin. Path đúng =
.claude/workflows/runs(đầy-đủ từ repo-root). Bareruns/(tên trần) là path SAI — ở repo khác,git check-ignore runstừ repo-root có thể trả exit 0 (match nhầm rule khác / không match negation.claude/**) → đọc sai thành "bị ignore". (Quan-sát SE: cảrunslẫn.claude/workflows/runsđều trả exit=1 vì .gitignore SE không có rulerunstrần — nhưng ĐỪNG dựa may-rủi đó: luôn dùng path đầy-đủ.claude/workflows/runs.) - Bẫy exit-code khi dùng
-v:git check-ignore -v <path>trả exit 0 cho CẢ ignore lẫn negation (!.claude/**) → đừng đọc exit của-vđể kết-luận; dùng dạng không--vở trên (exit!=0 = không ignore) hoặc&& echo IGNORED || echo NOT.
C4 — Per-turn primary (gom NGAY, không đợi session-end)
Gom là việc của turn, không defer. Sau MỖI fan-out turn → em main đọc sub-*+findings → ghi <stage>-synthesis.md liền trong turn đó (chính file synthesis này là bằng-chứng). Lợi: detail tươi, không mất qua nén-context; session-end chỉ VERIFY (không tái-tạo). Đây là đường CHÍNH (primary); gom toàn-bộ @session-end (L3) chỉ là lưới an-toàn (safety-net), KHÔNG phải đường chính.
C5 — 3-layer anti-miss (lưới chống bỏ-sót — KHÔNG khoá-cứng-cùng-lúc-fire)
| Layer | Khi | Làm gì |
|---|---|---|
| L1 in-run folder-check (🧊 ledger-check retired H18-B S100) | em-main @P1, lúc mở run mới (TRƯỚC scaffold) | scan runs/*/: nếu run TRƯỚC còn folder có run.md mà thiếu <stage>-synthesis.md (hoặc synthesis 0-byte) → gom + đóng nó TRƯỚC khi mở run mới. (L1 là convention EM-MAIN, KHÔNG phải hmw.js prompt. hmw.js chỉ emit C4 per-turn return-instruction cho sub tại writeGuard.) |
| L2 session-start orphan-scan | đầu session (session-start.md §2.1.1 H2) |
scan runs/*/ tìm orphan = folder có run.md mà KHÔNG có <stage>-synthesis.md (hoặc synthesis 0-byte) → báo + giải-quyết. (🧊 tiêu-chí ledger-⏳ retired H18-B S100; run cũ S71 dual-accept harvest/<stage>-synthesis.md.) |
| L3 session-end close-gate | cuối session (session-end.md §L.b(f) H2) |
VERIFY per-turn gom đã xong cho mọi runs/<id>/ (idempotent — KHÔNG re-APPEND, chống DUPLICATE-HARVEST) + 5-trục GATE backstop trước khi commit. 🆕 close-gate chấp nhận CẢ 2 dạng (old-subfolder + new-flat) trong giai-đoạn chuyển — xem C8. |
3 layer độc-lập, fire ở 3 thời-điểm khác nhau (run-open @P1 / session-start / session-end) — KHÔNG layer nào do engine enforce (hmw.js no-fs), cả 3 là convention em-main/H2. → giảm xác-suất sót, KHÔNG triệt-tiêu. Sót ở P1 (C2) cùng blind-spot với L1 (đều @P1) → chỉ bắt MUỘN ở L2 (session sau) / L3 (close-gate).
C6 — Ledger 2-nhịp + orphan resolution (_ledger.md) — 🧊 RETIRED H18-B S100 (nguyên-văn dưới GIỮ làm lịch-sử — dời-đi không xoá; orphan-authority = folder-scan C5 L1/L2; đảo-ngược = gỡ marker này + marker _ledger.md header + restore mandate C2-step-2)
Sổ tất-cả run, 1 bảng. Mỗi run 2 lần ghi (2-nhịp):
- OPEN-beat (@P1, lúc scaffold): thêm dòng
| <run-id> | <workflow> | <opened> | ⏳ | <agents> | ⏳ | <stage>-synthesis.md |. - CLOSE-beat (lúc đóng run): điền
closedtimestamp +verdict(PASS/FAIL + 1 dòng +wf_…) +harvest(path file synthesis ✓).
closed=⏳ = đang chạy (OPEN chưa CLOSE).
Orphan = dòng ledger closed=⏳ nhưng run thực-tế đã xong/bỏ (session bị kill, agent die-0-byte, quên CLOSE-beat). Giải-quyết-CỨNG (không để treo):
- Điều-tra đĩa THẬT:
run.mdstatus + có filesub-*? + có<stage>-synthesis.md? + git-log workflowwf_…. - Đóng tay nếu run thật-sự xong: điền CLOSE-beat (timestamp + verdict + harvest path).
- Đánh-dấu aborted nếu run bỏ-dở: verdict =
⚠️ ABORTED — <lý-do>, ghi rõ phần nào hoàn-thành (recover qua git/disk/prod truth, KHÔNG tin agent return-message).
C7 — 🔴 CAVEAT trung-thực (no-overclaim)
- Engine no-fs → scaffold KHÔNG tự-động.
hmw.js(JS-sandbox no-filesystem) KHÔNG tạo được folder/file. Run-trace dựa 100% vào em-main: scaffoldrun.md@P1 (C2) + tự ghi<stage>-synthesis.mdmỗi run (C4). Không có cơ-chế nào ép tạo file. NOT fully-autonomous — đây là hard-gate-trên-INPUT (em main tự dựng khung + tự bơm tham-số đầu/cuối mỗi run), KHÔNG phải engine tự-động. - Cấu trúc phẳng giảm fragile từ 2 → 1, KHÔNG triệt-tiêu. Bỏ subfolder xoá được điểm-hay-quên "dựng sẵn
sub-md/+harvest/" (engine giờ ghi 1 cấp, no subfolder-to-forget). NHƯNG còn dư-lượng: em-main VẪN phải nhớ ghi<stage>-synthesis.mdmỗi run (close-gate L3 bắt nếu thiếu). Điểm-yếu giảm 1-trong-2, chứ không biến mất → C2 vẫn bắt-buộc. - 3-layer = LƯỚI, KHÔNG khoá-cứng-cùng-lúc-fire. L1/L2/L3 bắt lỗi sau khi việc đã xảy ra (post-hoc) hoặc nhắc dựa-trên-input em-main-bơm — giảm xác-suất sót, KHÔNG chặn tại-đúng-thời-điểm-fire. Phòng-thủ-nhiều-lớp, KHÔNG bảo-đảm tuyệt-đối.
- G-015 no-overclaim — TRACKED ≠ read-only-ENFORCED. Run-folder git-tracked KHÔNG biến sub thành read-only: sub vẫn giữ Bash (write-channel mở — ghi-ngoài-repo git-diff mù / curl Qdrant). Containment THẬT (model dưới) = em-main single-writer + git-diff(in-repo) + chunk-count(RAG), defense-in-depth — KHÔNG sandbox cứng, KHÔNG claim "ENFORCED".
- 🔴 ĐIỂM MÙ CỦA CHÍNH VAI ĐIỂM DANH — vai điểm danh KHÔNG tự soi được mình (khoản sàn GĐ-2(v), adopt S180/W2). Vật chứng của một vai sinh ra SAU khi vai đó chạy xong; nên bất kỳ vai nào đi điểm danh vật chứng — kể cả
scripts/artifact-integrity.ps1, kể cảring2-audit— đều không nằm trong phạm vi tự soi của chính nó. Một lượt soi đơn độc luôn để hở đúng phần cuối cùng nó vừa đẻ ra. Phủ chỗ hở đó cần hai chân, thiếu chân nào cũng hở: (a) vai thứ hai CÙNG PHIÊN —closeout-sentinel.ps1chạy cặp{harvest-curator, tooling-auditor}vô-điều-kiện, vàring2-auditPIN đích danh run-folder tươi (cấm glob-latest), chính chữ "pin đích danh" là thứ cho phép vai-sau soi vật-chứng-của-vai-trước; (b) lượt soi ở ĐẦU PHIÊN SAU — bookend@open(session-start.md) bắt phần lọt qua đêm. 🔸 Khai thẳng chân (b) đang YẾU, đo được, đừng đọc thành đã-đủ: nhịp thì có, chỉ thị thì không. Đo 2026-08-07:grep -cE 'run-folder|runs/' .claude/agents/lead-stale-auditor.md= 0 (control-dương cùng tệp:grep -c FLAG= 4 ⇒ lệnh chạy đúng, 0 là 0 THẬT);lead-gap-auditor.md= 1 hit, mà hit đó là dòng mô tả lớpgap-incident-unrecorded(:39), không phải lệnh đọc run-folder phiên trước. ⇒ cặp bookend có chạy đúng nhịp nhưng spec của cả hai vai không hề bảo chúng soi RUỘT vật chứng lượt chạy phiên trước. Cái đang phủ (b) trên thực tế chỉ làcloseout-sentinelM5 (delta thư mục vai) +nhip-no-proberun-chua-gom— cả hai đều không đọc ruột tệp. Nợ này có tên, giao gói-B persona của W3; tới khi nó đóng, đừng ghi (v) là đã phủ trọn.
C8 — MIGRATION (run cũ giữ subfolder · close-gate chấp-nhận CẢ 2 dạng)
🔴 KHÔNG viết lại lịch-sử. 5 run-folder S71 đã chốt giữ NGUYÊN cấu trúc cũ sub-md/ + harvest/ (đã commit, KHÔNG đụng):
2026-06-18-h10-invest/ (run.md + sub-md/ + harvest/invest-synthesis.md) ← cũ, GIỮ
2026-06-18-h10-implement/ (run.md + sub-md/ + harvest/implement-synthesis.md) ← cũ, GIỮ
2026-06-18-h10-review/ (run.md + sub-md/ + harvest/review-synthesis.md) ← cũ, GIỮ
2026-06-18-h910-finalize/ (run.md + sub-md/ + harvest/finalize-synthesis.md) ← cũ, GIỮ
2026-06-18-h910-curate/ (run.md + sub-md/ + harvest/curate-synthesis.md) ← cũ, GIỮ
2026-06-18-harness-audit-invest/ (run.md + audit-synthesis.md) ← 🆕 FLAT
- Run MỚI từ refine 06-18 → dùng FLAT (
sub-<role>-<i>.md+<stage>-synthesis.mdcùng cấp). Run CŨ → để yên (đừng gom-lên-cấp/đừng xoá subfolder — re-writing history vô-ích + làm bẩn git-log). - 🟢 Close-gate (L3) ACCEPT BOTH suốt giai-đoạn chuyển: verify gom ở
harvest/<stage>-synthesis.md(dạng cũ) HOẶC<stage>-synthesis.mdphẳng (dạng mới). Không fail run cũ chỉ vì thiếu file-phẳng. - 2 nấc track (C3) áp cho CẢ 2 dạng:
check-ignoreexit!=0 +ls-filesnon-empty.
Containment model (PHẢI khớp ../hmw.js — đồng-bộ 2 chỗ: đây · ../hmw.js; 🧊 chỗ thứ-3 _ledger.md retired H18-B S100, header nó giữ bản frozen)
Run-folder
runs/<run-id>/được git TRACKED → mọi write HIỆN trong git-diff = audit trực-tiếp. Containment: tracked-change NGOÀIruns/<run-id>/VÀ NGOÀI code-disjoint đã giao = vi-phạm (thay model Harness-2 B6 "mọi tracked-change = vi-phạm"). G-015 no-overclaim: TRACKED ≠ read-only-enforced — sub vẫn giữ Bash (write-channel mở), containment THẬT = em-main single-writer + git-diff(in-repo) + chunk-count(RAG).
Anti-bypass detector — SE TAILORED-OUT (quyết-định có chủ-đích, anh chốt)
Refine 06-18 (b) đề-xuất làm-chặt một bộ-dò chống-lách-engine (soi nhật-ký/mã xem có run nào né engine chuẩn không) theo 3 chức-năng. SE quyết-định KHÔNG hiện-thực bộ-dò này — đã CÂN-NHẮC và thấy N/A cho threat-model của SE. Giữ trung-thực, KHÔNG overclaim "đã có anti-bypass detector".
Lý-do tailored-out:
- SE chạy workflow qua Anthropic Workflow tool (
hmw.jsinvoke), KHÔNG có bề-mặt-lách kiểu CLI-launcher. AI_INFRA threat-model giả-định một node-CLI launcher (đường-vòng chạy lén engine) cần bộ-dò canh. SE không có launcher như vậy → không có "đường-vòng" để dò. - Containment SE đã đủ bằng cơ-chế khác (G-015 defense-in-depth):
git diffcommit-gate (mọi write tracked HIỆN trong diff) + run-folder git-tracked (audit trực-tiếp) + folder-scan orphan L1/L2 (🧊 ledger-scan retired H18-B S100) — backstop THẬT (không phải prompt). Bộ-dò pattern-match thêm = trùng-lặp, không bịt lỗ mới.
3 chức-năng refine — CÂN-NHẮC rồi N/A cho SE:
| Chức-năng refine (b) | Áp SE? | Vì sao |
|---|---|---|
| (1) Whitelist launcher hợp-lệ | N/A | SE không có launcher-wrapper quanh engine → không có gì để whitelist. |
| (2) Khớp đa-dạng biến-thể path tới engine | N/A | SE invoke engine qua Workflow tool (1 đường duy-nhất), không có path-variant để khớp. |
| (3) Neo KHOÁ-khởi-chạy-thật (đừng match tên-engine lẫn trong script) + acceptance theo QUAN-HỆ | N/A | Không có log-scan detector → không có chỗ neo launch-key. Acceptance-by-relation (hợp-lệ ≠ vi-phạm, hợp-lệ tăng dần OK) là nguyên-tắc tốt nhưng chỉ áp được khi CÓ detector. |
🔴 No-overclaim: SE KHÔNG claim đã adopt anti-bypass detector. SE claim: đã đọc + cân-nhắc 3 chức-năng, chọn tailored-out vì threat-model SE không có CLI-launcher-bypass-surface; containment dựa git-diff + run-folder-tracked + ledger-orphan-scan (G-015). Nếu sau này SE thêm launcher-wrapper → re-visit quyết-định này.