docs(agent): bổ sung role fix-dispatcher và siết lại bộ tài liệu agent
- Thêm agent/roles/0_fix_dispatcher.md: phân tier/lane cho từng defect trước khi các agent khác chạy, kèm agent/commands/fix.md và hợp đồng đầu ra agent/output/dispatch_plan.md. - Cập nhật system/guardrail, response_policy, security và các checklist ui/ux/pr_readiness cho khớp luồng mới. - Mở rộng knowledge: i18n_rules, screen_map, theme_tokens, secrets_and_config; cập nhật workflow intake_to_fix và handoff_contract. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
thanhnv
co-authored by
Claude Opus 5
parent
9459dbe197
commit
3c3ec748f9
+429
-43
@@ -1,81 +1,467 @@
|
||||
# Guardrail — luật bất biến cho mọi agent trong `agent/`
|
||||
# Guardrail — Luật bất biến cho mọi agent trong `agent/`
|
||||
|
||||
Áp dụng cho cả 6 role. Role nào mâu thuẫn với file này thì **file này thắng**.
|
||||
> **PRECEDENCE:** File này áp dụng cho **tất cả 6 role** trong `agent/`.
|
||||
>
|
||||
> Nếu role-specific instruction mâu thuẫn với bất kỳ quy tắc nào dưới đây, **Guardrail này thắng**.
|
||||
|
||||
---
|
||||
|
||||
## G1. Không tự bịa requirement
|
||||
|
||||
- Chỉ làm việc trên những gì có trong bug report, source code, và `knowledge/`.
|
||||
- Thiếu thông tin → ghi vào mục **Assumption** hoặc **Open Question**, KHÔNG tự suy diễn
|
||||
rồi sửa theo suy diễn đó.
|
||||
- Không tự ý "tiện tay cải thiện UX" ngoài phạm vi lỗi được báo. Phát hiện vấn đề khác →
|
||||
ghi vào mục **Out of scope (đề xuất issue riêng)**.
|
||||
* Chỉ làm việc dựa trên:
|
||||
|
||||
* bug report;
|
||||
* source code thực tế;
|
||||
* các tài liệu trong `knowledge/`;
|
||||
* governance và security policy liên quan.
|
||||
* Nếu thiếu thông tin:
|
||||
|
||||
* ghi vào `Assumption`; hoặc
|
||||
* ghi vào `Open Question`.
|
||||
* **Không được tự suy diễn requirement rồi sửa theo suy diễn đó.**
|
||||
* Không tự ý "tiện tay cải thiện UX", refactor hoặc đổi behavior ngoài phạm vi bug.
|
||||
* Nếu phát hiện vấn đề khác:
|
||||
|
||||
* ghi vào `Out of scope (đề xuất issue riêng)`;
|
||||
* không sửa trong cùng patch.
|
||||
|
||||
---
|
||||
|
||||
## G2. Không đoán vị trí code
|
||||
|
||||
- Mọi khẳng định về code phải kèm `path/file.py:line`. Chưa đọc file thì chưa được kết luận.
|
||||
- Người dùng mô tả bằng tiếng Việt/Nhật → tra `knowledge/screen_map.md` và
|
||||
`docs/screens/controls.json` để tìm đúng widget, không đoán theo tên gọi.
|
||||
* Không được kết luận về code khi chưa đọc code thực tế.
|
||||
* Mọi khẳng định cụ thể về implementation phải kèm:
|
||||
|
||||
```text
|
||||
path/file.py:line
|
||||
```
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
Root cause nằm tại presentation/shell/nav_rail.py:242
|
||||
```
|
||||
|
||||
* Khi người dùng mô tả bằng tiếng Việt hoặc tiếng Nhật:
|
||||
|
||||
1. tra `knowledge/screen_map.md`;
|
||||
2. tra `docs/screens/manifest.json`;
|
||||
3. tra `docs/screens/controls.json`;
|
||||
4. xác nhận `screen → view → widget → file → line`.
|
||||
* **Không đoán file chỉ dựa vào tên widget hoặc tên màn hình.**
|
||||
* Nếu chưa đủ bằng chứng để xác định vị trí:
|
||||
|
||||
* `confidence: low`;
|
||||
* ghi rõ thông tin còn thiếu.
|
||||
|
||||
---
|
||||
|
||||
## G3. Sửa đúng tầng
|
||||
|
||||
Cowork Local là Clean Architecture 4 tầng, phụ thuộc chỉ hướng vào trong:
|
||||
Cowork Local sử dụng Clean Architecture 4 tầng:
|
||||
|
||||
```text
|
||||
presentation/ → application/ → domain/ ← infrastructure/
|
||||
```
|
||||
|
||||
- Bug UI/UX được sửa ở `presentation/`, `ui/`, `theme/`, `i18n/`. Đó là mặc định.
|
||||
- Nếu buộc phải đụng `application/` hoặc `domain/`, phải nêu rõ **lý do tại sao không
|
||||
sửa được ở tầng trên** trong `fix_plan.md`, và coi đó là thay đổi cần reviewer chú ý.
|
||||
- `domain/` và `application/` là **100% Pure Python**. Tuyệt đối không thêm import
|
||||
`PySide6`/`PyQt` vào hai tầng này — Gate C sẽ chặn.
|
||||
- Widget chỉ gọi xuống service của `application/`. Không query SQLite/JSON trực tiếp,
|
||||
không gọi LLM trực tiếp trong GUI thread.
|
||||
### Quy tắc
|
||||
|
||||
* Bug UI/UX mặc định được xử lý tại:
|
||||
|
||||
* `presentation/`
|
||||
* `ui/`
|
||||
* `theme/`
|
||||
* `i18n/`
|
||||
|
||||
* Nếu buộc phải sửa `application/` hoặc `domain/`:
|
||||
|
||||
* phải giải thích trong `fix_plan.md` **tại sao không thể giải quyết ở tầng trên**;
|
||||
* phải đánh dấu đây là thay đổi cần reviewer chú ý.
|
||||
|
||||
### Pure Python boundary
|
||||
|
||||
`domain/` và `application/` phải là **100% Pure Python**.
|
||||
|
||||
**Tuyệt đối không thêm:**
|
||||
|
||||
```python
|
||||
from PySide6 ...
|
||||
from PyQt...
|
||||
```
|
||||
|
||||
vào hai tầng này.
|
||||
|
||||
Gate C sẽ chặn vi phạm này.
|
||||
|
||||
### GUI boundary
|
||||
|
||||
Widget:
|
||||
|
||||
* chỉ gọi service/use case của `application/`;
|
||||
* không query SQLite trực tiếp;
|
||||
* không đọc/ghi JSON repository trực tiếp;
|
||||
* không gọi LLM trực tiếp trong GUI thread.
|
||||
|
||||
---
|
||||
|
||||
## G4. Không đặt tên màu ngoài `theme/`
|
||||
|
||||
- Không hex literal (`#1f6fb2`), không `QColor("red")`, không `setStyleSheet("color: blue")`
|
||||
trong bất kỳ file nào ngoài `theme/`.
|
||||
- Sửa màu = sửa/đọc token trong `theme/palettes.py`, hoặc gán `objectName` rồi style trong
|
||||
`theme/qss.py`. Chi tiết: `knowledge/theme_tokens.md`.
|
||||
- Đây là lỗi bị từ chối review thường xuyên nhất khi sửa bug UI.
|
||||
Ngoài `theme/`, tuyệt đối không định nghĩa màu trực tiếp.
|
||||
|
||||
### Không được dùng
|
||||
|
||||
```python
|
||||
"#1f6fb2"
|
||||
QColor("red")
|
||||
setStyleSheet("color: blue")
|
||||
```
|
||||
|
||||
Cũng không được tạo màu bằng:
|
||||
|
||||
* hex literal;
|
||||
* color name;
|
||||
* RGB/RGBA literal;
|
||||
* stylesheet màu viết trực tiếp.
|
||||
|
||||
### Cách đúng
|
||||
|
||||
Màu phải đi qua theme system:
|
||||
|
||||
```text
|
||||
Palette
|
||||
↓
|
||||
semantic token
|
||||
↓
|
||||
QSS template / current_palette()
|
||||
↓
|
||||
widget
|
||||
```
|
||||
|
||||
Có hai cách hợp lệ:
|
||||
|
||||
1. Widget có `objectName` và được style trong `theme/qss.py`.
|
||||
2. Custom painting dùng `current_palette()`.
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/theme_tokens.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## G5. Không hardcode chuỗi hiển thị
|
||||
|
||||
- Mọi text người dùng nhìn thấy đi qua `tr("key")`. Chi tiết: `knowledge/i18n_rules.md`.
|
||||
- Sửa một nhãn = sửa cả 3 ngôn ngữ `en` / `ja` / `vi`, không sửa mỗi tiếng Việt.
|
||||
Mọi text người dùng nhìn thấy phải đi qua:
|
||||
|
||||
```python
|
||||
tr("key")
|
||||
```
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/i18n_rules.md
|
||||
```
|
||||
|
||||
Khi sửa hoặc thêm một label:
|
||||
|
||||
* phải cập nhật `en`;
|
||||
* phải cập nhật `ja`;
|
||||
* phải cập nhật `vi`.
|
||||
|
||||
**Không chỉ sửa tiếng Việt.**
|
||||
|
||||
Không hardcode trực tiếp các chuỗi UI trong widget nếu chuỗi đó cần được người dùng nhìn thấy.
|
||||
|
||||
---
|
||||
|
||||
## G6. Giữ Single Responsibility
|
||||
|
||||
- Mọi module production `<= 400 LOC` (Gate S). Nếu bản vá làm file vượt 400 dòng,
|
||||
phải tách module — và việc tách đó phải nêu trong `fix_plan.md` trước khi làm.
|
||||
- Không "sửa bug" bằng cách nhét thêm 150 dòng vào một file đã 380 dòng.
|
||||
Mọi production module phải:
|
||||
|
||||
```text
|
||||
<= 400 LOC
|
||||
```
|
||||
|
||||
Đây là giới hạn của Gate S.
|
||||
|
||||
### Nếu patch làm file vượt 400 dòng
|
||||
|
||||
Không được tiếp tục nhồi code vào file.
|
||||
|
||||
Phải:
|
||||
|
||||
1. xác định phần cần tách;
|
||||
2. ghi kế hoạch tách trong `fix_plan.md`;
|
||||
3. thực hiện việc tách như một phần rõ ràng của patch;
|
||||
4. đảm bảo dependency direction không bị phá vỡ.
|
||||
|
||||
### Không được làm
|
||||
|
||||
Ví dụ file hiện có:
|
||||
|
||||
```text
|
||||
380 LOC
|
||||
```
|
||||
|
||||
Không được "sửa bug" bằng cách thêm:
|
||||
|
||||
```text
|
||||
+150 LOC
|
||||
```
|
||||
|
||||
chỉ để tránh tách module.
|
||||
|
||||
---
|
||||
|
||||
## G7. Không làm suy yếu kiểm thử
|
||||
|
||||
- Không xoá test, không `@pytest.mark.skip`, không nới assert để pass gate.
|
||||
- Test đang đỏ vì lý do khác → báo trong report, không sửa lén.
|
||||
- Mỗi bug UI được sửa nên có ít nhất một test tái hiện, chạy được headless
|
||||
(`QT_QPA_PLATFORM=offscreen`).
|
||||
Tuyệt đối không:
|
||||
|
||||
* xoá test;
|
||||
* disable test;
|
||||
* dùng `@pytest.mark.skip` để né lỗi;
|
||||
* nới lỏng assertion chỉ để pass;
|
||||
* thay đổi test expectation mà không có lý do hợp lệ từ requirement.
|
||||
|
||||
Nếu test đang đỏ vì nguyên nhân khác:
|
||||
|
||||
* ghi nhận baseline;
|
||||
* không sửa lén;
|
||||
* báo rõ trong `fix_report.md`.
|
||||
|
||||
### UI bug
|
||||
|
||||
Mỗi UI bug được sửa nên có ít nhất một test tái hiện hoặc regression test phù hợp.
|
||||
|
||||
Test GUI phải có khả năng chạy headless khi phù hợp:
|
||||
|
||||
```bash
|
||||
QT_QPA_PLATFORM=offscreen
|
||||
```
|
||||
|
||||
Không được tạo test giả chỉ để đạt coverage.
|
||||
|
||||
---
|
||||
|
||||
## G8. Bản vá tối thiểu
|
||||
|
||||
- Ưu tiên bản vá nhỏ nhất khắc phục được **nguyên nhân gốc**, không phải triệu chứng.
|
||||
- Không refactor kèm trong PR fix bug. Một PR = một thay đổi logic (Definition of Done).
|
||||
- Không đổi format/indent toàn file — diff phải đọc được.
|
||||
Mục tiêu là:
|
||||
|
||||
> **Bản vá nhỏ nhất có thể sửa đúng nguyên nhân gốc.**
|
||||
|
||||
Không chỉ sửa triệu chứng.
|
||||
|
||||
### Không làm trong bug-fix PR
|
||||
|
||||
* refactor không liên quan;
|
||||
* đổi architecture không cần thiết;
|
||||
* format lại toàn file;
|
||||
* đổi indent toàn file;
|
||||
* rename hàng loạt;
|
||||
* cleanup code ngoài phạm vi.
|
||||
|
||||
Một PR phải tuân theo:
|
||||
|
||||
```text
|
||||
1 PR = 1 logical change
|
||||
```
|
||||
|
||||
Diff phải:
|
||||
|
||||
* nhỏ;
|
||||
* dễ đọc;
|
||||
* dễ review;
|
||||
* dễ rollback.
|
||||
|
||||
---
|
||||
|
||||
## G9. Không tự merge, không tự đóng issue
|
||||
|
||||
- Agent chỉ đề xuất. Quyết định merge thuộc Cowork Team (`docs/governance/ownership.md`).
|
||||
- Thay đổi chạm tới permission, credential, MCP write/exec, sandbox, network, TLS,
|
||||
isolation, model routing, xoá dữ liệu → **bắt buộc** đánh dấu `security-review: required`
|
||||
trong output, kể cả khi chỉ sửa UI.
|
||||
Agent chỉ:
|
||||
|
||||
* phân tích;
|
||||
* đề xuất;
|
||||
* tạo `fix_plan`;
|
||||
* implement khi đúng role;
|
||||
* kiểm chứng;
|
||||
* tạo report;
|
||||
* handoff.
|
||||
|
||||
Agent **không tự quyết định merge**.
|
||||
|
||||
Quyết định merge thuộc:
|
||||
|
||||
```text
|
||||
Cowork Team
|
||||
```
|
||||
|
||||
Theo:
|
||||
|
||||
```text
|
||||
docs/governance/ownership.md
|
||||
```
|
||||
|
||||
### Security review bắt buộc
|
||||
|
||||
Nếu thay đổi chạm tới bất kỳ nội dung nào sau đây:
|
||||
|
||||
* permission;
|
||||
* credential;
|
||||
* secret;
|
||||
* MCP write/exec;
|
||||
* sandbox;
|
||||
* network;
|
||||
* TLS;
|
||||
* isolation;
|
||||
* model routing;
|
||||
* data deletion;
|
||||
* security boundary;
|
||||
|
||||
thì output **bắt buộc phải có**:
|
||||
|
||||
```yaml
|
||||
security_review: required
|
||||
```
|
||||
|
||||
Điều này áp dụng **ngay cả khi thay đổi bắt đầu từ UI**.
|
||||
|
||||
`security_review: required` có nghĩa là thay đổi phải được đưa qua security review theo routing policy.
|
||||
|
||||
Không được tự kết luận:
|
||||
|
||||
> "Chỉ sửa UI nên không cần security review."
|
||||
|
||||
---
|
||||
|
||||
## G10. Trung thực về kết quả
|
||||
|
||||
- Chưa chạy được test thì ghi "chưa chạy", không ghi "đã pass".
|
||||
- Sửa được 2/3 vấn đề trong report thì nói rõ phần còn lại và lý do.
|
||||
- Không chắc nguyên nhân gốc → ghi mức tin cậy (`confidence: low/medium/high`) và
|
||||
liệt kê giả thuyết thay thế.
|
||||
Agent phải báo cáo đúng những gì thực sự đã làm.
|
||||
|
||||
### Chưa chạy test
|
||||
|
||||
Không được viết:
|
||||
|
||||
```text
|
||||
Tests passed
|
||||
```
|
||||
|
||||
Phải viết:
|
||||
|
||||
```text
|
||||
Tests: not run
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```text
|
||||
Chưa chạy test do <lý do>.
|
||||
```
|
||||
|
||||
### Chỉ sửa được một phần
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
2/3 vấn đề đã được xử lý.
|
||||
Vấn đề còn lại: ...
|
||||
Lý do chưa xử lý: ...
|
||||
```
|
||||
|
||||
Không được báo cáo như thể toàn bộ bug đã được giải quyết.
|
||||
|
||||
### Không chắc root cause
|
||||
|
||||
Phải ghi:
|
||||
|
||||
```yaml
|
||||
confidence: low
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: medium
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: high
|
||||
```
|
||||
|
||||
và nếu có:
|
||||
|
||||
```text
|
||||
Alternative hypotheses:
|
||||
- ...
|
||||
- ...
|
||||
```
|
||||
|
||||
### Nguyên tắc
|
||||
|
||||
> **Evidence trước, kết luận sau.**
|
||||
|
||||
Không được biến:
|
||||
|
||||
```text
|
||||
chưa kiểm chứng
|
||||
```
|
||||
|
||||
thành:
|
||||
|
||||
```text
|
||||
đã xác nhận
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Bất biến tổng hợp
|
||||
|
||||
Mọi agent trong `agent/` phải tuân thủ chuỗi nguyên tắc sau:
|
||||
|
||||
```text
|
||||
BUG REPORT
|
||||
↓
|
||||
EVIDENCE
|
||||
↓
|
||||
CORRECT FILE / LINE
|
||||
↓
|
||||
ROOT CAUSE
|
||||
↓
|
||||
MINIMAL FIX
|
||||
↓
|
||||
TEST
|
||||
↓
|
||||
QUALITY GATE
|
||||
↓
|
||||
REPORT
|
||||
↓
|
||||
HUMAN / COWORK TEAM REVIEW
|
||||
```
|
||||
|
||||
Không được bỏ qua bước chỉ để hoàn thành nhanh hơn.
|
||||
|
||||
---
|
||||
|
||||
# Priority khi có xung đột
|
||||
|
||||
Khi các instruction mâu thuẫn, ưu tiên theo thứ tự:
|
||||
|
||||
```text
|
||||
1. Guardrail G1–G10
|
||||
2. Security policy / governance
|
||||
3. knowledge/
|
||||
4. Role-specific instruction
|
||||
5. Bug report / task-specific detail
|
||||
6. Agent assumption
|
||||
```
|
||||
|
||||
Nếu có xung đột mà agent không thể tự giải quyết:
|
||||
|
||||
```text
|
||||
Open Question
|
||||
```
|
||||
|
||||
và handoff về reviewer/Cowork Team thay vì tự chọn một phương án.
|
||||
|
||||
Reference in New Issue
Block a user