# ADAP-REQUEST (se → AI_INFRA) — R6: 🔴 user-memory sống NGOÀI repo ⇒ 0 git · 0 backup · 0 history — và bug #53 zero-byte xảy ra ĐÚNG ở đó

- **id:** 2026-07-15-se-r6-user-memory-outside-repo-no-backup
- **from:** se · **date:** 2026-07-15 (S122) · **classify:** **infra** (harness memory-location — AI_INFRA owns per charter v2)
- **status:** proposed · **raised-by:** 🔴 **anh chủ-dự-án** (owner-raised, S122) — lead đang vá triệu-chứng thì anh chỉ ra gốc
- **nấc:** evidenced (đo trên đĩa) + **1 câu HỎI HUB** (§3.0) mà SE **không tự trả lời được**

## 1. Phát hiện (evidence-first)

### 1.1 Bất-đối-xứng KHÔNG có lý-do kỹ-thuật

| | **user-memory** | **agent-memory** |
|---|---|---|
| Vị-trí | `C:\Users\<user>\.claude\projects\<slug>\memory\` | `<repo>/.claude/agent-memory/` |
| Nội-dung | **48 file** `feedback_*` + `MEMORY.md` = **151 671 B** | 82 file tracked = 1 163 069 B |
| **Git** | 🔴 **KHÔNG** — `git rev-parse` → `fatal: not a git repository` | ✅ tracked |
| **Backup ngoài** | 🔴 **KHÔNG** — repo ở `D:\Dropbox\…` (auto-sync), cái này ở `C:\Users\…` (**KHÔNG** trong Dropbox) | ✅ theo repo |
| **History / rollback** | 🔴 **KHÔNG** | ✅ |
| **Travel giữa máy/acc** | 🔴 **KHÔNG** | ✅ |

⇒ **148 KB bài-học đắt nhất của dự-án đang nằm ở nơi DUY NHẤT không có bản sao nào.**

### 1.2 🔴 Điều làm việc này thành RỦI-RO THẬT, không phải chuyện gọn-gàng

Fleet **đã biết** bug **#53 làm memory-Write ra 0-byte** — SE ghi hẳn thành luật vận-hành: *"closeout Write có thể 0-byte; **verify byte>0 sau mỗi memory Write**"*. Lý-do luật đó tồn tại: **S45 MẤT index thật**.

🔴 **Bug ghi-hỏng-file đang xảy ra ĐÚNG tại thư-mục KHÔNG CÓ HISTORY để phục-hồi.**
Cùng bug đó nếu rơi vào `.claude/agent-memory/` ⇒ `git checkout` là xong. Rơi vào user-memory ⇒ **mất vĩnh viễn**, và cách duy nhất phát hiện là **con người tình cờ nhận ra**.

⇒ Lớp phòng-thủ hiện tại (`verify byte>0`) là **kỷ-luật người**, đứng thay cho thứ mà **version-control cho không**.

### 1.3 Hệ-quả phụ: vị-trí ngoài-repo **ép** hardcode — sống 27 ngày qua cả một đợt double-check

Vì path nằm ngoài repo và **machine-specific**, script muốn đọc nó phải tự dựng đường:
```powershell
# Derive from this machine's project slug; ...        ← comment nói DERIVE
$userMemDir = 'C:\Users\pqhuy\.claude\projects\D--Dropbox-...\memory'   ← code HARDCODE
```
**Comment mô-tả Ý-ĐỊNH; code hardcode cả path tuyệt-đối LẪN username.**

**Vòng đời đo được:**
| | |
|---|---|
| Sinh ra | `e70c046` · **2026-06-18 20:44** · *"adopt Harness-11 engine tự-bảo-trì"* |
| Vá | `c39ba9d` · **2026-07-15 15:12** |
| **Sống** | **27 ngày** |

🔴 **Cơ-chế KHÔNG phải "bị viết lại nhiều lần" — mà là "sinh 1 lần rồi SỐNG SÓT qua các đợt rà".** `git log -S` bắt 8 commit, nhưng **5/8 có `ps1/js-touched=0`** (chỉ là doc/WAL **nhắc tới** path — kể cả adap-report SE vừa viết hôm nay). Chỉ **3** động vào `.ps1/.js` thật — và một trong số đó là **`ae957c4` = *"Harness-11 **double-check ×2** + finalize report"***: một đợt **double-check** đã sờ **đúng file đó** và **không bắt được**.

**2 hại cụ-thể (không phải style):**
1. `-RepoRoot <cây-tạm>` **vẫn đọc user-memory THẬT** ⇒ **fault-inject C1-wikilink KHÔNG cô-lập được** ⇒ **chính công-cụ dựng ra để CHỨNG-MINH-CÓ-RĂNG lại không có răng của nó**.
2. Hardcode username ⇒ máy/acc khác ⇒ **degrade IM LẶNG** xuống else-branch — mà **degrade im lặng đọc y hệt "sạch"**.

🟢 **Đối-chứng cho thấy cách ĐÚNG đã được biết:** `scripts/spawn-model-audit.ps1` (viết **hôm nay**, W1) làm chuẩn ngay từ đầu — `$TranscriptRoot = (Join-Path $env:USERPROFILE '.claude\projects')`, folder-name derive từ `$RepoRoot`, và **tự ghi chú**: *"Default derives from `$env:USERPROFILE` (**NOT a hardcoded absolute path**). The per-project folder name is derived from `$RepoRoot`, so a fault-inject tree…"*.
⇒ **Không phải fleet không biết. Là KHÔNG CÓ LUẬT nào cấm, nên file cũ không ai quét lại.**

## 2. Phạm vi ĐÃ verify vs CHƯA verify (không overclaim)

| Điều | Trạng-thái |
|---|---|
| 48 file / 151 671 B ở user-memory | ✅ đo |
| user-memory **không** phải git repo | ✅ đo (`fatal: not a git repository`) |
| user-memory **không** trong Dropbox | ✅ suy từ path (`C:\Users\` ⟂ `D:\Dropbox\`) — hiển-nhiên |
| `settings.json` (project **+** user) **0 key** cấu-hình memory-path | ✅ đo |
| hardcode sống **27 ngày**, sinh @`e70c046`, sống qua **1 đợt double-check** | ✅ đo bằng `git log -S` + `--stat` |
| `spawn-model-audit.ps1` làm đúng | ✅ đọc mã |
| 🔴 **Harness có đường NÀO KHÁC để đổi vị-trí memory không** (env-var? flag? config ngoài `settings.json`?) | ❓ **SE KHÔNG BIẾT** — SE **chỉ kiểm `settings.json`**. Đây là **câu hỏi §3.0** |
| Repo khác trong fleet có cùng tình-trạng không | ❓ **KHÔNG BIẾT** — SE chỉ đo repo mình |
| Vì sao harness đặt memory ngoài repo | ❓ **KHÔNG BIẾT** — **có thể có lý-do đúng mà SE chưa thấy** (vd: memory chứa thứ **không nên** vào git — secret? cross-project? per-machine?) |

🔴 **SE KHÔNG kết-luận "harness sai".** SE kết-luận: **rủi-ro là thật và đo được**; **lý-do thì SE không biết**.

## 3. Đề xuất cho AI_INFRA

### 3.0 🔴 CÂU HỎI TRƯỚC — SE hỏi thật, không phải hỏi tu-từ

**Vị-trí user-memory có đổi được không, và nếu KHÔNG thì vì sao?**
SE chỉ kiểm được `settings.json` (0 key). Nếu harness **có** đường khác (env-var / flag / config khác) ⇒ xin chỉ, SE tự áp và đóng request.
Nếu **cố ý** đặt ngoài repo ⇒ xin nêu lý-do; SE sẽ ghi vào doc để **lần sau không ai lại đề-xuất chuyện này nữa** (chính SE cũng suýt vá triệu-chứng mà không hỏi gốc).

### 3.1 Nếu ĐỔI ĐƯỢC — ưu-tiên theo thứ-tự

1. **Memory sống trong repo** (vd `<repo>/.claude/memory/`) — đối-xứng với `agent-memory` đang chạy tốt. Được ngay **git + Dropbox + history + rollback + travel**, và **xoá luôn nhu-cầu hardcode** (§1.3 biến mất tận gốc thay vì phải vá từng script).
2. **Nếu không thể**: cho **config path** ⇒ mỗi repo tự trỏ vào thư-mục **được git theo dõi**.
3. **Nếu cả hai không** — tối-thiểu **document rõ**: *"memory KHÔNG được version-control; project tự lo backup"* — để nó là **quyết-định có ý-thức**, không phải **mặc-định vô-hình**. Kèm khuyến-nghị đường backup được hỗ-trợ.

### 3.2 Độc-lập với 3.1 — 2 việc nên làm dù chọn gì

4. **Luật `no-absolute-path`**: script đọc thứ ngoài repo **PHẢI** derive từ `$RepoRoot` / `$env:USERPROFILE`, **CẤM** path tuyệt-đối + **CẤM** hardcode username. `spawn-model-audit.ps1` = mẫu sẵn (kèm lý-do). Bằng-chứng cần luật: bug sống **27 ngày** qua **một đợt double-check** — *biết cách đúng* **không đủ**, phải có thứ **soi**.
5. **Khảo-sát fleet**: repo khác có hardcode tương-tự không? Grep `C:\Users\` / `/home/` / `/Users/` trong `scripts/` là ra ngay.

## 4. SE đã tự làm (không chờ)

- **Vá `governance-detectors.ps1`** (`c39ba9d`): `$projectSlug = $RepoRoot -replace '[:\\/_]', '-'` + `$env:USERPROFILE`. **Verify 2 chiều:** slug derive == literal cũ (**KHỚP 100%**, `Test-Path`=True, TOTAL vẫn 45 ⇒ **0 đổi hành-vi**) · `-RepoRoot` cây-tạm → *"user-memory path not reachable (…fake-repo\memory)"* ⇒ **CÔ LẬP**, rò path thật = **0**.
- **Quét lại toàn repo:** `grep -rn 'C:\\Users\\pqhuy' scripts/ .claude/ docs/` = **0 hit code** còn lại.
- 🔴 **SE KHÔNG tự dời memory** — vị-trí do **harness quyết**, dời tay ⇒ harness **thôi auto-inject** ⇒ **mất memory khỏi context** = hỏng nặng hơn bug đang có. **Chờ hub.**

## 5. 🔸 Lead tự bắt — 2 lỗi trong chính việc này

1. **Vá triệu-chứng, không hỏi gốc.** Lead fix hardcode xong coi như xong. **Anh chủ-dự-án phải chỉ ra** rằng câu hỏi đúng là *"vì sao memory lại nằm ngoài repo để mà phải hardcode?"*. ⇒ khớp `feedback_root_cause_over_symptom` — **bài học đã có trong memory của lead, và lead vẫn không tự bật ra**.
2. **Vá đúng cái được chỉ, không quét xem còn cái nào khác.** WAL:30 nêu đích-danh `governance-detectors.ps1`; lead vá đúng nó rồi **dừng**. Chỉ khi anh hỏi mới quét ra **script thứ hai cũng đọc user-memory** (`spawn-model-audit.ps1` — may là nó **sạch sẵn**). **Lần này thoát vì may, không vì quy-trình.**

🔸 Ghi 2 lỗi này vào request vì chúng là **dữ-liệu về quy-trình fleet**, không phải lời xin lỗi: **luật ở §3.2(4) tồn tại chính vì hai lỗi này**, không phải vì lý-thuyết.
