21 KiB
BÁO CÁO KẾT QUẢ — TEAM HOA: EPIC R07, R08 (phần Team Hoa)
- Dự án: Cowork Local (Cowork-Local BamBOO)
- Team: 🟢 Team Hoa — Workspace, Filesystem, Scheduling & Tool Registry
- Nhánh:
feature/teamhoa/r05-r06(tiếp tục từ R05/R06, chưa push lên remote — xem mục 7 #4) - Thời gian thực hiện: 27/08/2026, 16:05 → 20:52
- Ngày báo cáo: 27/08/2026
- Tài liệu gốc:
Feature_Architecture_Proposal.md,Refactoring_Checklist.md,plan.md,BaoCao_TeamHoa_R05_R06.mdmục 9 ("Việc kế tiếp của Team Hoa")
1. Tóm tắt điều hành
Hoàn tất 9/9 task thuộc phạm vi Team Hoa của 2 EPIC: R07 (Scheduling & Workflow Runtime, T01→T05) và R08 (UI/Application Separation, T11→T14). Đã commit 2 commit trên branch cục bộ; chưa push lên Gitea (cùng lý do đã ghi nhận ở báo cáo R05/R06).
| Chỉ số | Kết quả |
|---|---|
| Task hoàn thành | 9/9 (R07: 5, R08: 4 — không tính R07-T06/R08-T01→T10 của team khác) |
| Commit | 2 (69ab8e1 R07, 0e51356 R08) |
| File thay đổi (R08 riêng) | 51 (44 file mới, 1 file đổi tên+sửa, 6 file sửa) |
| Test | 377 pass / 4 fail (283 sau R05/R06 → 328 sau R07 → 377 sau R08; +94 test mới) |
CASAN Check 3 (scripts/check_imports.py) |
PASS — 0 Qt import trong domain/, application/ |
| File production > 400 dòng (file mới) | 0 — lớn nhất presentation/graph/graph_renderer.py 391 dòng |
python -c "import cowork_local.app" |
OK sau mỗi task |
1 quyết định kiến trúc thay đổi so với plan gốc, xác nhận bằng thực nghiệm (chi tiết mục 5): platform/qt/qt_scheduler_clock.py (R07-T03) đổi thành infrastructure/qt/qt_scheduler_clock.py vì package platform/ ở top-level đè lên module chuẩn platform của Python trong một số ngữ cảnh chạy.
2. Kết quả theo từng EPIC
🔹 EPIC R07 — Scheduling & Workflow Runtime (5/5, phạm vi Team Hoa)
| Task | Sản phẩm | Ghi chú |
|---|---|---|
| R07-T01 | infrastructure/persistence/json/task_repository_impl.py::TaskRepository |
Bọc CRUD của core/tasks.py. Sửa bug thật: save_task trước đây path.write_text() không atomic — cùng lớp bug đã sửa cho projects.py/history.py ở R06-T02. Giờ ghi qua atomic_write.py::write_json. |
| R07-T02 | domain/tasks/schedule_calculator.py::ScheduleCalculator |
Tách phần "schedule math" (cron/interval/daily/weekly/monthly + working-days/holiday exclusion) khỏi core/tasks.py thành pure Python. is_holiday/make_cron inject qua constructor để domain/ không import core/ (ADR-001 I2). core/tasks.py giữ nguyên tên hàm cũ, chuyển thành wrapper mỏng — không phá call site nào. Trước đây 0 test, giờ có 14 test riêng. |
| R07-T03 | infrastructure/qt/qt_scheduler_clock.py::QtSchedulerClock |
Bọc QTimer mà TaskScheduler trước đây tự tạo trực tiếp, inject qua tham số clock= mới (mặc định vẫn dùng clock thật). tests/fakes/fake_clock.py::FakeClock cho phép test dispatch tick-by-tick không cần Qt event loop. Đổi vị trí so với plan gốc — xem mục 5. |
| R07-T04 | application/scheduling/task_application_service.py::TaskApplicationService |
Gom run_now/duplicate/pause/delete/bulk_delete và luật nghiệp vụ kéo-thả Kanban (move_to_status) — trước đây chỉ kiểm chứng được bằng cách thao tác trực tiếp trên widget thật. |
| R07-T05 | application/scheduling/ai_task_planner_service.py::AiTaskPlannerService |
Bọc core/ai_task_planner.py::plan_tasks và core/task_import.py::import_tasks làm seam, cộng thêm bước "gắn file/link đính kèm vào mọi task vừa tạo" (trước đây chỉ tồn tại trong closure của AI worker). |
Ghi chú phạm vi: R07-T06 (Co4EWorkflowService, core/co4e_run_manager.py) là việc Team Nam — không đụng.
🔹 EPIC R08 — UI/Application Separation (4/4, phạm vi Team Hoa: T11→T14)
presentation/ chưa tồn tại trong repo trước task này — Team Hoa là người tạo cấu trúc presentation/ đầu tiên.
| Task | God file gốc | Tách thành | Ghi chú |
|---|---|---|---|
| R08-T11 | ui/schedule_task_tab.py (795 dòng) |
presentation/scheduling/{kanban_board_widget,calendar_view_widget,ai_task_creator_dialog,ai_task_import_dialog,run_history_dialog}.py + shell schedule_task_tab.py |
Kéo-thả Kanban giờ gọi TaskApplicationService.move_to_status (R07-T04) thay vì ~30 dòng if/elif nội tuyến. |
| R08-T12 | ui/folder_tab.py (1587 dòng — lớn nhất trong 4 file) |
presentation/folder/{workspace_file_tree,document_preview_manager,code_editor,office_document_renderer,ai_file_editor_dialog,ai_edit_model_resolver,ai_edit_pipeline}.py + shell folder_tab.py |
Nối xong FileWorkspaceService (nợ từ R06-T05) — xem mục 5. |
| R08-T13 | ui/dashboard_tab.py (437 dòng) |
presentation/dashboard/{token_usage_card_widget,usage_chart_widget,habits_widget}.py + shell dashboard_tab.py |
application/monitoring/dashboard_query_service.py mới — 3 widget dùng chung 1 nơi merge pricing/period thay vì mỗi widget tự tính lại. Ghi chú xung đột thư mục — xem mục 5. |
| R08-T14 | ui/structure_graph_view.py (1035 dòng) |
presentation/graph/{graph_scene_items,graph_renderer,graph_messages_view,graph_qa_widget}.py + shell structure_graph_view.py |
Renderer và Q&A panel chỉ giao tiếp qua signal (node_selected/graph_rendered/raw_json_ready/project_changed) — không bên nào import bên kia. |
Quy ước áp dụng cho cả 4 task: mỗi god-file cũ chỉ có 1-2 nơi khởi tạo thật (app.py, ui/workspace_tab.py) — khác core/tools.py ở R05 (hàng chục call site nên phải giữ shim). Nên đã sửa thẳng import site và xoá hẳn file ui/*.py cũ, không giữ shim vô thời hạn.
3. Kiến trúc sau refactor
presentation/ (MỚI — Team Hoa tạo cấu trúc lần đầu)
scheduling/ {kanban_board_widget, calendar_view_widget,
ai_task_creator_dialog, ai_task_import_dialog,
run_history_dialog, schedule_task_tab}.py
folder/ {workspace_file_tree, document_preview_manager, code_editor,
office_document_renderer, ai_file_editor_dialog,
ai_edit_model_resolver, ai_edit_pipeline, folder_tab}.py
dashboard/ {token_usage_card_widget, usage_chart_widget,
habits_widget, dashboard_tab}.py
graph/ {graph_scene_items, graph_renderer, graph_messages_view,
graph_qa_widget, structure_graph_view}.py
shared/ web_engine_support.py (HAS_WEB_ENGINE — 1 flag dùng chung
thay vì folder/ import module của graph/)
│
▼
application/ scheduling/{task_application_service, ai_task_planner_service}.py
monitoring/dashboard_query_service.py
workspaces/{file_preview_helpers, ai_edit_output, graph_index_service}.py
│ (100% pure Python — check_imports.py chặn import Qt)
▼
domain/ tasks/schedule_calculator.py ← due-time/cron math thuần Python
▲
infrastructure/ qt/qt_scheduler_clock.py ← QTimer đằng sau 1 interface nhỏ
persistence/json/task_repository_impl.py
Nguyên tắc di trú (tiếp nối R04/R05/R06): không viết lại engine. core/tasks.py, core/task_scheduler.py, core/task_executors.py, core/ai_task_planner.py, core/task_import.py vẫn là logic gốc bên dưới; các module mới chỉ sở hữu phần đã từng nằm rải rác trong widget (business rule kéo-thả, model routing, extraction pipeline). pytest xanh liên tục giữa các bước — chạy full suite sau MỖI task, không dồn tới cuối.
Điểm khác với R05/R06: khi 1 file bị tách vượt quá 400 dòng dù đã theo đúng mapping trong Feature_Architecture_Proposal.md, đã tách thêm 1-2 file phụ theo kiểu composition (một class phụ nhận owner là widget chính, thao tác trực tiếp lên state của owner) thay vì service riêng biệt — ví dụ run_history_dialog.py, office_document_renderer.py, ai_edit_pipeline.py, ai_edit_model_resolver.py, graph_messages_view.py. Đây là split thuần kỹ thuật để đạt giới hạn LOC, không phải ranh giới kiến trúc tầng (cả object chính và object phụ đều ở presentation/).
4. Bằng chứng kiểm thử
Phân bố test (bao gồm test mới của Team Hoa)
| Mốc | Tổng pass | Test mới thêm |
|---|---|---|
| Sau R05/R06 (baseline) | 283 | — |
| Sau R07 (T01→T05) | 328 | +45 |
| Sau R08 (T11→T14) | 377 | +49 |
| Tổng test mới R07+R08 | +94 |
4 fail còn lại giống hệt baseline đã ghi nhận ở báo cáo R05/R06 — không liên quan R07/R08:
tests/test_config_security.py× 2 (EPIC R02/Team Nam)tests/unit/test_routing_wiring.py× 2 (môi trường máy này có Ollama/llama3.1 thật)
Loại test theo task
- Pure Python, không Qt (R07-T01/T02/T04/T05,
application/workspaces/*,application/monitoring/*):tests/unit/test_{task_repository,schedule_calculator,task_application_service,ai_task_planner_service,dashboard_query_service,file_preview_helpers_and_ai_edit_output,graph_index_service}.py. - Qt thật, offscreen (R07-T03, R08-T11→T14):
tests/integration/test_{qt_scheduler_clock,task_scheduler_clock_wiring* (unit, dùng FakeClock),schedule_task_tab,folder_tab,dashboard_tab,structure_graph_view}.py— dựng widget thật, không phải double, theo đúng phong cáchtest_history_dir_race.pyđã lập ở R06-T04. - Test đã sửa (không phải mới):
tests/integration/test_routing_surfaces.py— 2 testtest_ai_edit_*trỏ thẳng vàoui.folder_tab.FolderTab._ai_apply_routing/_ai_routed_provider(thuộc code CŨ); đã cập nhật để trỏ vàopresentation.folder.folder_tab.FolderTab.ai_panel.resolver.apply_routing/.routed_provider(thêm 2 property public mới trênAiEditModelResolverđể giữ khả năng test).
Đối chiếu Definition of Done
| # | Tiêu chí | Kết quả |
|---|---|---|
| 1 | Mọi file mới < 400 dòng | ✅ Lớn nhất: presentation/graph/graph_renderer.py 391 dòng |
| 2 | 0 import Qt trong domain/, application/ |
✅ check_imports.py PASS |
| 3 | Comment tiếng Anh giải thích lý do ở mọi khối sửa/mới | ✅ |
| 4 | Có unit/contract/integration test, verify bằng chạy thật | ✅ +94 test mới, mọi widget Qt test bằng offscreen thật |
| 5 | Không hồi quy | ✅ 377/381 pass — 4 fail là lỗi có sẵn từ trước, cùng baseline R05/R06 |
| 6 | Ghi Start/End vào Checklist | ✅ 9 task đã tick kèm mốc thời gian thật |
| 7 | Cổng CASAN (run_quality_gate.py, R10-T02) |
⚠️ Chưa viết (thuộc R10, chưa tới lượt) — Check 3 đã PASS |
5. Quyết định kiến trúc & phát hiện trong quá trình làm
🔴 R07-T03 — platform/qt/ đè lên module chuẩn platform của Python
Plan gốc (Feature_Architecture_Proposal.md) đặt tên platform/qt/qt_scheduler_clock.py — một package top-level mới tên platform. Trước khi viết, đã thử:
cd <repo_root> && python -c "import cowork_local; import platform; print(platform.system())"
Sau khi tạo platform/__init__.py, lệnh trên báo lỗi:
AttributeError: module 'platform' has no attribute 'system' (consider renaming
'...\platform\__init__.py' since it has the same name as the standard library
module named 'platform' and prevents importing that standard library module)
Nguyên nhân: package repo root chính là cowork_local, nhưng bất cứ khi nào chính thư mục repo root nằm trực tiếp trên sys.path (ví dụ chạy python -c "..." hoặc bất kỳ script nào với cwd = repo root — không đi qua __main__.py's parent-dir fixup), import platform sẽ phân giải nhầm vào package cục bộ thay vì thư viện chuẩn. core/windows_sandbox_vm.py và core/appcontainer_sandbox.py đều import platform — nếu 2 file này chạy trong ngữ cảnh cwd=repo root, chức năng phát hiện hệ điều hành sẽ vỡ hoàn toàn.
Sửa: chuyển sang infrastructure/qt/qt_scheduler_clock.py (không tạo package platform/ mới) — infrastructure/ đã có sẵn các thư mục cùng cấp (filesystem/, mcp/, persistence/, providers/, telemetry/), đúng layer cho một adapter cụ thể-toolkit. Verify lại: python -c "import cowork_local; import platform; print(platform.system())" → Windows (đúng).
🟠 R08-T12 — Nối FileWorkspaceService (nợ từ R06-T05)
Báo cáo R05/R06 mục 7-#3 đã ghi: "FileWorkspaceService chưa có nơi gọi thật... ui/folder_tab.py vẫn dùng trực tiếp core/tools.py::execute_tool". Xác nhận lại bằng grep trước khi bắt đầu R08-T12: đúng 0 occurrence.
Khi tách document_preview_manager.py, mọi điểm ghi text thuần (save(), create_new_file(), write_content()) đã chuyển sang gọi FileWorkspaceService.write_file(rel, content) — dùng WorkspaceSession.unscoped(Path(root)) vì Folder Explorer duyệt bất kỳ thư mục nào người dùng chọn (không giới hạn vào 1 project sandbox). Nhánh ghi .pptx (build file nhị phân từ pptx_edit) vẫn giữ nguyên đường cũ — không phải văn bản thuần, FileWorkspaceService không có ý nghĩa ở đó.
Tác dụng phụ có lợi, không chủ đích tìm kiếm nhưng xác nhận đúng: infrastructure/filesystem/file_tools.py::write_file đã có sẵn cảnh báo cú pháp Python (_check_python_syntax) và tự tạo .xlsx thật từ text khi đích là .xlsx — cả 2 hành vi này trước đây KHÔNG tồn tại trên đường ghi cũ của folder_tab.py (chỉ Path.write_text() trần). Từ giờ Folder Explorer/AI Editor được hưởng cả 2 miễn phí, cùng đường với agent's write_file tool.
🟡 R08-T13 — Xung đột thư mục application/monitoring/ với Team Nam
Giống cách R06-T02 xử lý xung đột atomic_write.py vs atomic_json_file.py: Feature_Architecture_Proposal.md's bảng "Ranh giới phân hệ" giao application/monitoring/ cho Team Nam (R08-T07→T10), nhưng cùng tài liệu đó lại đặt dashboard_query_service.py vào ĐÚNG thư mục này như một phần việc Dashboard của Team Hoa (R08-T13). Vì thư mục chưa tồn tại (chưa ai tạo trước), không có xung đột FILE thật — chỉ tạo file mới. Đã ghi chú trong application/monitoring/__init__.py's docstring và trong Checklist để Team Nam xác nhận khi họ bắt đầu R08-T07→T10.
6. Cải thiện phụ (không nằm trong yêu cầu task)
| Cải thiện | Ảnh hưởng |
|---|---|
core/tasks.py::save_task chuyển sang ghi atomic (R07-T01) |
Cùng lớp bug đã sửa cho projects.py/history.py ở R06-T02 — path.write_text() trần không atomic, crash giữa lúc ghi để lại file task hỏng, load_task coi như "không tồn tại" → mất task âm thầm. Có test giả lập crash xác nhận file cũ không hỏng. |
domain/tasks/schedule_calculator.py có bộ test riêng (R07-T02) |
core/tasks.py's docstring tự nhận "Qt-free so it can be unit-tested headlessly" nhưng 0 test tồn tại cho phần cron/interval/holiday-exclusion trước task này. Giờ có 14 test bao phủ daily/weekly/monthly/cron + working-days/holiday. |
AiEditModelResolver.routed_provider/.routed_model (public property mới, R08-T12) |
Cần thêm để giữ được tests/integration/test_routing_surfaces.py's 2 test AI-Edit routing sau khi lớp routing chuyển từ FolderTab sang AiEditModelResolver — không có trong yêu cầu gốc nhưng bắt buộc để không hồi quy 1 test đã có từ EPIC R03. |
7. Còn nợ & cần quyết định
| # | Nội dung | Người quyết |
|---|---|---|
| 1 | application/monitoring/ xung đột quy hoạch với Team Nam (mục 5) — cần xác nhận hợp nhất hay giữ nguyên khi Team Nam bắt đầu R08-T07→T10. |
Team Nam |
| 2 | AI-Edit pipeline (ai_edit_pipeline.py) và Graph Q&A ask-flow (graph_qa_widget.py::_ask) chưa có test end-to-end thật — cả 2 chạy trên AgentWorker (QThread) thật, và vốn dĩ đã không có test nào trước khi refactor (xác nhận bằng grep trước khi bắt đầu R08-T12/T14). Phạm vi test hiện tại: wiring giữa các widget, containment ghi file, render pipeline gọi trực tiếp (_render()), KHÔNG phải luồng gửi câu hỏi/instruction → chờ AgentWorker → nhận kết quả qua QThread thật. |
Team Hoa (nếu cần, thuộc phạm vi R10 Testing Pyramid) |
| 3 | Dev tooling chưa cập nhật đường dẫn cũ: tools/check_controls_alive.py, tools/capture_screens.py, tools/build_audit_page.py, docs/screens/*.json, docs/ui-audit*.html vẫn tham chiếu ui/schedule_task_tab.py/ui/folder_tab.py/ui/dashboard_tab.py/ui/structure_graph_view.py (đường dẫn cũ, giờ không còn tồn tại) — các script/tài liệu này không nằm trong tests/, không ảnh hưởng CI, nhưng sẽ lỗi nếu chạy tay. |
Chưa quyết định người phụ trách |
| 4 | Chưa git push — cùng tình trạng đã ghi nhận ở báo cáo R05/R06 mục 7-#1. |
Admin Gitea |
| 5 | WorkspaceRepository/ConversationRepository (R06) vẫn chưa có call site sản xuất thật — R08-T12 chỉ nối FileWorkspaceService, không đụng 2 repository kia (nằm ngoài phạm vi Folder Explorer). |
Còn treo từ R06, chưa có EPIC nào nhận |
8. Phạm vi chưa kiểm thử
Nêu rõ để tránh hiểu nhầm mức độ bảo đảm, cùng tinh thần minh bạch đã dùng ở báo cáo R05/R06:
presentation/folder/ai_edit_pipeline.py(toàn bộ luồng plan → edit → apply/discard, streaming quaAgentWorker) — chỉ verify được bằng cách đọc code + đảm bảo import/construction không lỗi (test_folder_tab.pydựngFolderTabthật, mở AI panel, nhưng không gửi instruction qua worker thật). Đây là khoảng trống có sẵn từ code gốc, không phải hồi quy do refactor.presentation/graph/graph_qa_widget.py::_ask(câu hỏi → provider thật → trích xuất file → câu trả lời) — tương tự, chỉ test được phần không cần AgentWorker thật (wiringnode_selected/project_changed,_candidate_file_paths, dedup).presentation/folder/ai_edit_model_resolver.py's image-model scan/suggest (_scan_all_image_models,_suggest_cross_provider_image) — chưa test với provider thật có model ảnh; unit test chỉ phủrouting/routed_provider/routed_modelquatest_routing_surfaces.py.office_document_renderer.py's PDF/LibreOffice conversion path (show_document,_ensure_pdf_view) — cầnQtPdf/LibreOffice cài thật trên máy chạy test; chưa xác nhận trên máy không có 2 phụ thuộc này (tự động fallback sang text, đã giữ nguyên logic, nhưng chưa lặp lại kịch bản fallback bằng test thật).- Đã mở app thật bằng
python -c "import cowork_local.app"sau mỗi task để xác nhận không lỗi import — chưa mở app GUI thật, thao tác tay qua Schedule Task/Folder Explorer/Dashboard/GraphRAG để xác nhận trải nghiệm người dùng cuối (chỉ verify bằng test Qt offscreen).
9. Việc kế tiếp của Team Hoa
Theo Refactoring_Checklist.md, phạm vi 4 EPIC của Team Hoa (R05, R06, R07, R08 phần T11→T14) đã hoàn tất toàn bộ. Các bước còn lại không thuộc EPIC riêng của Team Hoa nữa:
| Việc | Điều kiện |
|---|---|
| Checkpoint 2 (Services & Sub-widgets, 28/08) | Cần cả 3 team xong phần UI split của mình (Team Duy R08-T01→T06, Team Nam R08-T07→T10 vẫn đang làm) |
| CASAN Check 2 (Modularity/LOC, Team Hoa chủ trì, 30/08) | scripts/check_loc.py chưa tồn tại (thuộc R10-T02, Team Duy) — khi có script, chạy trên toàn repo để xác nhận 0 file >400 dòng |
Giải quyết mục 7 #1 (xung đột application/monitoring/) |
Khi Team Nam bắt đầu R08-T07→T10 |
| R10 (Testing, Packaging & Contributor Experience) | Team Duy chủ trì, chờ 3 team hoàn tất |
10. Lịch sử commit
| Commit | Nội dung |
|---|---|
69ab8e1 |
feat(R07): task repository, schedule calculator, Qt clock adapter, task/AI-planner services |
0e51356 |
feat(R08): split ScheduleTaskTab, FolderTab, DashboardTab, StructureGraphView |