Files
cowork-local/docs/refactor/BaoCao_TeamHoa_R07_R08.md
T

21 KiB
Raw Blame History

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.md mụ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ách test_history_dir_race.py đã lập ở R06-T04.
  • Test đã sửa (không phải mới): tests/integration/test_routing_surfaces.py — 2 test test_ai_edit_* trỏ thẳng vào ui.folder_tab.FolderTab._ai_apply_routing/_ai_routed_provider (thuộc code CŨ); đã cập nhật để trỏ vào presentation.folder.folder_tab.FolderTab.ai_panel.resolver.apply_routing/.routed_provider (thêm 2 property public mới trên AiEditModelResolver để 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 qua AgentWorker) — chỉ verify được bằng cách đọc code + đảm bảo import/construction không lỗi (test_folder_tab.py dựng FolderTab thậ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 (wiring node_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_model qua test_routing_surfaces.py.
  • office_document_renderer.py's PDF/LibreOffice conversion path (show_document, _ensure_pdf_view) — cần QtPdf/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