# sub-implementer-frontend-2 — T5: `hmw.js` +VALID_ROLES `ctx-audit` +writeGuard read-only

> RUN: `2026-07-26-S153-ctx-adopt` · wave `hmw-2` · vai `implementer-frontend` · ĐỢT-2 adopt thư `0df10df4`.
> Vết uỷ-quyền: **OWNER-DELEGATED** (CẤM ghi "owner chốt").
> File này ghi **TRONG LÚC LÀM** (anti-#53) — có END-line ở cuối. Nếu thiếu END-line ⇒ lane chết giữa đường, đọc phần đã ghi làm ground-truth.
> 🔸 **Vết tự-sửa (honesty):** bản đầu của §4/§5 được ghi TRƯỚC khi Edit (dự-đoán số dòng để chống #53). Sau khi đo thật, §4/§5 đã bị **thay bằng số ĐO ĐƯỢC** — 2 chỗ dự-đoán lệch: dòng template-literal thật là **:235** (dự-đoán :234) và comment writeGuard thật **tách 2 dòng** (:228+:229, dự-đoán gộp 1 dòng). Không để số dự-đoán đứng như số đo.

## 0. Cờ NAMING (khai NGAY, không chôn)

Prompt harness (writeGuard `hmw.js:235`) bơm `subMdPath = .../sub-implementer-frontend-1.md` (index GLOBAL theo `taskList` — S134), NHƯNG:

- `sub-implementer-frontend-1.md` **ĐÃ TỒN-TẠI** từ ĐỢT-1 (T2 template, 2020 B, mtime 2026-07-26 14:23) — bằng chứng `ls` run-folder.
- TASK text của lead ghi rõ: "RUN-TRACE: ghi `sub-implementer-frontend-2.md`".
- ⇒ Ghi vào `-1` = **đè mất evidence đợt-1** (vi-phạm B6 isolation "KHÔNG ghi sub-MD agent khác"). Chọn `-2` theo TASK. `subMdPath` return = `-2` (file THẬT tôi ghi); lệch với writeGuard-injected là **CÓ Ý**, khai ở đây + trong findings.
- Nguyên-nhân gốc: `hmw.js:225` đánh index theo `i` trong **taskList của invocation hiện tại**, KHÔNG biết đợt trước đã dùng `-1`. Đợt-2 = invocation MỚI ⇒ `i` reset ⇒ collision. Cùng lớp S133/S134 nhưng **kẽ CÒN LẠI**: S134 chỉ vá ca "2 role KHÁC nhau cùng invocation"; đây là **CÙNG role, 2 invocation khác nhau** ⇒ vẫn đụng. (Đề-xuất cho lead, KHÔNG tự làm: cho `run-id` + số đợt vào tên, hoặc lead truyền `startIndex`.)

## 1. Pre-state (đo TRƯỚC khi sửa)

```
$ grep -n "ctx-audit" .claude/workflows/hmw.js      → 0 hit
$ grep -c "" .claude/workflows/hmw.js               → 287 dòng
$ ls -la .claude/agents/ctx-audit.md                → 14347 B, Jul 26 14:13  (T3 đã land ⇒ tên vai chốt = 'ctx-audit')
```

`VALID_ROLES` = `hmw.js:22-41` (trước sửa), đếm phần tử = **20**:
investigator-codebase · investigator-api · implementer-backend · implementer-frontend · test-specialist · reviewer · cicd-monitor · frontend-designer · database-agent · office-document · tooling-auditor · harvest-curator · lead-stale-auditor · lead-gap-auditor · harness-eval · harness-refine · harness-audit · ring1-audit · ring2-audit · ring4-audit.

Vùng writeGuard đọc `hmw.js:226-242` (trước sửa). Cấu-trúc = **2 nơi** liệt vai read-only theo TÊN, phải sửa CẢ 2 (chính comment `:226-227` tự khai luật "thêm vai = sửa CẢ 2 chỗ"):

1. **JS comment `:226-227`** — dòng doc "SE read-only sub (KHÔNG Write tool): …" + "Write sub: …". Đây là chỗ DUY NHẤT đặt được **comment JS** (mục 2 nằm trong template-literal ⇒ không nhét `//` vào được, sẽ thành text đi vào prompt).
2. **Template-literal `:233`** (nay `:235`) — bullet `• NẾU mày CHỈ có Bash (read-only sub: … — KHÔNG Write tool)` = **prose đi VÀO PROMPT sub** ⇒ đây là điểm có RĂNG runtime.

Xác nhận `ctx-audit` THUỘC nhóm read-only: `.claude/agents/ctx-audit.md:7` → `tools: [Read, Grep, Glob, Bash, mcp__rag-unified__*]` — **KHÔNG Write/Edit**. (Persona tự khai đây là "mô-tả ý-định", carry `tools-whitelist-no-teeth`; backstop THẬT = git-diff commit-gate.)

## 2. Ràng buộc CẤM (đã tuân thủ, có đo)

- ❌ KHÔNG đụng `WIDTH_CAP` (nay `hmw.js:152`, = 20). Roster 21 > cap 20 là **câu hỏi owner đã NÊU** ở `spec-ctx-adopt-26-07-2026.md:36` ("roster 21 > hmw_width.cap 20 → NÊU owner (câu hỏi riêng, KHÔNG tự đổi)"). Số canonical ở `.claude/agent-memory/memory-budget.json → hmw_width.cap` (B1) ⇒ sửa 1 nơi = tạo drift. KHÔNG chạm.
- ❌ KHÔNG đụng `TIER2_EXPECTED_FULL_ID` (nay `:64`, = `'claude-opus-5'`).
- ❌ KHÔNG sửa gì khác trong hmw.js · KHÔNG chạm `agent-memory/*` · KHÔNG chạm MD canonical · KHÔNG chạm sub-MD người khác · KHÔNG RAG-write.

## 3. Sửa đã thực hiện (đúng 2 vùng, 3 Edit)

### Vùng A — `VALID_ROLES` :41 (phần tử cuối mảng)

```js
  'ctx-audit', // +S153 ctx soft-memory 0df10df4 — vai KIỂM lớp mềm _mind, INFORM-only, @2 bookend (OWNER-DELEGATED pipeline 26-07)
```

Comment 1 dòng **đúng nguyên-văn** lead giao. Đặt SAU dòng `'ring2-audit', 'ring4-audit',` (và sau comment của chúng) = append cuối, giữ trật-tự lịch-sử "vai mới append cuối". Dấu `,` cuối giữ trailing-comma style hiện hành.

### Vùng B — writeGuard, 2 điểm (gộp 1 hunk vì cách nhau < 6 dòng)

- `:228-229` (JS comment) — thêm `(+S153 ctx-audit — KIỂM lớp mềm _mind, tools: KHÔNG Write/Edit).` vào cuối danh-sách read-only; dòng "Write sub: …" tách xuống dòng riêng (giữ độ dài dòng đọc được, KHÔNG đổi nội dung).
- `:235` (template-literal đi vào prompt) — thêm `, ctx-audit` SAU `harness-audit`, giữ đúng syntax hiện hành (dấu `,` + đuôi `— KHÔNG Write tool`).

**Vì sao PHẢI cả 2:** chỉ sửa `:235` ⇒ doc-comment `:228` nói sai (drift NỘI-BỘ cùng file, đúng lớp bẫy mà chính comment đó cảnh báo); chỉ sửa comment ⇒ **prompt runtime KHÔNG đổi** ⇒ ctx-audit được hướng-dẫn như write-sub ⇒ nó Bash-write MD ⇒ mojibake G-009. Điểm `:235` mới là điểm có răng; điểm `:228` giữ doc khỏi lệch.

## 4. Post-state — SỐ ĐO THẬT (verbatim)

```
$ grep -n "ctx-audit" .claude/workflows/hmw.js
41:  'ctx-audit', // +S153 ctx soft-memory 0df10df4 — vai KIỂM lớp mềm _mind, INFORM-only, @2 bookend (OWNER-DELEGATED pipeline 26-07)
228:  // reviewer, cicd-monitor (+ monitor tooling-auditor/harvest-curator) (+S153 ctx-audit — KIỂM lớp mềm _mind, tools: KHÔNG Write/Edit).
235:        `  • NẾU mày CHỈ có Bash (read-only sub: … harness-refine, harness-audit, ctx-audit — KHÔNG Write tool): …`
$ grep -c "ctx-audit" .claude/workflows/hmw.js  → 3        ✅ ≥2 (VALID_ROLES + writeGuard ×2)
```

Đếm `VALID_ROLES` **bằng lệnh KHÁC** grep-đơn (trích block rồi đếm string quoted — né bẫy "grep -c đếm DÒNG" vì `'ring2-audit', 'ring4-audit',` là 2 phần tử TRÊN CÙNG 1 DÒNG):

```
$ awk 'NR>=22 && NR<=43' .claude/workflows/hmw.js | grep -o "'[a-z0-9-]*'" | wc -l
21        ✅ = 21   (thứ tự 1..21, ctx-audit ở vị-trí 21 — danh sách đầy đủ đã in, xem §1 + ctx-audit)
```

Diff-scope:

```
$ git diff --stat -- .claude/workflows/hmw.js
 .claude/workflows/hmw.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

$ git diff -U3 | grep "^@@"
@@ -38,6 +38,7 @@ const VALID_ROLES = [                                  ← vùng A
@@ -224,13 +225,14 @@ const results = await parallel(...)              ← vùng B (2 điểm gộp 1 hunk)
⇒ ĐÚNG 2 hunk, KHÔNG có hunk thứ 3.
```

Cân sổ +4/−2: vùng A = +1/−0 · comment `:228` 1 dòng → 2 dòng = +2/−1 · literal `:235` = +1/−1. Tổng +4/−2, net +2 dòng ⇒ 287 → **289** dòng (khớp `grep -c ""`).

Vùng CẤM còn nguyên (đo, không phải khẳng định):

```
$ git diff -- .claude/workflows/hmw.js | grep -c 'WIDTH_CAP'              → 0
$ git diff -- .claude/workflows/hmw.js | grep -c 'TIER2_EXPECTED_FULL_ID' → 0
$ grep -n "^const WIDTH_CAP" hmw.js              → 152:const WIDTH_CAP = 20                     (giá trị NGUYÊN)
$ grep -n "^const TIER2_EXPECTED_FULL_ID" hmw.js →  64:const TIER2_EXPECTED_FULL_ID = 'claude-opus-5'  (NGUYÊN)
```

## 5. Syntax-check — làm ĐÚNG cách (KHÔNG lấy `node --check` file thô làm acceptance)

Memory-pack cảnh báo: `hmw.js` = body được runtime **wrap async fn**, có top-level `await`/`return` ⇒ `node --check` file thô SẼ fail. Đo thật đúng như vậy, và **đã chứng là pre-existing bằng đối-chứng HEAD**:

```
$ node --check <copy .mjs cua ban DA SUA>   → SyntaxError: Illegal return statement (:289 `return results.filter(Boolean)`)
$ node --check <copy .mjs cua ban HEAD>     → SyntaxError: Illegal return statement (CÙNG lỗi, CÙNG chỗ)
⇒ fail này là BASELINE, KHÔNG phải regression của tôi.
```

Tín-hiệu DƯƠNG (3 phép, đều PASS):

```
1) Isolated parse VALID_ROLES block  (awk 22-42 → .mjs)   → PARSE-OK   (mảng 21 phần tử, nháy/phẩy cân)
2) Isolated parse writeGuard assign  (awk 229-245 → .mjs) → PARSE-OK   (template-literal cân, backtick/${} không vỡ)
3) Wrapped-parse TOÀN FILE (mô phỏng runtime: bọc `async function __wrap(){…}` + de-export `meta`):
     ban DA SUA → PARSE-OK toan file
     ban HEAD   → PARSE-OK toan file
   ⇒ 2 bản CÙNG trạng-thái hợp-lệ ⇒ edit KHÔNG đổi tính hợp-lệ cú-pháp.
```

*(2 lượt wrap đầu của tôi fail vì LỖI CỦA WRAPPER, không phải của hmw.js: `export const meta` không đặt được trong function, và param `A`/`SCHEMA` của wrapper trùng `const` trong file. Ghi lại để người sau khỏi đọc nhầm thành "hmw.js lỗi".)*

`npm run build` ×2 app = **N/A, khai thẳng**: task này KHÔNG chạm `fe-admin/src` hay `fe-user/src` (file là governance-script **single-copy**, không có bản mirror 2 app) ⇒ sàn thường-lệ "mirror SHA ×2 + build ×2" **không áp-dụng được**; sàn thay-thế đã dùng = grep-count + đếm-bằng-lệnh-khác + diff-scope 2-hunk + 3 phép parse có đối-chứng HEAD.

## 6. Containment (git status)

Tôi chạm ĐÚNG 2 path: `.claude/workflows/hmw.js` (3 Edit) + `.claude/workflows/runs/2026-07-26-S153-ctx-adopt/sub-implementer-frontend-2.md` (Write, file này). Các entry khác trong `git status` (`memory-budget.json`, `commands/pause.md`, `commands/tiep.md`, `.session-counter.json`, `broadcasts/*`, `adap-reports/*`, `scripts/session_ctx.py`, `docs/governance/ctx-soft-memory-se-draft.md`, `.claude/agents/ctx-audit.md`, `.claude/templates/session-mind-template.md`, sub-MD backend) = của **đợt-1 / lane khác / lead**, KHÔNG phải tôi.

🔸 **Cờ cho lead (ngoài scope tôi, KHÔNG tự xử):** `?? scripts/__pycache__/` đang untracked — artifact chạy Python của lane T1, đừng để lọt vào commit (kiểm `.gitignore`).

## 7. Đã KHÔNG làm (khai để lead không đọc thành đã-phủ)

- KHÔNG đổi `WIDTH_CAP` 20 → 21. **Hệ-quả THẬT phải biết:** roster nay 21 > cap 20 ⇒ sweep TOÀN-ROSTER sẽ bị `:153-161` **LOUD-skip lane thứ 21** (chạy 20 lane đầu, bỏ lane cuối, log 🔴). Lane bị bỏ = lane **cuối theo thứ-tự taskList**, KHÔNG cố-định là ctx-audit. Cần owner trả lời câu hỏi spec `:36`; nếu owner đồng ý nâng thì phải đổi **2 nơi cùng lúc** (`hmw.js:152` mirror + `memory-budget.json → hmw_width.cap` canonical) — B1.
- KHÔNG wire ctx-audit vào `session-start.md` Phase 3.5(iii) / `session-end.md` §L.b(l) (= T6 lead-solo, governance single-writer H6.1).
- KHÔNG cập-nhật `docs/STATUS.md §Sub-agents` (= T8 lead-solo).
- KHÔNG chạm `memory-budget.json`, KHÔNG ghi `agent-memory/implementer-frontend/MEMORY.md` (lead harvest @P3 từ `memoryDelta`).
- KHÔNG dogfood/spawn thử ctx-audit (= T9 phiên sau, cần restart CLI để registry nhận agent MỚI — lesson: agent-MỚI cần restart, khác hot-reload sửa hmw.js).

END sub-implementer-frontend-2 — T5 HOÀN TẤT · 3 hit grep (:41/:228/:235) · VALID_ROLES=21 · 2 hunk (+4/−2) · WIDTH_CAP=20 & TIER2 NGUYÊN · parse PASS đối-chứng HEAD.
