Files
cowork-local/docs/refactor/BaoCao_TeamDuy_R01_R03_R04.md
f9f6bc01fd
CI / test (push) Canceled after 0s
Feature/delta team/epic r04 (#7)
## Summary

epic r04 - begin refactor

## Change Type

- [x] Cowork feature
- [ ] Bug fix
- [ ] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com>
Co-authored-by: Huong Le Thi Thien <huongltt35@fpt.com>
Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com>
Co-authored-by: Vu Dam Tuan <vudt15@fpt.com>
Co-authored-by: Hiep Ha Van <hiephv3@fpt.com>
Co-authored-by: Lam Hoang Van <lamhv7@fpt.com>
Reviewed-on: #7
Co-authored-by: Duy Le Huu <duylh19@fpt.com>
2026-08-31 05:15:13 +00:00

15 KiB
Raw Permalink Blame History

BÁO CÁO KẾT QUẢ — TEAM DUY: EPIC R01, R03, R04

  • Dự án: Cowork Local (Cowork-Local BamBOO)
  • Team: 🔵 Team Duy — Core AI, Routing, Turn Runtime & Testing (Tech Lead)
  • Nhánh: feature/deltateam/refactor-plan
  • Thời gian thực hiện: 21/08/2026, 09:56 ➔ 10:56
  • Ngày báo cáo: 21/08/2026
  • Tài liệu gốc: Feature_Architecture_Proposal.md, Refactoring_Checklist.md, DeltaTeam_prompt.md

1. Tóm tắt điều hành

Hoàn tất 16/16 task của 3 EPIC được giao trong đợt này: R01 (nền tảng kiến trúc & lưới an toàn), R03 (hợp nhất provider & routing), R04 (vòng đời turn hội thoại). Toàn bộ đã commit và push lên nhánh.

Chỉ số Kết quả
Task hoàn thành 16/16 (R01: 5, R03: 6, R04: 5)
Commit 5
File thay đổi 48 (37 file mới, 11 file sửa)
Dòng code +5.843 / −225
Test 243 pass / 44s
Test suite nhanh (unit + contract + characterization + routing) 218 pass / 1,22s
CASAN Check 3 (scripts/check_imports.py) PASS — 0 Qt import trong domain/, application/
File production > 400 dòng 0

3 lỗi thật được phát hiện và sửa trong quá trình làm (chi tiết mục 5) — trong đó 1 lỗi deadlock sẽ làm treo ứng dụng ngay ở tin nhắn đầu tiên.


2. Kết quả theo từng EPIC

🔹 EPIC R01 — Architecture Foundation & Characterization (5/5)

Task Sản phẩm Ghi chú
R01-T01 docs/architecture/ADR-001-layered-architecture.md Định nghĩa 4 tầng, chiều phụ thuộc, 6 quy tắc bất biến I1–I6, chiến lược di trú Strangler Fig
R01-T02 tests/fakes/fake_provider.py, fake_tool_executor.py Test double chạy offline, kịch bản hoá, ghi lại mọi lời gọi
R01-T03 scripts/check_imports.py (239 dòng) Quét AST, bắt cả import tương đối (from ...ui import x) và import trong thân hàm
R01-T04 tests/characterization/test_run_cowork.py 13 test chụp snapshot hành vi hiện tại của run_cowork trước khi R04 đụng vào
R01-T05 docs/architecture/dormant-code.md Quét đồ thị import: 43 module "không ai import" ➔ xác minh còn 6 hạng mục chết thật (~1.887 dòng)

Điểm đáng chú ý ở R01-T03: dùng AST thay vì grep là bắt buộc — trong repo có nhiều docstring nhắc tên PySide6 một cách hợp lệ, grep sẽ báo nhầm và đội sẽ học cách tắt cổng kiểm duyệt.

Điểm đáng chú ý ở R01-T05: 43 module không có importer không đồng nghĩa 43 module chết. Sau xác minh thủ công: __main__.py là entry point, mcp_servers/ms365_server.py chạy bằng subprocess (state.py:285), 34 file tools/check_*.py là dev tooling chạy tay. Chỉ 6 hạng mục là dormant thật.

🔹 EPIC R03 — Model Providers & Routing (6/6)

Task Sản phẩm Ghi chú
R03-T01 tests/contracts/test_providers.py 29 contract test; chạy được cả 2 adapter thật mà không cần mạng nhờ thay Provider._request bằng SSE đóng hộp
R03-T02 domain/models/provider_descriptor.py, infrastructure/providers/provider_registry.py Gom 3 nơi khai báo provider về 1 chỗ
R03-T03 application/model_routing/routing_application_service.py Pure Python, 4 chế độ: Off / Auto / Manual / Fallback (mới)
R03-T04, T05 ui/chat_panel.py, ui/co4e_tab.py, ui/folder_tab.py Gỡ 3 bản sao logic routing
R03-T06 infrastructure/telemetry/usage_sink.py Tách ghi nhận token usage khỏi provider

Vấn đề gốc đã giải quyết — cùng một thuật toán routing tồn tại 3 bản gần giống nhau:

ui/chat_panel.py::_apply_routing       (~45 dòng)
ui/co4e_tab.py::_apply_co4e_routing    (~38 dòng)
ui/folder_tab.py::_ai_apply_routing    (~42 dòng)

Cả 3 đều nằm trong widget Qt ➔ không thể test nếu không dựng cửa sổ, và đã bắt đầu lệch nhau (mỗi bản xác định "model hiện tại" một kiểu). Nay cả 3 chỉ còn gọi ctx.routing_application().route_turn(...) + một callback xác nhận.

Chế độ Fallback (mới): giữ nguyên model người dùng chọn, chỉ đổi sau khi model đó lỗi. Đây là chế độ người dùng cần khi họ tin lựa chọn của mình nhưng vẫn muốn lượt chat sống sót qua sự cố nhà cung cấp.

Bộ từ vựng mode: trước đây tuple ("off", "auto", "manual") bị lặp ở 4 chỗ (config.py × 2, state.py × 2). Thêm một mode mà quên một chỗ sẽ âm thầm hạ lựa chọn của người dùng về "off". Nay tập trung vào normalize_mode() / is_valid_mode().

🔹 EPIC R04 — Agent Runtime & Conversation Service (5/5)

Task Sản phẩm Ghi chú
R04-T01 domain/agents/conversation_execution_request.py Frozen dataclass, chụp toàn bộ input của 1 turn tại thời điểm submit
R04-T02 domain/agents/agent_event.py (370 dòng) 13 event có kiểu thay cho dict không kiểu, kèm cầu nối 2 chiều
R04-T03 application/conversations/conversation_application_service.py Điều phối vòng đời turn, không import Qt
R04-T04 ui/cowork_tab.py::build_job Chuyển sang snapshot + service
R04-T05 core/task_executors.py::_run_agent Chuyển sang cùng service (trước đây là bản lắp ráp thứ hai, hơi khác)

Vấn đề gốc đã giải quyết — closure trong build_job đọc state của widget từ trong worker thread:

def job(worker):
    provider = self.build_provider()                  # đọc combo box
    proj_ctx = project_context_text(load_project(project_id))

Người dùng có thể đổi model, đổi workspace, sửa chỉ dẫn project trong lúc turn đang chạy. Turn khi đó chạy trên hỗn hợp state cũ + mới, và hỗn hợp nào phụ thuộc vào thời điểm luồng — đúng loại bug tái hiện mỗi tuần một lần và không bao giờ tái hiện trong test.

TurnCompletedEvent là tín hiệu kết thúc turn mà engine cũ hoàn toàn không có: hiện tại mọi consumer suy ra "xong" từ việc worker thread kết thúc, nên turn bị huỷ và turn thất bại trông giống hệt nhau với giao diện.


3. Kiến trúc sau refactor

presentation/  ui/chat_panel.py, ui/co4e_tab.py, ui/folder_tab.py, ui/cowork_tab.py
      │        (chỉ dựng UI, mở dialog xác nhận, render thông báo)
      ▼
application/   model_routing/routing_application_service.py    ← 4 mode routing
               conversations/conversation_application_service.py ← vòng đời turn
      │        (100% pure Python — cổng kiểm duyệt tự động chặn import Qt)
      ▼
domain/        agents/conversation_execution_request.py  ← snapshot bất biến
               agents/agent_event.py                     ← 13 event có kiểu
               models/provider_descriptor.py             ← catalog provider
      ▲
infrastructure/ providers/provider_registry.py   telemetry/usage_sink.py

Nguyên tắc di trú (ADR-001 mục 4): không viết lại engine. core/chat_agent.py::run_cowork và core/routing/* (2.263 dòng, 79 test đang xanh) vẫn là engine bên dưới; tầng application chỉ sở hữu phần trước đây bị trộn vào UI. Nhờ vậy pytest luôn xanh giữa các bước và một team có thể merge mà không phải chờ team khác.


4. Bằng chứng kiểm thử

Phân bố test

Suite Số test Thời gian Vai trò
tests/unit/ 97 Logic thuần, không Qt/mạng
tests/contracts/ 29 Mọi provider phải thoả cùng bộ cam kết
tests/characterization/ 13 Chốt hành vi hiện tại của run_cowork
tests/routing/ 79 Có sẵn từ trước, vẫn xanh
Cộng 4 suite nhanh 218 1,22s ✅ đạt CASAN "A — unit < 1s"
tests/integration/ 25 42s Widget Qt thật (offscreen) + provider kịch bản hoá
Tổng 243 44s

Đối chiếu Definition of Done (7 tiêu chí, DeltaTeam_prompt.md)

# Tiêu chí Kết quả
1 Mọi file < 400 dòng ✅ Lớn nhất: agent_event.py 370 dòng
2 0 import Qt trong domain/, application/ ✅ check_imports.py PASS
3 Comment tiếng Anh ở mọi khối sửa/mới ✅ Docstring + giải thích lý do, không chỉ mô tả code
4 Có unit/contract test, pass 100% < 1s ✅ 218 test / 1,22s
5 Không hồi quy ✅ 79 test routing có sẵn vẫn xanh
6 Ghi Start/End vào Checklist ✅ 16 task đã tick kèm mốc thời gian
7 Cổng CASAN ⚠️ run_quality_gate.py thuộc R10-T02, chưa viết. Check 3 đã có và PASS

Ba đường code đã sửa nhưng ban đầu chưa được thực thi

Sau khi hoàn tất 16 task, rà soát lại phát hiện 3 đường code đã bị sửa nhưng không test nào chạy qua. Đã bổ sung 18 test:

Đường code Rủi ro nếu bỏ qua Test bổ sung
task_executors._run_agent Autosave History có thể đóng băng ở tin nhắn đầu 7
_apply_co4e_routing / _ai_apply_routing Mới chỉ import được, chưa từng gọi hàm 11
confirm_switch(decision) Manual mode Thiếu field ➔ nổ bên trong modal, nơi khó phát hiện nhất (nằm trong 11 ở trên)

5. Ba lỗi thật phát hiện trong quá trình làm

🔴 Lỗi 1 — Deadlock khi khởi tạo routing service

AppContext.routing_application() giữ _routing_lock rồi gọi routing(), vốn cũng lấy chính lock đó. threading.Lock không reentrant ➔ treo cứng ngay ở tin nhắn đầu tiên, không có thông báo lỗi.

Sửa: tách _routing_app_lock riêng, và resolve engine trước khi lấy lock.

🟠 Lỗi 2 — Event notice bị cầu nối nuốt mất

Bản đầu của agent_event.py liệt kê 12 loại event nhưng thiếu notice. Trong khi đó notice được phát ra từ 3 nơi trên đường chạy bình thường:

  • core/agent_security.py — yêu cầu/lệnh bị Agent Security chặn
  • core/context_budget.py — hội thoại vừa bị tự động nén
  • Bộ đọc file đính kèm — file không xử lý được, và tiến độ "đang đọc trang X/Y"

Cầu nối bỏ qua event không nhận diện được (đúng thiết kế, để engine có thể thêm event mới) — nên người dùng sẽ không bao giờ thấy cảnh báo bảo mật, hoàn toàn im lặng.

Sửa: thêm NoticeEvent, và thêm test quét mã nguồn engine tìm mọi tag emit({"type": ...}) rồi bắt lỗi nếu có tag nào chưa có event tương ứng — biến sự im lặng thành test đỏ.

🟡 Lỗi 3 — Test đang chạy trên checkout khác

tests/routing/conftest.py đẩy thư mục cha vào sys.path. Vì thư mục checkout tên là cowork_local_gitea (không phải cowork_local), lệnh import cowork_local ăn nhầm sang Desktop\cowork_local — một bản checkout khác. Suite báo xanh trên mã nguồn không phải nhánh đang review.

Sửa: tests/conftest.py nạp __init__.py theo đường dẫn tuyệt đối và đăng ký vào sys.modules trước mọi test.


6. Cải thiện phụ (không nằm trong yêu cầu task)

Cải thiện Ảnh hưởng
ProviderRegistry.build() đóng dấu descriptor.id lên instance Sửa việc usage của ollama / github_copilot / codex bị ghi nhận nhầm thành openai_compat trên Dashboard. Chưa nối vào production — xem mục 7.
ProviderRegistry.build() copy config trước khi ghi Trước đây một model do routing chọn có thể ghi đè lên default đã lưu của người dùng
UsageTrackerSink ghi log ở mức debug khi thất bại Trước là except: pass — mất sạch lý do khi Dashboard hỏng
estimate_tokens được chốt bằng test so với core.usage_tracker Bảo đảm việc tách telemetry không làm lệch một con số nào

7. Còn nợ & cần quyết định

# Nội dung Người quyết
1 ProviderRegistry chưa nối vào state.build_provider_for (vẫn dùng providers/factory.py). Nối vào sẽ sửa lỗi quy kết usage ở mục 6, nhưng đổi cách gom dữ liệu lịch sử trên Dashboard. Team Duy + PO
2 Mode fallback chưa có trên toggle UI — config và service đã hỗ trợ đầy đủ; widget RoutingToggle thuộc R08. Team Duy (R08)
3 Đã sửa 2 dòng trong config.py (routing_mode_for, set_routing_mode_for) để dùng chung bộ từ vựng mode. File này Team Nam đang refactor ở R02-T02. ⚠️ Cần báo Team Nam
4 Circular import core/model_pricing.py ↔ core/usage_tracker.py chưa xử lý (task ngày 28/08). Team Duy
5 2 test đỏ có sẵn từ trước: config.py:108 hardcode sandbox_pw = "quandh14" ➔ tests/test_config_security.py. Thuộc EPIC R02 / Team Nam. 🟣 Team Nam
6 tests/integration/test_routing_surfaces.py mất 41s do dựng Co4ETab/FolderTab. Nên gắn marker slow khi làm R10. Team Duy (R10)

8. Phạm vi chưa kiểm thử

Nêu rõ để tránh hiểu nhầm mức độ bảo đảm:

  • Chưa mở ứng dụng bằng tay — mới chạy widget headless (QT_QPA_PLATFORM=offscreen), chưa có ai kiểm tra bằng mắt.
  • Chưa gọi provider thật — toàn bộ dùng FakeProvider, không có lưu lượng mạng.
  • Chưa chạy 34 script tools/check_*.py — các script này tự sys.path.insert thư mục cha nên sẽ import nhầm checkout khác (đúng lỗi 3 ở mục 5). Cần sửa chúng ở R10.

9. Việc kế tiếp của Team Duy

EPIC Nội dung Điều kiện
R08 (T01 ➔ T06) Tách ui/chat_panel.py (1.795 dòng) thành 6 widget < 400 dòng Sẵn sàng bắt đầu — AgentEvent (R04-T02) chính là kênh dữ liệu 6 widget con sẽ dùng thay vì đọc trực tiếp state của ChatPanel
R10 (T01 ➔ T05) Testing Pyramid, run_quality_gate.py, Contributor Recipes, E2E Smoke Chờ cả 3 team hoàn tất

10. Lịch sử commit

Commit Nội dung
bbc09f6 feat(R01): architecture foundation, offline fakes and characterization net
96bec97 feat(R03): unify provider catalogue, routing decisions and usage telemetry
a53163e feat(R04): immutable turn snapshot, typed agent events, conversation service
15e1d3e test(R03/R04): cover the three code paths that were changed but never executed
67b8d2e docs(refactor): correct the Team Duy scope block in the checklist