Files
cowork-local/agent/examples/good_fix.md
T
anhtnm1andClaude Opus 5 7bd2b95a57 docs(agent): thư viện instruction cho việc sửa bug UI/UX
Bộ 7 role chuyên biệt (triage → specialist → implementer → reviewer) cùng
lớp dùng chung: guardrail, tri thức về repo, checklist, và contract đầu ra.

Vì sao có: bug UI/UX được báo bằng lời kể triệu chứng, và người sửa hay bỏ
qua ba thứ mà repo này rất dễ vi phạm — luật "không file nào ngoài theme/
được đặt tên một màu", trần LOC theo bánh cóc, và việc ui/ với presentation/
cùng tồn tại nên sửa nhầm file là "đã fix mà vẫn thấy lỗi".

knowledge/qt_pitfalls.md chép lại 20 nguyên nhân gốc hay gặp của bug PySide6;
examples/bad_fix.md có hai ca CÓ THẬT, gồm ca chính bản vá trong nhánh này
từng mắc (compare_digest trên str ngoài ASCII) và lọt qua vòng review đầu.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:55:02 +09:00

5.9 KiB

Ví dụ ĐẠT — một vòng xử lý bug UI hoàn chỉnh

⚠️ Kịch bản minh hoạ để dạy format. Số dòng và defect_id là giả định, không trỏ tới một lỗi có thật trong repo. Cái cần học ở đây là hình dạng của một vòng xử lý đúng.


Phản ánh gốc từ người dùng

"Chị Hoa bên BRSE bảo là bật app lên chọn tiếng Nhật thì màn Giám sát vẫn hiện tiếng Việt. Mà lạ là màn Workspace thì đổi bình thường. Chắc thiếu dịch."

✅ Bước 1 — Triage (rút gọn)

defect_id: UI-20260907-03
next_agent: i18n-a11y-fixer
category: i18n-a11y
severity: S2
confidence: high
reproducible: yes
themes_verified: [dark, light]
languages_verified: [vi, ja, en]

Quan sát vs kỳ vọng

Người dùng thấy Đổi ngôn ngữ sang ja ở top bar; Workspace đổi ngay; Monitoring vẫn vi
Người dùng mong Mọi màn đổi cùng lúc
Suy đoán (chưa xác minh) "thiếu bản dịch"

Điểm mấu chốt Triage tìm ra: suy đoán của người dùng sai. Bản dịch có đủ. Triage thử thêm một biến thể mà người dùng không nghĩ tới:

Thứ tự thao tác Kết quả
Mở Monitoring trước, rồi đổi sang ja ✅ đổi đúng
Đổi sang ja trước, rồi mới mở Monitoring ❌ vẫn vi

→ Không phải thiếu key. Là bẫy P07 (widget dựng lười bỏ lỡ sự kiện đã phát).

Khoanh vùng: presentation/shell/page_registry.py::_ensure_page — Monitoring dựng lười, Workspace dựng ngay. Đúng khớp với việc chỉ Monitoring bị.

Đây là giá trị thật của bước Triage: nếu tin theo chẩn đoán của người dùng, cả pipeline sẽ đi thêm bản dịch — sửa xong bug vẫn còn.

✅ Bước 4 — i18n-a11y-fixer (rút gọn)

Nguyên nhân gốc: _ensure_page dựng widget rồi insertWidget luôn, không áp lại ngôn ngữ hiện tại. Widget đăng ký on_language_changed trong __init__, nhưng callback chạy lần đầu với ngôn ngữ lúc đăng ký — mà lúc đó nó chưa được dựng, nên nó không thể "bỏ lỡ" gì cả... trừ khi listener của nó được đăng ký sau lần phát cuối cùng.

Đã loại các giả thuyết:

Giả thuyết Cách loại
Thiếu key ja grep -c '"ja"' i18n/monitoring_overview.py → đủ
MonitoringTab quên đăng ký listener Có đăng ký, ui/monitoring_tab.py:__init__
Do theme, không phải ngôn ngữ Tái hiện được ở cả dark và light

Mức can thiệp đã chọn: thấp nhất — sửa một chỗ ở _ensure_page, không đụng MonitoringTab. Sửa ở _ensure_page khắc phục luôn cho cả ba màn dựng lười (Dashboard, Schedule, Monitoring), thay vì vá riêng từng màn.

Đã cân nhắc và loại: thêm _retranslate() vào MonitoringTab.showEvent — vá được Monitoring nhưng Dashboard và Schedule vẫn hỏng. Đó là sửa triệu chứng.

Blast radius: cả 3 màn dựng lười. Đã grep _ensure_page — chỉ được gọi từ _goto.

LOC: page_registry.py 111/400 — an toàn.

Cách kiểm chứng:

# tests/ui/test_lazy_page_i18n.py
def test_lazy_page_uses_current_language_when_built_late(qtbot, ctx):
    """Regression: đổi ngôn ngữ trước khi mở màn dựng lười thì nhãn vẫn ngôn ngữ cũ (UI-20260907-03)."""

✅ Bước 5 — Implementer (rút gọn)

Test viết trước, xác nhận đỏ:

tests/ui/test_lazy_page_i18n.py::test_lazy_page_uses_current_language_when_built_late FAILED
AssertionError: assert 'Tổng quan' == '概要'

Diff — 4 dòng:

--- a/presentation/shell/page_registry.py
+++ b/presentation/shell/page_registry.py
@@
         real = builder()
+        # A lazily-built page misses every language/theme signal emitted before
+        # its first visit, so re-apply the current state right after building.
+        apply_current_language(real)
         placeholder = self._page_widgets[row]

Gate — output thật:

>> Running Gate: [C] Clean Architecture ...        [PASS]  0.8s
>> Running Gate: [A] Secrets Audit ...             [PASS]  1.9s
>> Running Gate: [S] LOC <= 400 ...                [PASS]  0.6s
>> Running Gate: [O] Orphan Modules ...            [PASS]  0.7s
>> Running Gate: [A/N] pytest ...                  [PASS]  74.2s

Kiểm bằng mắt: đã chạy run.bat; thử vi→ja→en với cả ba màn dựng lười, dark và light.

✅ Bước 6 — Reviewer (rút gọn)

Kiểm test có thật sự bắt bug — bước hay bị bỏ nhất:

git stash push -- presentation/shell/page_registry.py
QT_QPA_PLATFORM=offscreen pytest tests/ui/test_lazy_page_i18n.py -q   # 1 failed  ✅
git stash pop
QT_QPA_PLATFORM=offscreen pytest tests/ui/test_lazy_page_i18n.py -q   # 1 passed  ✅

Verdict: PASS

Ghi chú không chặn merge: cùng cơ chế này cũng nên áp lại theme cho màn dựng lười — diff hiện tại chỉ xử lý ngôn ngữ. Đã mở issue riêng thay vì nhét vào PR này.


Vì sao vòng này ĐẠT

Tiêu chí Bằng chứng
Triage bác bỏ chẩn đoán sai của người dùng Thử thêm biến thể thứ tự thao tác
Đúng một nguyên nhân gốc, có file:line _ensure_page
Sửa nguyên nhân, không sửa triệu chứng Sửa ở chỗ chung, không vá riêng Monitoring
Mức can thiệp thấp nhất 4 dòng, khắc phục cho cả 3 màn
Có test, và test được chứng minh là bắt được bug Revert-and-rerun
Gate output thật, không tóm tắt Dán nguyên
Phát hiện out-of-scope được tách ra Issue riêng cho theme