# sub-task-3 — LANE W1b — `scripts/spawn-model-audit.ps1` (PA-2b)

> **VERDICT: DONE + 2 TIỀN-ĐỀ CỦA LỆNH BỊ ĐO NGƯỢC.** Script land, 6/6 acceptance PASS, fault-inject 11 ca có RĂNG (không chỉ happy-path).
> 🔴 **Hai giả-định trong lệnh giao lane này SAI — đo được, không phải suy-diễn.** Cả hai đều theo hướng **dè-dặt quá mức** (under-claim), nên không tạo "acceptance giả" — nhưng nếu bê nguyên vào adap-report thì **báo sai nấc lên hub**, và W2 sẽ tự trói tay vô cớ.

- **File TẠO (duy nhất):** `scripts/spawn-model-audit.ps1` — 25.606 byte · 0 byte non-ASCII · no BOM (`3c 23 0a`) · PS 5.1 parse **0 error** · exit **0**.
- **Containment:** `git status --porcelain` ⇒ chỉ `?? scripts/spawn-model-audit.ps1` là của W1b. `git diff -- .claude/workflows/hmw.js docs/STATUS.md .claude/agents/` = **rỗng**. Cây tạm đã xoá.

---

## 0. 🔴 HAI TIỀN-ĐỀ BỊ ĐO NGƯỢC (đọc trước khi dùng lane này)

### (A) "resolved model rất có thể KHÔNG đo được từ .ps1" — **SAI. ĐO ĐƯỢC, đầy đủ.**

Lệnh lane dặn: *"NEU KHONG DO DUOC: KHAI THAT … script audit dùng phần ĐO ĐƯỢC (static)"*. Em đi **đo thật** thay vì nhận giả-định. Kết quả: **resolved model được ghi thẳng ra đĩa**, offline, .ps1 đọc được.

`owner-decisions-15-07-2026.md:60` đã trỏ đúng đường (`…/subagents/workflows/wf_*/agent-*.jsonl`) — đường đó **CÓ THẬT** và **có model**:

| wf-run (phiên S119 `3d9bec56`) | lane | resolved model | records |
|---|---|---|---|
| `wf_1f6bd5e2-478` (fable-clone invest) | 5 | `claude-opus-4-8` | 45/80/54/60/51 |
| `wf_78a84f9b-03e` (fable-clone reviewer) | 4 | `claude-opus-4-8` | 56/58/66/53 |
| `wf_cb964f83-331` (fable-real reviewer) | 2 | **`claude-fable-5`** | 39/42 |

Vị trí: `message.model` của record `"type":"assistant"`.
⇒ Script **KHÔNG** phải lùi về static-only. Nó làm **PA-2b THẬT** như owner-decision đặt hàng: `{n dispatch · n explicit · n mismatch}`.
⇒ Bài học: `meta.json` **KHÔNG** có model (`{"agentType":"reviewer","spawnDepth":1}`) — ai chỉ soi meta sẽ kết luận nhầm "không đo được". Model nằm trong `.jsonl`, không nằm trong `.meta.json`.

### (B) "precedence CHƯA TỪNG ĐƯỢC TEST … chỉ test được ở phiên lead=Fable" — **SAI. ĐÃ TEST RỒI, hôm nay, ngoài ý muốn.**

Lệnh bắt khai nguyên-văn: *"…CHUA TUNG DUOC TEST … Phep thu phan biet duoc CHI chay duoc trong phien lead=Fable; hom nay lead=Opus => KHONG phan biet duoc => DEFER"*.

**Chỗ hụt của lập-luận:** nó chỉ xét **chiều `tier:'opus'`**. Điều-kiện phân-biệt thật chỉ là **`họ(spawn-param) ≠ họ(lead)`** — nên **chiều `tier:'fable'` dưới lead=Opus phân biệt ngang hệt**. Và nó **đã chạy**: `wf_cb964f83-331` (`/fable-real reviewer`, cổng-cuối chính phiên này).

| Yếu tố | Giá trị ĐO ĐƯỢC | Nguồn |
|---|---|---|
| lead model phiên `3d9bec56` | `claude-opus-4-8` — **290/290 record, 0 Fable** | `3d9bec56….jsonl` |
| agentType lane | `reviewer` (agent registry thật) | `agent-*.meta.json` |
| frontmatter lane | `model: inherit` | `.claude/agents/reviewer.md:5` |
| spawn-param | `fable` (`hmw.js:44` `return tier`) | `/fable-real` escape-hatch |
| **RESOLVED** | **`claude-fable-5`** — 2/2 lane | `agent-a5167691d772fad12.jsonl` · `agent-abe4f7938106101ef.jsonl` |

**Suy ra:** nếu frontmatter `inherit` **thắng** ⇒ resolved phải là lead = `claude-opus-4-8`. **Nó không phải.**
⇒ **spawn-param CÓ hiệu-lực trên agent frontmatter-`inherit`** ⇒ 🔴 **`fix GAP#6` KHÔNG phải NO-OP.** Nỗi lo lớn nhất trong lệnh **đã được gỡ bằng số đo**, không cần defer.

**Giới-hạn trung-thực (giữ nguyên, không nống):**
1. Đây **không** chứng minh `inherit` **THUA** một cuộc tranh precedence. `inherit` rất có thể nghĩa là *"nghe theo caller"* — khi đó **không hề có tranh chấp**. Hai cách đọc cho **cùng một kết-luận vận-hành** (param có hiệu-lực); dữ-liệu này **không tách được** chúng, và script **không giả vờ tách**.
2. Cái **THẬT SỰ chưa test** = precedence với **frontmatter PIN CỨNG** (dạng hub: 17/17 `model: claude-opus-4-8`). SE có **0 agent pin cứng** (12/12 `inherit`, lệnh anh S66/H8) ⇒ ca đó **không có bằng-chứng**, và **không thể** có ở SE nếu không cố ý tạo.
3. `wf_1f6bd5e2-478` + `wf_78a84f9b-03e` (9 lane `claude-opus-4-8`) **không** phân-biệt được: lead=Opus nên cả 2 giả-thuyết đều tiên-đoán Opus. **Chỉ** `wf_cb964f83-331` mang sức phân-biệt. Đúng như lệnh nói *"hôm nay không phân biệt được"* — **cho chiều opus**. Chiều fable thì được.

📌 **Đề-xuất cho lead:** câu khai ở `v2:271` cần tách đôi khi vào adap-report — **(A) inherit ⇒ ĐÃ ĐO, param thắng** (kèm run-id + số đo) · **(B) hard-pin ⇒ CHƯA TEST, SE không có ca**. Bê nguyên "CHƯA TỪNG ĐƯỢC TEST" lên hub = **under-report** đúng lớp lỗi `fix #9(b)` vừa bắt (*"dán PASS thành n-a"*, đây là bản đối xứng: dán ĐÃ-ĐO thành CHƯA-TEST). Quyền chốt chữ = lead/anh; em không sửa spec.

---

## 1. Cấu-trúc script (5 section + summary)

| § | Việc | Nguồn | Đo được? |
|---|---|---|---|
| **A** | PA-2a: hằng `TIER2_EXPECTED_FULL_ID` trong `hmw.js` — tồn-tại? == `claude-opus-4-8`? | `.claude/workflows/hmw.js` | ✅ static |
| **B** | PA-2b: resolved vs expected — `{n dispatch · n explicit · n mismatch}` | `…/wf_*/agent-*.jsonl` | ✅ **đo thật** |
| **C** | Canonical: row `\| Sub-agents \| **N** \|` + marker flip-chain + cross-check đĩa | `docs/STATUS.md:24` | ✅ static |
| **D** | H8 all-inherit: frontmatter `model: inherit` — **glob**, KHÔNG hardcode 12 | `.claude/agents/*.md` | ✅ static |
| **E** | In **mọi lần chạy** các trục KHÔNG-đo-được ⇒ báo-cáo không thể bị đọc quá nấc | — | khai báo |

### Quyết-định thiết-kế đáng soi

**(1) Neo CẤU-TRÚC, không grep chuỗi — bài học W0.4 #1 (tự-tham-chiếu).**
`hmw.js:36` **đã sẵn** chứa literal `claude-opus-4-8` trong comment (*"KHÔNG còn demote-pin…"*). Nên acceptance thô ở `v2:269` (*"`TIER2_EXPECTED_FULL_ID` ≥1 hit = claude-opus-4-8"*) nếu code thành **2 grep rời** thì:
> `grep TIER2_EXPECTED_FULL_ID` ≥1 ✓ **AND** `grep claude-opus-4-8` ≥1 ✓ ⇒ **XANH** — kể cả khi hằng-số đang mang `claude-opus-9-9`.

⇒ Script **bắt giá-trị bằng capture-group** (`TIER2_EXPECTED_FULL_ID\s*=\s*['"]([^'"]+)['"]`) rồi so **giá-trị**. Cái bẫy được **in ra stdout mỗi lần chạy** làm phản-chứng: `anti-vacuous note: naive grep 'claude-opus-4-8' in hmw.js = 1 hit(s) [comment text] -> NOT used as evidence`.

**(2) `$expected` KHÔNG có default — fail-loud.** Thiếu hằng ⇒ FLAG HIGH `expected constant missing (W2 chua land)` + §B in **`[SKIPPED] … This is NOT a pass`**. Audit mà tự bịa giá-trị nó phải kiểm = tự cấp PASS cho chính mình.

**(3) 2-key có chủ-đích.** Kỳ-vọng khai **2 nơi**: `hmw.js` (PA-2a) + hằng `$OWNER_RATIFIED_TIER2_FULL_ID` trong script. Sửa lén **một** bên ⇒ FLAG. **Giá phải trả nói thẳng:** anh re-pin thì phải sửa **cả hai** — *chính cái giá đó là phép kiểm*.

**(4) Path derive 100% từ `$RepoRoot`.** Slug = `$RepoRoot -replace '[:\\/_]','-'` ⇒ `D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP` (khớp thật). `$TranscriptRoot` từ `$env:USERPROFILE`, **không** hardcode `C:\Users\pqhuy` (khác `governance-detectors.ps1:323`). ⇒ cây tạm tự ra slug lạ ⇒ `[NO-SCOPE]`, **không bịa số**.

**(5) `mismatch` định-nghĩa hẹp — chống dương-giả.** Alias khoá **HỌ**, không khoá phiên-bản (H23 §2(2)) ⇒ mismatch = *cùng họ `claude-opus-`, khác version*. Lane `claude-fable-5` = **other-family**, KHÔNG phải drift (đó là escape-hatch cố ý). Nếu tính nó là mismatch thì mọi `/fable-real` sẽ báo động giả.

**(6) KHÔNG dùng `U @(code-point)`.** Quy-ước bắt buộc U() **khi cần match token tiếng Việt**. Mọi neo của lane này **thuần ASCII** (`Sub-agents` · `model: inherit` · `TIER2_EXPECTED_FULL_ID` · `CANONICAL single-owner flip-chain`) ⇒ **không cần** ⇒ nhét U() chết vào cho "giống mẫu" = Goodhart. Thân script vẫn **ASCII tuyệt đối** (rule 1, đo: 0/25.606 byte >127).

**(7) Glob, không hardcode 12** (fix #9(h) / R2-M3): roster 12→14 ở W2 ⇒ hardcode sẽ **tự già thành FAIL giả** ngay khi W2 land.

**(8) Mọi verdict TÍNH TỪ SỐ ĐO — bài học W0.4 #2.** Không có nhãn dán cạnh số. Chứng: ca F5 in `frontmatter: 11/12` **và** FLAG — nhãn không thể mâu-thuẫn số vì nhãn **sinh ra từ** số.

---

## 2. Chạy thật trên repo (stdout thật, rút gọn)

```
===== A - expected constant (PA-2a, hmw.js) =====
  anti-vacuous note: naive grep 'claude-opus-4-8' in hmw.js = 1 hit(s) [comment text] -> NOT used as evidence
[SPAWN-AUDIT] HIGH | .claude/workflows/hmw.js | expected constant missing (W2 chua land): TIER2_EXPECTED_FULL_ID not declared in hmw.js | resolve: land PA-2a: ...
  -> section B comparison will report SKIPPED (no expected value to compare against)

===== B - resolved model (PA-2b, spawn transcripts) =====
  project slug   : D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP (derived from RepoRoot)
  session scope  : 95c916ee-253d-4813-8379-f58802d65746 (last write 2026-07-15 12:15)
    wf_de36dea9-265/agent-a80fe3808ac6ce234.jsonl [workflow-subagent] -> claude-opus-4-8 (67 record(s)) : SKIPPED (no expected constant)
    ... x4 lane ...
  COUNTS: 4 dispatch | 4 explicit | 0 mismatch
  [SKIPPED] resolved-vs-expected NOT evaluated: section A found no expected constant.
            This is NOT a pass. The lanes above are reported raw, uncompared.

===== C ===== STATUS.md:24 canonical Sub-agents = 12 | [OK] marker | [OK] canonical 12 matches disk (12)
===== D ===== frontmatter: 12/12 agent .md carry 'model: inherit' | [OK] all-inherit holds (12/12)
TOTAL FLAGS: 1        >>> EXIT CODE = 0
```

> 4 lane §B = **chính wave W1 này** (`wf_de36dea9-265` — W1a/W1b/W1c/W1d). Tất cả `claude-opus-4-8`, `agentType=workflow-subagent` (role-less ⇒ inherit lead=Opus) — **khớp H8 all-inherit**, quan sát trực-tiếp.

---

## 3. FAULT-INJECT — 11 ca, cây tạm `$env:TEMP\w1b-faultinject`, `-RepoRoot <cây-tạm>`

Vật-liệu tối-thiểu: `hmw.js` (14.810B) + `STATUS.md` (124.526B) + 13 agent `.md`.

| Ca | Inject | Kỳ-vọng | **stdout thật** | |
|---|---|---|---|---|
| **F0** | không có hằng (comment `:36` vẫn mang version) | FLAG missing | `HIGH … expected constant missing (W2 chua land)` · `TOTAL FLAGS: 1` | ✅ |
| **F1** 🔴 | hằng = `'claude-opus-9-9'` | **FLAG mismatch** | `HIGH … hmw.js declares 'claude-opus-9-9' but S119 PA-2a ratified 'claude-opus-4-8'` · `TOTAL FLAGS: 1` | ✅ |
| **F2** 🔴 | sửa về `'claude-opus-4-8'` | **hết FLAG** | `[OK] hmw.js expected = 'claude-opus-4-8' = owner-ratified` · **`TOTAL FLAGS: 0`** | ✅ |
| **F3** | `'claude-opus-4-8[1m]'` | FLAG suffix | `MED … carries a '[1m]' context-window suffix` (+HIGH mismatch) · `TOTAL FLAGS: 2` | ✅ |
| **F4** | 2 định-nghĩa lệch nhau | FLAG conflict | `HIGH … declared with 2 different values [claude-opus-4-1 vs claude-opus-4-8]` | ✅ |
| **F5** | `reviewer.md` pin cứng model | FLAG H8 | `MED \| .claude/agents/reviewer.md:5 \| frontmatter pins 'model: claude-opus-4-8'` + **`frontmatter: 11/12`** | ✅ |
| **F6** | STATUS `Sub-agents`=14, đĩa 12 | FLAG stale | `MED … canonical-itself-stale: STATUS Sub-agents=**14** but disk has 12 agent .md` | ✅ |
| **F7** | gỡ hết | 0 FLAG | `TOTAL FLAGS: 0` | ✅ |
| **B1** | transcript giả: lane `claude-opus-9-9` | **FLAG drift** | `HIGH \| wf_fake/agent-a2.jsonl \| alias-drift: resolved 'claude-opus-9-9' … expected 'claude-opus-4-8'` · `COUNTS: 4 dispatch \| 4 explicit \| 1 mismatch` | ✅ |
| **B2** | gỡ lane drift | mismatch=0 | `COUNTS: 3 dispatch \| 3 explicit \| 0 mismatch` · `TOTAL FLAGS: 0` | ✅ |
| **B3** | lane sạch nhưng tool-payload mang `"model":"claude-opus-9-9"` ở **nesting khác** | **KHÔNG** dương-giả | `-> claude-opus-4-8 (1 record(s)) : match` · `0 mismatch` | ✅ |

### 🔴 F1 = bằng-chứng chống-Goodhart (không phải happy-path)
Ngay trong stdout ca F1: `naive grep 'claude-opus-4-8' in hmw.js = 1 hit(s)`. Nghĩa là ở F1 file có **đồng thời** `TIER2_EXPECTED_FULL_ID` (≥1 hit) **và** `claude-opus-4-8` (≥1 hit, comment `:36`) ⇒ **gate grep-thô sẽ XANH** trên file khai `claude-opus-9-9`. Neo cấu-trúc **FLAG**. Đây là chỗ răng cắn thật.

### B3 = chứng neo `"message":{"model":` đáng đồng tiền (đo, không phán)
```
NAIVE    hits = 2 -> [claude-opus-9-9, claude-opus-4-8]     <- sẽ đẻ MISMATCH GIẢ (HIGH) trên lane sạch
ANCHORED hits = 1 -> [claude-opus-4-8]                       <- đúng
```

### ⚪ Chỗ em ĐỊNH chứng mà KHÔNG chứng được — khai thẳng
Giả-thuyết ban đầu: agent dán snippet transcript vào text ⇒ nhiễm regex. **Đo ra là SAI:** decoy `\"model\":\"claude-opus-9-9\"` trong text ⇒ **naive = anchored = 1 hit `[claude-opus-4-8]`** — JSON escaping tự chặn (sau `model` là `\` chứ không phải `"`). ⇒ Giá-trị của neo **KHÔNG** nằm ở chống-escaping (như em tưởng) mà **chỉ** ở chống **nesting khác** (ca B3). Ghi lại đúng nấc thay vì nống công.

---

## 4. Acceptance (tính từ số đo)

| # | Tiêu-chí | Số đo | Verdict |
|---|---|---|---|
| 1 | `TIER2_EXPECTED_FULL_ID` — W2 chưa land ⇒ **FAIL-LOUD**, không crash, không im-lặng-xanh | 0 def ⇒ `HIGH … missing (W2 chua land)`; §B `[SKIPPED] … NOT a pass`; exit 0 | **PASS** |
| 2 | 🔴 fault-inject expected giả ⇒ **PHẢI FLAG**; đổi về đúng ⇒ hết FLAG | F1 `TOTAL FLAGS: 1` (mismatch) → F2 `TOTAL FLAGS: 0` | **PASS** |
| 3 | `param -RepoRoot` bắt buộc | `:74` `[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path` | **PASS** |
| 4 | non-ASCII = 0 · PS 5.1 parse sạch | 0/25.606 byte >127 · parse errors **0** · PSVersion 5.1.26100.8737 · no BOM · 0 `&&`/`\|\|`/ternary/`??` | **PASS** |
| 5 | exit 0 | `>>> EXIT CODE = 0` (mọi ca, kể cả khi có FLAG) | **PASS** |
| 6 | Header khai trục CHƯA-ĐO-ĐƯỢC, không bàn quá nấc | §E in mỗi lần chạy (6 mục) + header khai (i)…(iv) + khối PRECEDENCE | **PASS** |

**6/6 PASS.** Trong đó (2) và (4) là số **đo**, không phải tường-thuật.

---

## 5. Bàn giao W2

1. **PA-2a land:** thêm cạnh `resolveModel` (`hmw.js:~43`):
   `const TIER2_EXPECTED_FULL_ID = 'claude-opus-4-8'` — **không** `[1m]` (gotcha #37; script FLAG nếu có).
   Land xong: §A `[OK]` · §B chuyển từ `SKIPPED` sang so thật. Ca F2 đã diễn-tập đúng đường này trên cây tạm.
2. **Nếu anh re-pin version:** sửa **cả hai** — `hmw.js` **và** `$OWNER_RATIFIED_TIER2_FULL_ID` (`spawn-model-audit.ps1:~86`). Chỉ sửa một ⇒ FLAG (đúng thiết-kế 2-key).
3. **Roster 12→14:** §C/§D **tự theo** (glob + đọc STATUS). Không có số nào phải sửa tay trong script này.
4. **CI:** `scripts/*.ps1` có trigger (AS-6) ⇒ file này vào path filter. Nó **exit 0 luôn** ⇒ không thể gãy build.
5. 🔴 **Cho R4-request / adap-report:** dùng **§0(A)** (resolved ĐO ĐƯỢC — bác "không đo được") + **§0(B)** (precedence-vs-`inherit` **ĐÃ ĐO**, param thắng, `wf_cb964f83-331`) thay câu "CHƯA TỪNG TEST" ở `v2:271`. Giữ nguyên caveat: **hard-pin vẫn chưa test** + `inherit` có thể là *"nghe theo caller"* chứ không phải *"thua"*.

## 6. Giới-hạn script tự khai (§E, in mỗi lần chạy)

1. Spot-check theo quy-ước, **KHÔNG enforcement** — không chặn spawn (H23 §2(4)).
2. **Chỉ phiên hiện-tại** — run cũ có trước quy-ước ⇒ nhiễu, không phải bão lỗi (owner-decisions:64).
3. **KHÔNG** đọc thành *"đã áp đủ sàn"* — chỉ đo **tính tường-minh trong transcript**, không đo độ-phủ tài-liệu (owner-decisions:65).
4. **Hồi-cứu**: đọc model **đã** resolve; **không** tiên-đoán được spawn KẾ. Báo-cáo sạch **không** hứa lần sau không trôi. Đây chính là lý-do H23 §2(4) để nó informational.
5. **CHƯA TEST** — precedence vs frontmatter **pin cứng**: SE có 0 ca (12/12 inherit).
6. **CHƯA THỬ** — param `model:` có từ-chối full-id không (fix #8a). Tài-liệu nói enum alias; **không thử** ở đây.
