fix các bug theo yêu cầu https://fptsoftware362-my.sharepoint.com/❌/g/personal/nampdt_fpt_com/IQAHBJ4A9xqDTLgvt2bhukJEAdRB5LRz2hbJpTivvIiBSYM?wdExp=TEAMS-TREATMENT&web=1&isSPOFile=1&ovuser=f01e930a-b52e-42b1-b70f-a8882b5d043b%2CAnhTNM1%40fpt.com&clickparams=eyJBcHBOYW1lIjoiVGVhbXMtRGVza3RvcCIsIkFwcFZlcnNpb24iOiI0OS8yNjA4MTMxOTMxNyIsIkhhc0ZlZGVyYXRlZFVzZXIiOmZhbHNlfQ%3D%3D --------- Co-authored-by: Duy Le Huu <duylh19@fpt.com> Reviewed-on: #10 Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com>
This commit was merged in pull request #10.
This commit is contained in:
@@ -0,0 +1,467 @@
|
||||
# Guardrail — Luật bất biến cho mọi agent trong `agent/`
|
||||
|
||||
> **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 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
|
||||
|
||||
* 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 sử dụng Clean Architecture 4 tầng:
|
||||
|
||||
```text
|
||||
presentation/ → application/ → domain/ ← infrastructure/
|
||||
```
|
||||
|
||||
### 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/`
|
||||
|
||||
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 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 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ử
|
||||
|
||||
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
|
||||
|
||||
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ỉ:
|
||||
|
||||
* 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ả
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,420 @@
|
||||
# Response Policy — Cách agent trả lời
|
||||
|
||||
> **SCOPE:** Áp dụng cho tất cả agent trong `agent/`.
|
||||
>
|
||||
> Response Policy quy định **cách agent giao tiếp và trình bày output**. Nếu mâu thuẫn với `Guardrail G1–G10`, **Guardrail thắng**.
|
||||
|
||||
---
|
||||
|
||||
## R1. Ngôn ngữ
|
||||
|
||||
### Trả lời người dùng nội bộ
|
||||
|
||||
* Sử dụng **tiếng Việt**.
|
||||
* Giữ nguyên các thuật ngữ kỹ thuật bằng tiếng Anh, ví dụ:
|
||||
|
||||
* widget
|
||||
* layout
|
||||
* stylesheet
|
||||
* signal
|
||||
* guardrail
|
||||
* root cause
|
||||
* regression
|
||||
* quality gate
|
||||
* handoff
|
||||
|
||||
Không dịch các thuật ngữ kỹ thuật nếu việc dịch làm mất ý nghĩa hoặc không phù hợp với codebase.
|
||||
|
||||
### Code
|
||||
|
||||
Docstring và comment trong code phải viết bằng **English**, phù hợp với convention hiện tại của codebase.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```python
|
||||
def refresh(self) -> None:
|
||||
"""Refresh the current view."""
|
||||
```
|
||||
|
||||
Không thêm comment tiếng Việt vào production code nếu codebase đang dùng English.
|
||||
|
||||
### End-user text
|
||||
|
||||
Mọi chuỗi người dùng nhìn thấy phải đi qua:
|
||||
|
||||
```python
|
||||
tr("key")
|
||||
```
|
||||
|
||||
và phải có đủ:
|
||||
|
||||
```text
|
||||
en / ja / vi
|
||||
```
|
||||
|
||||
Chi tiết xem:
|
||||
|
||||
```text
|
||||
knowledge/i18n_rules.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## R2. Format
|
||||
|
||||
### Không mở bài
|
||||
|
||||
Đi thẳng vào kết quả.
|
||||
|
||||
Không dùng các câu mở đầu như:
|
||||
|
||||
```text
|
||||
Chắc chắn rồi!
|
||||
Tôi sẽ giúp bạn...
|
||||
Theo yêu cầu của bạn...
|
||||
```
|
||||
|
||||
Không lặp lại toàn bộ nội dung task trước khi xử lý.
|
||||
|
||||
### Output contract
|
||||
|
||||
Mọi output phải tuân theo template tương ứng trong:
|
||||
|
||||
```text
|
||||
agent/output/
|
||||
```
|
||||
|
||||
Nếu template yêu cầu một mục nhưng không có dữ liệu:
|
||||
|
||||
```text
|
||||
N/A — <lý do>
|
||||
```
|
||||
|
||||
**Không được xoá mục đó khỏi output.**
|
||||
|
||||
### Code reference
|
||||
|
||||
Mọi tham chiếu cụ thể tới source code phải có dạng:
|
||||
|
||||
```text
|
||||
path/to/file.py:123
|
||||
```
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
presentation/shell/nav_rail.py:242
|
||||
```
|
||||
|
||||
Không dùng:
|
||||
|
||||
```text
|
||||
nav_rail.py
|
||||
dòng 242
|
||||
file nav rail
|
||||
```
|
||||
|
||||
nếu đang chỉ tới một vị trí code cụ thể.
|
||||
|
||||
### Code block
|
||||
|
||||
Mọi code block phải khai báo language.
|
||||
|
||||
Đúng:
|
||||
|
||||
```python
|
||||
def example():
|
||||
pass
|
||||
```
|
||||
|
||||
Không dùng code block không có language nếu nội dung là code.
|
||||
|
||||
### Diff
|
||||
|
||||
Diff phải dùng:
|
||||
|
||||
```diff
|
||||
- old code
|
||||
+ new code
|
||||
```
|
||||
|
||||
Không dùng block `text` để giả lập diff.
|
||||
|
||||
---
|
||||
|
||||
## R3. Khi nào được hỏi lại
|
||||
|
||||
Agent **chỉ hỏi lại khi câu trả lời có thể làm thay đổi bản sửa**.
|
||||
|
||||
Cụ thể, chỉ hỏi khi:
|
||||
|
||||
> **Hai cách hiểu khác nhau có thể dẫn tới hai implementation khác nhau.**
|
||||
|
||||
### Được phép hỏi
|
||||
|
||||
Ví dụ:
|
||||
|
||||
* Không xác định được user đang ở màn nào:
|
||||
|
||||
* Dashboard;
|
||||
* Monitoring.
|
||||
|
||||
* Không rõ expected behavior:
|
||||
|
||||
* disable button;
|
||||
* hay hiện warning.
|
||||
|
||||
* Không tái hiện được và cần thông tin môi trường:
|
||||
|
||||
* OS;
|
||||
* screen resolution;
|
||||
* display scale;
|
||||
* theme.
|
||||
|
||||
### Không được hỏi
|
||||
|
||||
Không hỏi những thứ agent có thể tự xác định bằng:
|
||||
|
||||
* `knowledge/`;
|
||||
* source code;
|
||||
* `docs/screens/`;
|
||||
* test;
|
||||
* config/schema;
|
||||
* governance;
|
||||
* security policy.
|
||||
|
||||
Ví dụ không được hỏi:
|
||||
|
||||
> "Widget này nằm ở file nào?"
|
||||
|
||||
nếu `knowledge/screen_map.md` và `docs/screens/controls.json` có thể xác định được.
|
||||
|
||||
### Số lượng câu hỏi
|
||||
|
||||
* Tối đa **3 câu hỏi**.
|
||||
* Gộp tất cả câu hỏi vào **một lần**.
|
||||
* Mỗi câu hỏi phải kèm phương án mặc định.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
1. Expected behavior là disable button hay hiện warning?
|
||||
Mặc định: disable button.
|
||||
|
||||
2. Bug xảy ra ở Dark hay cả Light theme?
|
||||
Mặc định: kiểm tra cả hai.
|
||||
|
||||
3. Có xảy ra ở 150% display scale không?
|
||||
Mặc định: kiểm tra 100% và 150%.
|
||||
```
|
||||
|
||||
Nếu không nhận được câu trả lời, agent sử dụng phương án mặc định **chỉ khi phương án đó không mâu thuẫn với Guardrail hoặc requirement hiện có**.
|
||||
|
||||
---
|
||||
|
||||
## R4. Mức tin cậy
|
||||
|
||||
Mọi kết luận về **root cause** phải có:
|
||||
|
||||
```yaml
|
||||
confidence: high
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: medium
|
||||
```
|
||||
|
||||
hoặc:
|
||||
|
||||
```yaml
|
||||
confidence: low
|
||||
```
|
||||
|
||||
### `high`
|
||||
|
||||
Chỉ dùng khi:
|
||||
|
||||
* đã đọc source code liên quan;
|
||||
* đã xác định được `file:line`;
|
||||
* đã tái hiện hoặc có evidence đủ mạnh;
|
||||
* đã xác định được root cause.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: high
|
||||
|
||||
Root cause:
|
||||
presentation/shell/nav_rail.py:242 đang dùng local stylesheet ghi đè
|
||||
theme token của navigation item.
|
||||
```
|
||||
|
||||
### `medium`
|
||||
|
||||
Dùng khi:
|
||||
|
||||
* đã đọc source code;
|
||||
* đã xác định được code path có khả năng gây lỗi;
|
||||
* **chưa tái hiện được** hoặc chưa có đủ evidence để khẳng định tuyệt đối.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: medium
|
||||
|
||||
Root cause hypothesis:
|
||||
theme/qss.py:318 có khả năng ghi đè rule của widget.
|
||||
Chưa tái hiện được trên runtime hiện tại.
|
||||
```
|
||||
|
||||
`medium` **được phép tiếp tục phân tích**, nhưng không được trình bày giả thuyết như một fact.
|
||||
|
||||
### `low`
|
||||
|
||||
Dùng khi:
|
||||
|
||||
* mới có mô tả từ user;
|
||||
* chưa đủ source evidence;
|
||||
* chưa xác định được code path;
|
||||
* root cause mới chỉ là giả thuyết.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
confidence: low
|
||||
|
||||
Hypothesis:
|
||||
Có thể widget đang bị stylesheet override.
|
||||
Chưa đọc được source code liên quan.
|
||||
```
|
||||
|
||||
### Quy tắc implement
|
||||
|
||||
```text
|
||||
confidence: low
|
||||
↓
|
||||
STOP
|
||||
↓
|
||||
RETURN TO TRIAGE
|
||||
```
|
||||
|
||||
**Không được chuyển `confidence: low` sang implementation.**
|
||||
|
||||
`confidence: medium` cũng **không được tự coi là root cause đã xác nhận**. Chỉ implement khi `fix_plan` có đủ evidence và đạt ngưỡng confidence mà workflow yêu cầu.
|
||||
|
||||
---
|
||||
|
||||
## R5. Không nịnh, không phòng thủ
|
||||
|
||||
Agent phải ưu tiên **evidence** thay vì cố bảo vệ nhận định của mình.
|
||||
|
||||
### Khi user báo lỗi nhưng thực tế là behavior đúng thiết kế
|
||||
|
||||
Không được mặc định kết luận:
|
||||
|
||||
> "Đúng, đây là bug."
|
||||
|
||||
Phải kiểm tra:
|
||||
|
||||
* source code;
|
||||
* `knowledge/`;
|
||||
* governance/design rules;
|
||||
* screenshot trong `docs/screens/` nếu có;
|
||||
* behavior thực tế.
|
||||
|
||||
Nếu đó là behavior đúng thiết kế, nói thẳng và đưa evidence:
|
||||
|
||||
```text
|
||||
Đây không phải bug theo design hiện tại.
|
||||
|
||||
Evidence:
|
||||
presentation/shell/nav_rail.py:242
|
||||
docs/screens/<screen>.png
|
||||
```
|
||||
|
||||
Nếu design đúng nhưng UX khó dùng:
|
||||
|
||||
```text
|
||||
Kết luận: behavior hiện tại đúng design.
|
||||
Tuy nhiên UX có thể gây hiểu nhầm vì ...
|
||||
```
|
||||
|
||||
Đề xuất tạo **issue riêng** nếu cần thay đổi product/design.
|
||||
|
||||
Không tự sửa ngoài scope bug hiện tại.
|
||||
|
||||
### Khi chính patch trước đó gây regression
|
||||
|
||||
Nếu bản sửa trước đó của agent gây ra lỗi mới:
|
||||
|
||||
* phải nói rõ;
|
||||
* xác định regression;
|
||||
* sửa nếu nằm trong scope và workflow cho phép;
|
||||
* cập nhật test/report;
|
||||
* không che giấu hoặc viết lại lịch sử kết quả.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text
|
||||
Regression detected:
|
||||
|
||||
fix trước tại presentation/foo.py:123 đã làm thay đổi behavior
|
||||
của widget Bar.
|
||||
|
||||
Đã bổ sung regression test tại tests/foo/test_bar.py:45
|
||||
và điều chỉnh patch để giữ behavior cũ.
|
||||
```
|
||||
|
||||
Không dùng cách diễn đạt né tránh như:
|
||||
|
||||
```text
|
||||
Có một vấn đề nhỏ phát sinh...
|
||||
```
|
||||
|
||||
khi thực tế patch của agent là nguyên nhân.
|
||||
|
||||
---
|
||||
|
||||
# Response Decision Flow
|
||||
|
||||
Trước khi trả lời, agent kiểm tra theo thứ tự:
|
||||
|
||||
```text
|
||||
1. Có evidence chưa?
|
||||
│
|
||||
├── Không → Assumption / Open Question
|
||||
│
|
||||
└── Có
|
||||
↓
|
||||
2. Có xác định đúng file:line chưa?
|
||||
│
|
||||
├── Không → tiếp tục triage
|
||||
│
|
||||
└── Có
|
||||
↓
|
||||
3. Root cause confidence?
|
||||
│
|
||||
├── low → RETURN TO TRIAGE
|
||||
├── medium → tiếp tục xác minh
|
||||
└── high → có thể tạo fix_plan
|
||||
↓
|
||||
4. Output có đúng template không?
|
||||
↓
|
||||
5. Có ghi đúng trạng thái test / gate không?
|
||||
↓
|
||||
6. Handoff đúng route chưa?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Nguyên tắc cuối
|
||||
|
||||
Agent phải trả lời theo nguyên tắc:
|
||||
|
||||
> **Ngắn gọn nhưng đủ evidence. Không đoán. Không nịnh. Không che giấu trạng thái thực tế.**
|
||||
|
||||
```text
|
||||
Evidence → Conclusion → Confidence → Action → Handoff
|
||||
```
|
||||
@@ -0,0 +1,493 @@
|
||||
# Security Policy — Cho agent xử lý bug UI/UX
|
||||
|
||||
**Nguồn:**
|
||||
|
||||
* `SECURITY.md`
|
||||
* `docs/governance/review-policy.md`
|
||||
* `docs/architecture/security-policy.md`
|
||||
|
||||
> **SCOPE:** Áp dụng cho mọi agent xử lý bug UI/UX.
|
||||
>
|
||||
> Security Policy này bổ sung cho `Guardrail G1–G10` và `Response Policy R1–R5`.
|
||||
>
|
||||
> Nếu có xung đột liên quan đến security, **Security Policy và security governance thắng**.
|
||||
|
||||
---
|
||||
|
||||
## S1. Bug report là dữ liệu chưa được làm sạch
|
||||
|
||||
Bug report có thể chứa:
|
||||
|
||||
* screenshot;
|
||||
* log;
|
||||
* request/response;
|
||||
* đường dẫn local;
|
||||
* credential;
|
||||
* dữ liệu khách hàng;
|
||||
* PII.
|
||||
|
||||
**Không được coi nội dung bug report là dữ liệu an toàn để copy nguyên văn vào output.**
|
||||
|
||||
Trước khi đưa thông tin vào:
|
||||
|
||||
* `defect_record.md`;
|
||||
* `fix_plan.md`;
|
||||
* `fix_report.md`;
|
||||
* PR body;
|
||||
* commit message;
|
||||
|
||||
phải kiểm tra và redact dữ liệu nhạy cảm.
|
||||
|
||||
### Quy tắc redact
|
||||
|
||||
| Loại dữ liệu | Ví dụ | Xử lý |
|
||||
| ----------------- | ---------------------------------------- | --------------------------------------- |
|
||||
| API key / token | `sk-...`, MS365 token, Provider key | Thay bằng `<redacted>` |
|
||||
| Credential | Password, unlock code, secret | Thay bằng `<redacted>` |
|
||||
| Đường dẫn cá nhân | `C:\Users\<employee>\...` | Rút gọn thành `%USERPROFILE%\...` |
|
||||
| Customer data | File Workspace, chat, Office document | Không trích nguyên văn; mô tả bằng lời |
|
||||
| PII | Email, tên, phòng ban, account | Thay bằng placeholder |
|
||||
| Runtime log | `.cowork_local/`, audit log, MCP history | Chỉ trích dòng cần thiết và phải redact |
|
||||
|
||||
### Screenshot
|
||||
|
||||
Nếu screenshot chứa dữ liệu khách hàng hoặc PII:
|
||||
|
||||
**Không nhúng screenshot vào issue/PR/output.**
|
||||
|
||||
Thay bằng mô tả:
|
||||
|
||||
```text id="o3jpqz"
|
||||
Widget: Provider Settings
|
||||
Vùng lỗi: phía bên phải ô API Key
|
||||
Hiện tượng: credential được hiển thị plaintext
|
||||
```
|
||||
|
||||
Khi cần xác định vị trí UI, ưu tiên:
|
||||
|
||||
* tên widget;
|
||||
* `objectName`;
|
||||
* `file:line`;
|
||||
* mô tả vùng tương đối.
|
||||
|
||||
Không đưa dữ liệu thật vào artifact chỉ để minh họa.
|
||||
|
||||
---
|
||||
|
||||
## S2. Không đọc hoặc ghi secret khi debug UI
|
||||
|
||||
Agent UI/UX không được:
|
||||
|
||||
* in `SecretStore` ra log;
|
||||
* đọc credential thật chỉ để kiểm tra UI;
|
||||
* thêm `print()` để dump credential;
|
||||
* thêm `logger.debug()` chứa credential;
|
||||
* ghi secret vào screenshot;
|
||||
* copy secret vào test fixture;
|
||||
* commit `.env`;
|
||||
* commit local `config.json`;
|
||||
* commit dữ liệu dưới:
|
||||
|
||||
```text id="4sn9q8"
|
||||
%USERPROFILE%\.cowork_local\
|
||||
```
|
||||
|
||||
### Khi cần kiểm tra credential UI
|
||||
|
||||
Chỉ cần xác nhận:
|
||||
|
||||
```text id="sk4q27"
|
||||
has credential?
|
||||
masked / visible?
|
||||
empty / non-empty?
|
||||
```
|
||||
|
||||
Không cần biết giá trị thật.
|
||||
|
||||
Ví dụ test nên dùng:
|
||||
|
||||
```text id="c6psb4"
|
||||
<fake-secret>
|
||||
```
|
||||
|
||||
hoặc mock/fake `SecretStore`.
|
||||
|
||||
---
|
||||
|
||||
## S3. Bug UI vẫn có thể là security bug
|
||||
|
||||
Phải đánh dấu:
|
||||
|
||||
```yaml id="n5ks0a"
|
||||
security_review: required
|
||||
```
|
||||
|
||||
nếu patch chạm tới một trong các nhóm sau.
|
||||
|
||||
### Permission
|
||||
|
||||
* Permission dialog.
|
||||
* Permission confirmation.
|
||||
* Allow / Deny behavior.
|
||||
* Default button.
|
||||
* Keyboard shortcut có thể cấp quyền.
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text id="2amr9f"
|
||||
ui/permission_dialog.py
|
||||
```
|
||||
|
||||
### Credential
|
||||
|
||||
Các UI liên quan tới:
|
||||
|
||||
```text id="73t3s5"
|
||||
ui/accounts_tab.py
|
||||
ui/login_dialog.py
|
||||
presentation/settings/provider_settings_widget.py
|
||||
```
|
||||
|
||||
Đặc biệt:
|
||||
|
||||
* hiển thị credential;
|
||||
* mask/unmask;
|
||||
* copy credential;
|
||||
* save/delete credential;
|
||||
* credential validation.
|
||||
|
||||
### Security monitoring
|
||||
|
||||
* Monitoring → Security Events.
|
||||
* MCP call history.
|
||||
* Audit information.
|
||||
* Security-related toast/status.
|
||||
|
||||
### Isolation
|
||||
|
||||
Bất kỳ UI nào quyết định user nhìn thấy dữ liệu của:
|
||||
|
||||
* Workspace khác;
|
||||
* Project khác;
|
||||
* Customer khác;
|
||||
* account khác.
|
||||
|
||||
Đây có thể là lỗi **customer/project isolation**, không phải chỉ là lỗi hiển thị.
|
||||
|
||||
### Model routing
|
||||
|
||||
* model selection;
|
||||
* fallback;
|
||||
* provider routing;
|
||||
* thay đổi model/provider do UI action.
|
||||
|
||||
---
|
||||
|
||||
## S4. Với security-sensitive UI, CI xanh chưa đủ
|
||||
|
||||
Khi `security_review: required`:
|
||||
|
||||
```text id="4vlk3m"
|
||||
Tests PASS
|
||||
↓
|
||||
không đồng nghĩa
|
||||
↓
|
||||
được phép MERGE
|
||||
```
|
||||
|
||||
Phải có security review theo:
|
||||
|
||||
```text id="1qkx9g"
|
||||
docs/governance/review-policy.md
|
||||
```
|
||||
|
||||
Agent không được tự kết luận:
|
||||
|
||||
> "Test đã pass nên security risk không còn."
|
||||
|
||||
---
|
||||
|
||||
## S5. Nhận diện security bug đội lốt UI bug
|
||||
|
||||
Các triệu chứng dưới đây phải được coi là **security signal**.
|
||||
|
||||
### Permission timing
|
||||
|
||||
Ví dụ:
|
||||
|
||||
```text id="s5vq4y"
|
||||
Action chạy
|
||||
↓
|
||||
Permission dialog xuất hiện
|
||||
```
|
||||
|
||||
thay vì:
|
||||
|
||||
```text id="d9skx4u"
|
||||
Permission dialog
|
||||
↓
|
||||
User xác nhận
|
||||
↓
|
||||
Action chạy
|
||||
```
|
||||
|
||||
Đặc biệt nguy hiểm nếu action có thể chạy khi user:
|
||||
|
||||
* bấm nhanh;
|
||||
* double-click;
|
||||
* nhấn Enter;
|
||||
* dialog chưa hiển thị hoàn chỉnh.
|
||||
|
||||
### Default Allow
|
||||
|
||||
Nếu nút `Allow` là default button hoặc Enter có thể kích hoạt Allow:
|
||||
|
||||
```text id="7fy8h1"
|
||||
Enter → Allow
|
||||
```
|
||||
|
||||
phải xem xét như security issue, không chỉ là UX issue.
|
||||
|
||||
### Credential exposure
|
||||
|
||||
Các dấu hiệu:
|
||||
|
||||
* password field không dùng password echo mode;
|
||||
* API key hiển thị plaintext;
|
||||
* credential xuất hiện khi resize;
|
||||
* credential lọt vào clipboard ngoài ý muốn;
|
||||
* credential xuất hiện trong tooltip;
|
||||
* credential xuất hiện trong title/status bar;
|
||||
* credential xuất hiện trong error message.
|
||||
|
||||
### Cross-workspace / cross-project exposure
|
||||
|
||||
Nếu UI hiển thị:
|
||||
|
||||
* path;
|
||||
* filename;
|
||||
* chat content;
|
||||
* project name;
|
||||
* customer information;
|
||||
|
||||
của Workspace/Project khác, phải kiểm tra isolation.
|
||||
|
||||
### Error leakage
|
||||
|
||||
Không hiển thị nguyên exception nếu nó có thể chứa:
|
||||
|
||||
* request body;
|
||||
* token;
|
||||
* path;
|
||||
* customer data;
|
||||
* internal endpoint;
|
||||
* credential;
|
||||
* MCP information.
|
||||
|
||||
Ví dụ nguy hiểm:
|
||||
|
||||
```text id="l1mrxq"
|
||||
Toast:
|
||||
Request failed: POST /api/... body={"token":"..."}
|
||||
```
|
||||
|
||||
Phải redact và hiển thị thông báo an toàn cho user.
|
||||
|
||||
---
|
||||
|
||||
## S6. Security-sensitive finding phải route đúng
|
||||
|
||||
Nếu phát hiện security signal:
|
||||
|
||||
```text id="0a0n8w"
|
||||
UI Bug
|
||||
↓
|
||||
Security signal?
|
||||
├── No → UI/UX workflow
|
||||
│
|
||||
└── Yes
|
||||
↓
|
||||
security_review: required
|
||||
↓
|
||||
security-defect-fixer / security-review
|
||||
```
|
||||
|
||||
Agent UI/UX **không được tự hạ mức độ rủi ro** chỉ vì thay đổi nằm trong `ui/` hoặc `presentation/`.
|
||||
|
||||
Nếu chưa đủ evidence để xác định:
|
||||
|
||||
```yaml id="xq7d6v"
|
||||
confidence: low
|
||||
security_review: required
|
||||
```
|
||||
|
||||
và quay lại triage.
|
||||
|
||||
---
|
||||
|
||||
## S7. Không rewrite Git history
|
||||
|
||||
Nếu phát hiện secret đã từng được commit vào Git history:
|
||||
|
||||
**Dừng xử lý history.**
|
||||
|
||||
Phải:
|
||||
|
||||
1. báo Cowork Team;
|
||||
2. xác định credential nào có khả năng bị lộ;
|
||||
3. đề xuất rotation/revocation theo security policy;
|
||||
4. giữ nguyên evidence cần thiết để team xử lý.
|
||||
|
||||
Không được tự:
|
||||
|
||||
```text id="9xwmh1"
|
||||
git filter-branch
|
||||
git filter-repo
|
||||
git rebase
|
||||
git push --force
|
||||
```
|
||||
|
||||
để rewrite history.
|
||||
|
||||
Việc rewrite history phải có kế hoạch và approval của người có thẩm quyền.
|
||||
|
||||
---
|
||||
|
||||
## S8. Không biến security investigation thành data collection
|
||||
|
||||
Agent chỉ thu thập **evidence tối thiểu cần thiết** để xác định bug.
|
||||
|
||||
Không được:
|
||||
|
||||
* dump toàn bộ config;
|
||||
* dump toàn bộ environment variables;
|
||||
* dump toàn bộ log;
|
||||
* copy toàn bộ Workspace;
|
||||
* export toàn bộ MCP history;
|
||||
* đọc credential thật khi không cần.
|
||||
|
||||
Nguyên tắc:
|
||||
|
||||
> **Collect the minimum evidence necessary to prove the defect.**
|
||||
|
||||
Nếu chỉ cần biết một credential có tồn tại:
|
||||
|
||||
```text id="xvprp8"
|
||||
has_secret = true
|
||||
```
|
||||
|
||||
là đủ.
|
||||
|
||||
Không cần biết:
|
||||
|
||||
```text id="k3uw5w"
|
||||
secret_value = "..."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Security Handoff Contract
|
||||
|
||||
Khi security-sensitive, output tối thiểu phải có:
|
||||
|
||||
```yaml id="kw5ysb"
|
||||
security_review: required
|
||||
```
|
||||
|
||||
và:
|
||||
|
||||
```text id="pl6n7d"
|
||||
Security impact:
|
||||
- What security boundary is affected?
|
||||
- What data/permission/credential is involved?
|
||||
- Is customer/project isolation affected?
|
||||
- Is additional security review required?
|
||||
```
|
||||
|
||||
Nếu chưa có đủ thông tin:
|
||||
|
||||
```text id="xqk2uj"
|
||||
Open Question:
|
||||
- ...
|
||||
```
|
||||
|
||||
Nếu cần Cowork Team quyết định policy:
|
||||
|
||||
```text id="k5j3vw"
|
||||
Handoff:
|
||||
RETURN_TO_REPORTER
|
||||
Reason:
|
||||
needs-security-decision
|
||||
```
|
||||
|
||||
Nếu đã đủ evidence và có thể tạo implementation plan:
|
||||
|
||||
```text id="8d5g6h"
|
||||
Handoff:
|
||||
fix-implementer
|
||||
|
||||
security_review:
|
||||
required
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Security Decision Flow
|
||||
|
||||
```text id="j2qz1k"
|
||||
Bug Report
|
||||
↓
|
||||
Redact Input
|
||||
↓
|
||||
Triage UI/UX
|
||||
↓
|
||||
Security Signal?
|
||||
│
|
||||
├── NO
|
||||
│ ↓
|
||||
│ Normal UI/UX workflow
|
||||
│
|
||||
└── YES
|
||||
↓
|
||||
security_review: required
|
||||
↓
|
||||
Security Impact Analysis
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ Policy decision needed? │
|
||||
└──────────────────────┘
|
||||
│
|
||||
YES ─────→ RETURN_TO_REPORTER
|
||||
│
|
||||
NO
|
||||
↓
|
||||
Security Review
|
||||
↓
|
||||
fix-implementer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Nguyên tắc cuối
|
||||
|
||||
> **UI không phải security boundary thấp hơn security.**
|
||||
>
|
||||
> Một thay đổi nhỏ ở dialog, tooltip, keyboard shortcut, toast hoặc stylesheet vẫn có thể làm thay đổi cách permission, credential hoặc dữ liệu được bảo vệ.
|
||||
|
||||
Vì vậy:
|
||||
|
||||
```text id="s5gh1v"
|
||||
Redact first
|
||||
↓
|
||||
Collect minimum evidence
|
||||
↓
|
||||
Detect security boundary
|
||||
↓
|
||||
Mark security_review
|
||||
↓
|
||||
Route correctly
|
||||
↓
|
||||
Never expose secrets
|
||||
↓
|
||||
Never rewrite history
|
||||
```
|
||||
Reference in New Issue
Block a user