diff --git a/docs/refactor/COWORK_LOCAL_REFACTOR_PLAN.md b/docs/refactor/COWORK_LOCAL_REFACTOR_PLAN.md new file mode 100644 index 0000000..90e30cc --- /dev/null +++ b/docs/refactor/COWORK_LOCAL_REFACTOR_PLAN.md @@ -0,0 +1,1657 @@ +# Cowork Local Refactor Plan + +> Phạm vi: phân tích source và lập kế hoạch; tài liệu này không thực hiện refactor, không di chuyển file và không thay đổi hành vi runtime. +> +> Baseline tại thời điểm phân tích: 162 file được CodeGraph index, khoảng 45.000 dòng Python; `81 passed` khi chạy `.venv/bin/python -m pytest tests -q`. + +## 1. Executive Summary + +Cowork Local là ứng dụng desktop Python/PySide6 chạy local-first. Luồng chính hiện tại đi từ `__main__.py` tới `app.run()`, dựng một `AppContext`, sau đó để `MainWindow` khởi tạo UI, scheduler và phần lớn lifecycle của ứng dụng. Runtime agent, provider, MCP, connector, workspace và persistence đã có các module riêng, nhưng UI vẫn trực tiếp điều phối nhiều concern đó. Kết quả là repository có module decomposition nhưng chưa có dependency boundary rõ. + +Các điểm quan trọng nhất từ source hiện tại: + +- `ui/chat_panel.py::ChatPanel`, `ui/co4e_tab.py::Co4ETab`, `ui/folder_tab.py::FolderTab`, `app.py::MainWindow`, `state.py::AppContext` và `config.py::AppConfig` đang là các điểm coupling lớn. +- Model routing, provider selection, usage tracking, persistence và filesystem operation bị lặp hoặc gọi trực tiếp từ nhiều screen. +- `core/chat_agent.py` là runtime seam có giá trị: phần lớn Cowork, scheduled Cowork và Co4E cuối cùng đều dùng `run_cowork()`. Tuy nhiên orchestration trước/sau runtime vẫn nằm trong UI hoặc executor. +- Tool security chưa có capability model thống nhất. Built-in command có classifier/sandbox/confirmation, nhưng generic MCP/REST tool có thể đi qua đường thực thi khác mà không được phân loại read/write/execute tương đương. +- `active_project_id`, project history directory và routed provider/model là mutable state dùng chung. Một turn chạy nền có thể quan sát project hoặc route mới nếu người dùng đổi selection trong lúc turn đang chạy. +- Persistence là nhiều JSON/JSONL store tự quản lý, chủ yếu ghi trực tiếp, không có atomic-write/schema-version/locking policy dùng chung. Routing assessment store là ví dụ tốt hiếm hoi đã có atomic replace và backup. +- Hai circular import ở mức module được CodeGraph phát hiện: `core.model_pricing` ↔ `core.usage_tracker` và `core.agent_security` ↔ `core.agent_security_alert`. +- Test baseline xanh nhưng rất hẹp: đa số test dành cho `core/routing`; ngoài routing chỉ có coverage đáng kể cho config security. Runtime agent, UI orchestration, tool policy, MCP/connectors, persistence và scheduler chưa có safety net tương xứng. + +Khuyến nghị không chia repository thành “frontend/backend”. Đây là một process desktop; boundary phù hợp hơn là: + +```text +Presentation (PySide6) + ↓ +Application services / use cases + ↓ +Domain & runtime contracts + ↑ +Infrastructure adapters + +Composition root nối Presentation, Application và Infrastructure. +``` + +Đơn vị refactor chính nên là **subsystem/capability**, bên trong chia tiếp thành module → class → function. Sau khi application service đã có, UI mới được migrate theo từng screen. Đây là cách giảm conflict tốt nhất giữa nhiều contributor mà vẫn tránh big-bang rewrite. + +Roadmap đề xuất 10 EPIC: + +1. Architecture Foundation & Characterization +2. Configuration, Secrets & Persistence +3. Model Providers & Routing +4. Agent Runtime & Conversation Application Service +5. Tool, MCP & Connector Policy +6. Workspace, Filesystem & History Isolation +7. Scheduling & Workflow Runtime +8. UI/Application Separation +9. Security Runtime, Sandbox & Observability +10. Testing, Packaging & Contributor Experience + +## 2. Current Repository Structure + +### 2.1 Cấu trúc cấp cao + +```text +cowork_local/ +├── __main__.py # Python module entrypoint +├── app.py # QApplication, MainWindow, bootstrap/lifecycle +├── state.py # AppContext service locator + mutable app state +├── config.py # DEFAULT_CONFIG + AppConfig JSON persistence +├── paths.py # package/resource path helpers +├── i18n.py # global translations + listener registry +├── theme.py # application styling +├── core/ +│ ├── chat_agent.py # Cowork agent loop +│ ├── code_agent.py # code-oriented agent loop +│ ├── worker.py # AgentWorker/QThread bridge +│ ├── task_executors.py # scheduled task dispatch +│ ├── tasks.py # task repository + schedule calculation +│ ├── projects.py # project repository +│ ├── history.py # conversation persistence +│ ├── co4e*.py # Co4E definitions, runner, run manager +│ ├── flows.py # second flow/workflow concept +│ ├── tools.py # built-in tool schemas + giant dispatcher +│ ├── mcp_client.py # MCP process/client adapter +│ ├── ext_connectors.py # generic REST/MCP connectors +│ ├── ms365_*.py # MS365 auth/Graph/tool adapters +│ ├── routing/ # model routing service/orchestrator/store/prober +│ ├── agent_security*.py # AI-assisted prompt/command guardrails +│ ├── sandbox_manager.py # command execution and sandbox selection +│ ├── *_sandbox*.py # integrity/AppContainer/Windows VM helpers +│ ├── audit_log.py # active audit query/write path +│ └── ... # skills, agents, docs, pricing, telemetry +├── security/ +│ ├── command_risk_classifier.py +│ ├── audit_logger.py +│ ├── prompt_validator.py +│ ├── attachment_validator.py +│ └── action_validator.py +├── providers/ +│ ├── base.py # provider contract and ToolSpec +│ ├── anthropic.py +│ ├── openai_compat.py +│ └── factory.py +├── ui/ +│ ├── chat_panel.py +│ ├── cowork_tab.py +│ ├── workspace_tab.py +│ ├── co4e_tab.py +│ ├── folder_tab.py +│ ├── structure_graph_view.py +│ ├── schedule_task_tab.py +│ ├── monitoring_tab.py +│ ├── settings_dialog.py +│ └── ... # dashboard, admin, skills, reusable widgets +├── mcp_servers/ +│ └── ms365_server.py +├── tests/ +│ ├── test_config_security.py +│ └── test_routing_*.py +├── docs/ +│ ├── governance/ +│ ├── integration/ +│ └── gitea/ +└── requirements-test.txt +``` + +### 2.2 Nhận xét về package structure + +- Tên `core/` hiện không đồng nghĩa với “domain thuần”. Nó chứa Qt worker/scheduler, MCP transport, filesystem repositories, security, telemetry và agent loop; provider adapters lại nằm ở package top-level `providers/`. +- `ui/` không chỉ chứa presentation. Nhiều widget gọi provider, routing, filesystem, persistence và agent runtime trực tiếp. +- `security/` và các file security trong `core/` tạo hai namespace có responsibility chồng lấn. +- Root modules `app.py`, `state.py`, `config.py`, `i18n.py` có fan-in/fan-out cao và hoạt động như global infrastructure. +- `core/flows.py` và `core/co4e*.py` cùng mô tả workflow nhưng có model/runtime khác nhau. +- `core/custom_agents.py`, `core/admin_agents.py` và custom agents trong Co4E là ba đường quản lý agent chưa có taxonomy chung. + +## 3. Current Architecture + +### 3.1 Composition và lifecycle + +`__main__.main()` lazy-import `app.run()`. `app.run()`: + +1. Khởi tạo `QApplication`. +2. Load `AppConfig`. +3. Tạo `AppContext`. +4. Áp dụng language/theme. +5. Best-effort prune/seed skills và Co4E flows. +6. Gán audit/usage identity cho account `local`, role `admin`. +7. Tạo và hiển thị `MainWindow`. +8. Vào Qt event loop. + +`MainWindow` đồng thời là: + +- composition root của phần lớn screen; +- controller cho navigation; +- owner của `TaskScheduler`; +- owner của tray/lifecycle; +- cầu nối settings/theme/language; +- coordinator cho history/task notification; +- điểm shutdown MCP. + +Đây là kiến trúc “UI-centric service locator”: widget nhận `AppContext`, rồi tự lấy config/provider/routing/MCP/repository cần dùng. + +### 3.2 Runtime architecture thực tế + +```mermaid +flowchart TD + Entry["__main__.py::main"] --> Run["app.py::run"] + Run --> Config["AppConfig.load"] + Run --> Context["AppContext"] + Run --> Window["MainWindow"] + + Window --> Scheduler["TaskScheduler"] + Window --> Workspace["WorkspaceTab"] + Window --> Dashboard["DashboardTab"] + Window --> Schedule["ScheduleTaskTab"] + Window --> Monitoring["MonitoringTab"] + + Workspace --> Cowork["CoworkTab / ChatPanel"] + Workspace --> Co4E["Co4ETab"] + Workspace --> Folder["FolderTab"] + Workspace --> Graph["StructureGraphView"] + + Cowork --> Worker["AgentWorker"] + Co4E --> Worker + Scheduler --> Worker + Worker --> ChatRuntime["chat_agent.run_cowork"] + Worker --> CodeRuntime["code_agent.run_code"] + Worker --> WorkflowRuntime["Co4ERunner / task_executors"] + + ChatRuntime --> Provider["ProviderFactory → ModelProvider"] + CodeRuntime --> Provider + ChatRuntime --> Tools["Built-in tools / MCP / connectors"] + CodeRuntime --> Tools + Tools --> FS["Workspace filesystem"] + Tools --> Security["PermissionGate / security / sandbox"] + + Context --> Config + Context --> Provider + Context --> Routing["RoutingService"] + Context --> MCP["MCP clients and connector cache"] + Context --> Project["Active project"] +``` + +### 3.3 Business logic đang nằm ở đâu? + +Business logic phân tán ở bốn vùng: + +- **UI:** turn orchestration, routing interaction, provider/model selection, session save, usage labels, filesystem editing, workflow CRUD và settings persistence. +- **Core runtime:** agent loop, tool dispatch, context budgeting, task/flow execution. +- **AppContext/config:** runtime object construction, mutable current project, connector lifecycle, provider factory, routing singleton. +- **Infrastructure-like modules:** JSON repositories, providers, MCP transport, REST connector, sandbox và audit. + +Không có application layer ổn định đứng giữa PySide6 và runtime/infrastructure. + +## 4. Main Application Flow + +### 4.1 Startup + +```text +python -m cowork_local + → __main__.main() + → app.run() + → AppConfig.load() + → AppContext(config) + → seed/prune defaults + → MainWindow(ctx) + → eager screens + TaskScheduler + → lazy Dashboard/Schedule/Monitoring + → QApplication.exec() +``` + +Ứng dụng hiện chạy local/admin; `LoginDialog` không nằm trên startup path. + +### 4.2 Cowork chat turn + +```text +Composer.submitted + → ChatPanel.submit() + → ChatPanel._start_turn() + → parse /skill and /agent + → snapshot messages and output directory + → UI-owned model routing + → CoworkTab.build_job() + → AgentWorker(QThread) + → attachment extraction + → CoworkTab worker job + → build provider + → AppContext.build_mcp_tools() + → load project context + → optionally create PermissionGate + → chat_agent.run_cowork() + → compose prompt/tool set + → provider.chat() + → execute external or built-in tool + → emit events + → ChatPanel._on_event() + → ChatPanel._on_finished() / _on_failed() + → render + → save history + → promote output + → record usage/notifications + → start queued turn +``` + +Điểm tốt: provider call và phần lớn task nặng chạy trong `AgentWorker`, không nằm trên UI thread. Điểm yếu: execution context chưa được snapshot đầy đủ; worker vẫn đọc mutable selection/project từ widget và `AppContext`. + +### 4.3 Agent loop + +`core/chat_agent.py::run_cowork()`: + +1. Tạo `ToolContext` từ workspace/sandbox config. +2. Ghép built-in tools với MCP/connector tools. +3. Ghép system prompt, skill, security và project context. +4. Gọi provider theo vòng lặp. +5. Compact context khi cần. +6. Xử lý tool call: + - internal plan event; + - external tool executor; + - built-in `execute_tool()`; + - command confirmation/security cho một số đường; +7. Emit stream/event về UI. +8. Cleanup scratch/intermediate output. + +`core/code_agent.py::run_code()` có loop tương tự nhưng có Plan mode và tập write-tool gate riêng. Hai runtime có common concepts nhưng chưa dùng chung một runtime kernel. + +### 4.4 Scheduled task + +```text +TaskScheduler (QTimer) + → due task + → AgentWorker + → task_executors.execute_task() + → cowork / code / co4e / flow / script branch + → runtime tương ứng + → save artifact + history + status +``` + +`core/tasks.py` vừa là repository, vừa tính lịch; `core/task_executors.py` vừa dispatch type, vừa orchestration, persistence và notification-related output. + +### 4.5 Co4E + +```text +Co4ETab + → workflow CRUD/canvas + → Co4ERunManager + → Co4ERunner + → execute graph in waves + → each agent node calls run_cowork(run_to_completion=True) +``` + +Co4E chat riêng trong UI cũng gọi `run_cowork()` nhưng dùng `enforce_rules=False` và không có `PermissionGate`, tạo policy khác Cowork chính. + +### 4.6 Folder AI và GraphRAG + +- `FolderTab` quản lý tree/editor/viewer/terminal, tự gọi routing/provider, tạo plan/edit response, ghi file sau confirm và có image generation path. +- `StructureGraphView` scan graph ở background worker, nhưng hỏi đáp graph tự build prompt, chọn provider, stream response và record usage trong widget. + +## 5. UI / Screens Map + +### 5.1 Số lượng surface chính + +- 4 top-level navigation page: Dashboard, Schedule, Workspace, Monitoring. +- 5 Workspace surface: Project Settings, Cowork, Co4E, Folder, GraphRAG. +- 8 Monitoring view khi chạy local/admin: Overview, Security Events, MCP History, Action Logs, Agent Status, Agents Admin, Tools, Icons. +- 1 floating Help Agent surface. +- 16 `QDialog` class được định nghĩa. Một số là dormant/legacy (`LoginDialog`, account flow, MCP server dialog cũ), do đó không nên dùng con số này như active product flow mà chưa xác nhận runtime navigation. + +### 5.2 Screen/component map + +| Surface | File/class hiện tại | Responsibility thực tế | Business logic trực tiếp | Direct dependencies đáng chú ý | Vấn đề / hướng refactor | +| --- | --- | --- | --- | --- | --- | +| Application shell | `app.py::MainWindow` | Navigation, lazy tabs, tray, lifecycle, scheduler, settings, notifications | Có | `AppContext`, `TaskScheduler`, hầu hết screen | Giữ shell chỉ làm navigation/lifecycle; chuyển bootstrap và app coordination sang composition/application services | +| Dashboard | `ui/dashboard_tab.py::DashboardTab` | Summary, suggestions, history/usage views | Có provider-backed suggestion jobs và direct telemetry query | usage, history, provider, worker | Tách dashboard query service và suggestion use case | +| Schedule | `ui/schedule_task_tab.py::ScheduleTaskTab` | Task list/editor/run controls | CRUD, schedule/run orchestration | `core.tasks`, scheduler, worker, providers | Tách `TaskApplicationService`; UI chỉ edit command/view state | +| Task editor | `ui/task_editor_dialog.py::TaskEditorDialog` | Create/edit task, AI assist | `_save` và AI creation logic lớn | config, providers, tasks, flows/Co4E | Tách validation, DTO mapping, AI task drafting | +| Workspace shell | `ui/workspace_tab.py::WorkspaceTab` | Project selection, history, surface switching | Mutate global project/history context | projects, history, config, child screens | Tạo immutable `WorkspaceSession`; không mutate config directory toàn cục | +| Project settings | `ui/workspace_tab.py::_build_project_tab` và các project CRUD methods | Project metadata and settings | Direct project/config persistence | project repo, filesystem | Dùng workspace use case/repository interface | +| Cowork | `ui/cowork_tab.py::CoworkTab` + `ui/chat_panel.py::ChatPanel` | Conversation UI và agent execution | Rất nhiều: routing, job build, MCP, provider, persistence, output, queue | provider factory, routing, runtime, history, tools, security, worker | Tách ConversationApplicationService, execution snapshot, presenter/event reducer | +| Co4E | `ui/co4e_tab.py::Co4ETab` | Workflow canvas/CRUD/run/chat/history | Rất nhiều | Co4E repo/runner, routing, provider, usage, runtime | Chia editor presenter, run service, chat service; dùng chung policy Cowork | +| Folder | `ui/folder_tab.py::FolderTab` | File browser/editor/viewer/terminal và AI editing | Rất nhiều filesystem/provider/routing/image logic | filesystem, provider, routing, image endpoint, worker | Tách file service, AI edit use case, terminal adapter; giữ UI diff/confirm | +| GraphRAG | `ui/structure_graph_view.py::StructureGraphView` | Scan graph và graph Q&A | Provider prompt/stream/usage trong widget | structure graph, codebase memory, provider, worker | Tách graph index/query service và Q&A use case | +| Monitoring shell | `ui/monitoring_tab.py::MonitoringTab` | 8 admin/observability views | Query/refresh orchestration | audit, usage, agents, tools, MCP | Mỗi view dùng read-only query service; giữ refresh timer ở presenter | +| Settings | `ui/settings_dialog.py::SettingsDialog` | Provider, security, sandbox, UI settings | Direct mutate/save config, model lookup, provider calls | config, providers, routing, sandbox | Dùng typed settings facade và secret store; không ghi secret trực tiếp | +| Accounts/agents/tools/skills dialogs | `ui/accounts_tab.py`, `ui/agents_admin_tab.py`, `ui/tools_admin_tab.py`, `ui/skills_dialog.py` | Admin CRUD | Direct repositories và một số AI jobs | JSON stores, provider, worker | Tách CRUD application services; xác nhận active/dormant trước migrate | +| Help agent | `ui/help_agent_widget.py::HelpAgentWidget` | Floating assistant | Direct agent/provider orchestration | provider, worker, config | Reuse conversation service với tool profile riêng | +| Connector dialogs | connector/Jira dialogs trong `ui/` | Configure/test integrations | Direct config save và network test | REST/MCP/Jira, config | Tách connector service; test connection phải chạy worker | + +### 5.3 UI-specific findings + +- Provider/model được gọi trực tiếp từ nhiều screen, không chỉ Cowork. +- Filesystem access xuất hiện trên nhiều UI module; `FolderTab` là nơi tập trung nhất nhưng Workspace, history, settings và editor dialogs cũng ghi trực tiếp. +- Routing interaction bị lặp giữa `ChatPanel._apply_routing`, `Co4ETab._apply_co4e_routing` và `FolderTab._ai_apply_routing`. +- `ChatPanel` xử lý agent event như một state machine ngầm nhưng state, rendering và persistence nằm trong cùng class. +- Hầu hết heavy provider/extraction job dùng `AgentWorker`; tuy nhiên connector connection test có synchronous REST/MCP startup từ click handler và có thể block UI. +- Reusable primitives như `AgentWorker`, provider picker, usage context, modal routing confirmation và tool/event rendering chưa được đóng thành application/adapter APIs dùng chung. + +## 6. Core Subsystems Map + +| Subsystem | Current responsibility | Files/modules chính | Public API thực tế | Dependencies/coupling | Potential boundary | +| --- | --- | --- | --- | --- | --- | +| Agent Runtime | Prompt assembly, provider loop, tool calls, context compaction, event emission | `core/chat_agent.py`, `core/code_agent.py`, `core/context_budget.py`, `core/plan.py` | `run_cowork()`, `run_code()` | config dict, providers, tools, security, filesystem, usage | Runtime kernel nhận typed request + ports, trả typed events/result | +| Qt execution bridge | Chạy synchronous job trên QThread, permission request/event | `core/worker.py`, `core/permissions.py` | `AgentWorker`, `PermissionGate` | PySide6, UI callback conventions | Platform/Qt adapter; domain không import Qt | +| Model Provider | Normalize message/tool/stream API; call Anthropic/OpenAI-compatible endpoints | `providers/*` | `ModelProvider.chat`, `ToolSpec`, `ProviderFactory.create` | config shape, usage tracking, HTTP SDKs | Provider contract trong domain; descriptors/implementations ở infrastructure | +| Model Routing | Probe/assess/route model, cache/store assessment | `core/routing/*` | `RoutingService.route`, orchestrator/prober/store | provider metadata, config, UI routing mode | Application routing service + provider catalog port | +| Workspace | Project/workspace metadata, active project, history/output paths | `core/projects.py`, `core/history.py`, `ui/workspace_tab.py`, `state.py` | dict CRUD functions + mutable `active_project_id` | config path mutation, UI, filesystem | `WorkspaceSession` snapshot + repository/filesystem ports | +| Filesystem/tools | Read/write/edit/run/install/fetch/Jira | `core/tools.py`, sandbox modules | tool schemas, `execute_tool()` | workspace path, audit, security, subprocess/network | Tool registry of handlers with capability metadata | +| MCP | Spawn/communicate with MCP servers, expose tools | `core/mcp_client.py`, `state.AppContext.build_mcp_tools`, `mcp_servers/*` | client start/call/close, external executor | config, process lifecycle, UI monitoring | `ToolSource`/`McpClient` adapters + lifecycle manager | +| Connectors | Generic REST/MCP and MS365 actions | `core/ext_connectors.py`, `core/ms365_*.py` | connector tool specs/executors | config secrets, HTTP, MCP, Graph | Connector plugin descriptor + secret reference + capability policy | +| Security | Prompt/attachment/command checks, permission, sandbox, audit | `core/agent_security*.py`, `core/security_rules.py`, `security/*`, sandbox files | multiple validators/classifiers/loggers | runtime, UI, provider, filesystem | One policy decision API; sandbox executor and audit as adapters | +| Scheduling | Store tasks, calculate due time, timer/run dispatch | `core/tasks.py`, `core/task_scheduler.py`, `core/task_executors.py` | CRUD functions, `TaskScheduler`, `execute_task` | Qt, runtime, persistence, UI | Task repository + scheduler clock + execution application service | +| Workflows | Co4E graph and separate flows | `core/co4e.py`, `core/co4e_runner.py`, `core/co4e_run_manager.py`, `core/flows.py` | dict CRUD, runner callbacks | runtime, usage, UI, tasks | Explicit workflow definitions + runner port; preserve product concepts until unified intentionally | +| Configuration | Defaults, env overrides, runtime settings | `config.py` | `AppConfig.load/save`, nested dict | almost every module | typed settings sections + config repository | +| Persistence | JSON/JSONL across config directory | projects/history/tasks/skills/agents/co4e/flows/usage/audit/routing stores | module-level CRUD returning dict | direct `Path`, shared mutable config paths | repository interfaces + common atomic JSON/JSONL primitives | +| Observability | Usage, pricing, audit, shared telemetry, monitoring | `core/usage_tracker.py`, `core/model_pricing.py`, `core/audit_log.py`, telemetry modules | global record/load/summarize functions | global identity/thread-local context/files | event sink/query services | + +## 7. Dependency Map + +### 7.1 Static hotspots + +CodeGraph cho thấy fan-out cao nhất ở: + +- `ui.chat_panel` (21 module dependencies) +- `app` (20) +- `core.task_executors` (16) +- `ui.folder_tab` (16) +- `ui.co4e_tab` (15) +- `ui.structure_graph_view` (14) +- `core.chat_agent` (13) + +Fan-in cao nhất gồm `i18n`, `ui.icons`, `config`, `core.worker`, `state` và `providers.base`. Impact analysis cho thấy thay đổi `AppConfig` có thể chạm 310 symbol, `ChatPanel` 246 symbol và `AppContext` 181 symbol; trong khi `run_cowork()` có impact hẹp hơn, 17 symbol. Điều này xác nhận runtime function là seam tốt hơn để ổn định contract so với tiếp tục thêm responsibility vào context/UI. + +### 7.2 Dependency map hiện tại + +```mermaid +flowchart LR + UI["ui/* + MainWindow"] --> State["AppContext"] + UI --> Config["AppConfig / dict"] + UI --> Runtime["chat/code/Co4E/task runtime"] + UI --> Providers["providers + routing"] + UI --> Repos["projects/history/tasks/skills/agents"] + UI --> FS["Path / filesystem"] + + State --> Config + State --> Providers + State --> Routing["routing"] + State --> MCP["MCP/connectors"] + State --> Project["active project"] + + Runtime --> Providers + Runtime --> Tools["tools"] + Runtime --> Security["security/permission"] + Runtime --> Repos + Runtime --> Usage["usage/audit"] + + Tools --> FS + Tools --> Sandbox["sandbox/subprocess"] + Tools --> MCP + Tools --> Security + + Repos --> ConfigDir["~/.cowork_local"] + Config --> ConfigDir + Usage --> ConfigDir +``` + +Vấn đề không phải là dependency tồn tại, mà là presentation có thể đi thẳng tới mọi tầng và concrete infrastructure import ngược vào runtime. Không có một direction rule có thể enforce. + +### 7.3 Circular dependencies + +| Cycle | Nguyên nhân | Hướng xử lý | +| --- | --- | --- | +| `core.model_pricing` ↔ `core.usage_tracker` | Pricing và usage vừa dùng default/format của nhau vừa cùng chịu responsibility tính cost | Tách value types/rate calculation thuần ra module domain; usage writer chỉ ghi event | +| `core.agent_security` ↔ `core.agent_security_alert` | Decision/evaluation và alert UI/notification tham chiếu ngược | Security policy trả decision/event; presentation adapter quyết định alert | + +## 8. Architecture Problems + +### 8.1 Findings ưu tiên + +| ID | File / symbol | Current problem | Why it is a problem | Suggested direction | +| --- | --- | --- | --- | --- | +| A01 | `ui/chat_panel.py::ChatPanel` | God class: UI, queue, routing, attachments, provider job, events, output, history, usage | Impact 246 symbol; khó test và thay đổi một concern mà không ảnh hưởng turn lifecycle | Conversation application service + immutable request + presenter/event reducer | +| A02 | `ui/co4e_tab.py::Co4ETab` | Workflow editor, persistence, runner, chat, routing, usage cùng class | Hai lifecycle editor/run/chat đan nhau; khó chia contributor | Tách editor controller, workflow service, run service, chat adapter | +| A03 | `ui/folder_tab.py::FolderTab` | File manager, editor, terminal, AI plan/edit, routing, image generation | Direct FS/network/provider; rủi ro data loss và UI khó test | File workspace service + AI edit use case + terminal/image adapters | +| A04 | `app.py::MainWindow` | Composition, navigation, scheduler, tray, settings, notifications, shutdown | App lifecycle và UI shell coupling | `bootstrap.py`/composition root; MainWindow chỉ shell | +| A05 | `state.py::AppContext` | Service locator và mutable global state | Widget lấy bất kỳ concrete service; background job có thể đọc state đã đổi | Explicit dependencies; immutable execution/workspace snapshot | +| A06 | `config.py::AppConfig`/`DEFAULT_CONFIG` | Untyped god config, nested dict mutate rải rác, save không atomic | Impact 310 symbol; typo/dynamic attr không bị phát hiện; corrupt file khi crash | Typed setting sections + repository + atomic writes | +| A07 | Nhiều UI modules | UI gọi provider/routing/filesystem/repository trực tiếp | Không có application boundary; duplicate workflow | Use cases trả DTO/event, UI chỉ bind/render/confirm | +| A08 | `ChatPanel._apply_routing`, `Co4ETab._apply_co4e_routing`, `FolderTab._ai_apply_routing` | Routing logic/modal flow bị lặp | Fix hoặc policy change phải sửa nhiều screen | Một routing application service; UI callback cho confirmation | +| A09 | `providers/factory.py`, `config.py`, Settings UI | Provider registry hard-code và metadata phân tán | Thêm provider phải sửa factory, defaults, labels, settings và routing metadata | Provider descriptor registry là single source of truth | +| A10 | `core/tools.py::execute_tool` | Giant `if/elif` dispatch | Handler, schema, capability, audit không co-locate; khó thêm/test tool | Tool registry: descriptor + handler + capability + tests | +| A11 | MS365/external connector executors | Action dispatch lớn, semantics read/write không chuẩn hóa | Permission behavior khác built-in tools | Chuẩn hóa connector action thành tool descriptor/capability | +| A12 | `run_cowork()` external tool path | `extra_tools` có thể execute trước built-in command gate | MCP/REST write/delete có thể không nhận cùng confirmation/security policy | Policy gateway áp dụng cho mọi tool call trước executor | +| A13 | `Co4ETab` chat path | Gọi `run_cowork(enforce_rules=False, gate=None)` | Policy khác Cowork chính và khó audit | Named policy profile; không dùng boolean bypass mơ hồ | +| A14 | `core/*security*`, `security/*` | Hai security namespace, validator/audit chồng lấn | Không rõ authoritative path; dead wrapper dễ tạo cảm giác bảo vệ giả | Security decision service duy nhất; consolidate sau characterization | +| A15 | `security/prompt_validator.py`, `security/attachment_validator.py`, `security/action_validator.py` | Không thấy active call site trong graph/source | Candidate dead code làm contributor hiểu sai | Xác nhận bằng runtime/contract tests rồi deprecate/remove ở PR riêng | +| A16 | `core/audit_log.py` và `security/audit_logger.py` | Hai event format/store path | Monitoring và sandbox có thể đọc/ghi dữ liệu không đồng nhất | Canonical audit event schema + append/query adapters | +| A17 | `core/ext_connectors.py::RestApiConnector` | Generic method gồm cả DELETE; secret/config và execution gần nhau | Không có per-action capability/approval rõ | Allow-list action descriptors; secret reference; policy gateway | +| A18 | Settings/Jira/connector dialogs | API key/token được lưu plaintext trong `config.json` | Vi phạm expectation production-grade và tăng blast radius | OS keyring/secret store; config chỉ lưu reference/non-secret | +| A19 | `core/agent_security.py` | AI-assisted guardrail fail-open theo thiết kế | Không thể coi là hard security boundary | Ghi rõ advisory vs enforced; deterministic policy phải fail-closed ở action boundary | +| A20 | sandbox config/manager | Một số option/backend field không ảnh hưởng đường chạy; direct backend “block network” chủ yếu qua proxy env | UI/config có thể overstate mức isolation | Capability matrix theo platform + integration tests + honest UI copy | +| A21 | Hầu hết JSON repositories | Ghi trực tiếp, không schema version/locking/backups dùng chung | Crash/concurrent writer gây corrupt/lost update | Common atomic store; per-repository schema/migration | +| A22 | `WorkspaceTab._load_current` + history/config path | Mutate `config._project_history_dir` toàn cục | Turn của project A hoàn tất sau khi chuyển B có thể save vào history B | Snapshot repository/path theo turn, không resolve từ global lúc finish | +| A23 | `CoworkTab.build_job`/`ChatPanel` routed fields | Worker lấy provider/model/project policy từ mutable UI/context | Concurrent/queued turn có thể dùng route hoặc policy của turn khác | Tạo immutable `ConversationExecutionRequest` trước khi start worker | +| A24 | `AppContext.active_project_id` | Current project dùng chung cho UI và background work | Race logic dù Python data access không crash | `WorkspaceSessionId` truyền explicit qua use case | +| A25 | `core/flows.py` và `core/co4e*.py` | Hai workflow model không có boundary/taxonomy rõ | Contributor không biết extend concept nào | Document semantics; adapter/common run contract trước khi cân nhắc unify | +| A26 | agents/accounts/login modules | Một số flow không reachable từ startup local/admin | Maintenance burden, docs/source drift | Mark dormant; telemetry/source graph confirmation; removal riêng, không lẫn refactor | +| A27 | Runtime/provider/store functions | Nhiều dict contract và hidden side effect | Khó type-check, mock và biết required fields | Typed DTO ở boundary; internal migration incremental | +| A28 | `core/tasks.py`, `core/task_executors.py` | Repository, scheduling math, dispatch và artifact persistence đan nhau | Scheduler test cần filesystem/Qt/runtime | Tách TaskRepository, schedule calculator, execution service | +| A29 | `core/usage_tracker.py` và global identity/context | Global identity + thread-local usage labels + file append | Khó inject/test; lifecycle implicit | Usage event sink/context explicit trong execution request | +| A30 | `i18n.py` | Gần 3.000 dòng data và global listener registry | Merge conflict cao khi nhiều screen thêm text | Tách catalogs theo feature ở phase cuối; giữ API `tr()` tương thích | + +### 8.2 Testability và hidden side effects + +- Provider implementations tự record usage; caller cũng quản lý usage context bằng thread-local. +- UI completion handler vừa render vừa persist/promote/notify. +- `AppConfig.save()` và repository CRUD ghi filesystem ngay. +- `AppContext.build_mcp_tools()` có lifecycle/cache side effect. +- Scheduler là Qt timer, clock và repository không inject được. +- Một số error path “best effort” nuốt exception; production symptom có thể chỉ xuất hiện như dữ liệu thiếu. + +### 8.3 Dead code policy + +Các module login/account/legacy MCP/security validator chỉ được coi là **candidate dormant/dead**, chưa phải kết luận xóa. Mỗi removal cần: + +1. CodeGraph caller/import check. +2. Search literal registration/config entrypoint. +3. Characterization test cho active replacement. +4. Deprecation note hoặc migration note. +5. PR removal riêng, không trộn với boundary refactor. + +## 9. Backend/Frontend vs Layered Architecture Decision + +### 9.1 Có nên gọi là backend/frontend? + +Không. Cowork Local là một desktop process: + +- PySide6 widget và agent runtime sống cùng process. +- Không có network API boundary nội bộ ổn định. +- “Backend” theo cách gọi web sẽ gom provider, runtime, filesystem và persistence vào một hộp quá rộng, không giải quyết dependency direction. +- “Frontend” dễ khiến team coi widget là nơi hợp lệ để orchestration chỉ vì không có server. + +Tên phù hợp hơn: + +1. **Presentation:** widget, dialog, view state, user confirmation. +2. **Application:** use case/coordinator cho chat, routing, workspace, tasks, workflows, connectors. +3. **Domain & Runtime:** contract, value object, deterministic policy, agent loop không phụ thuộc Qt/concrete filesystem. +4. **Infrastructure:** provider SDK, MCP/REST, filesystem/JSON, config/secrets, sandbox, telemetry. +5. **Platform/Composition:** Qt worker/timer, desktop lifecycle và dependency wiring. + +### 9.2 Dependency direction + +```mermaid +flowchart TD + Presentation["Presentation / PySide6"] --> Application["Application services"] + Application --> Domain["Domain & runtime contracts"] + Infrastructure["Infrastructure adapters"] --> Domain + Qt["Qt platform adapters"] --> Application + Composition["Desktop composition root"] --> Presentation + Composition --> Application + Composition --> Infrastructure + Composition --> Qt +``` + +Rules: + +- Domain/runtime contract không import PySide6, concrete provider, `AppConfig` hoặc `Path` repository implementation. +- Application không lấy dependency từ global `AppContext`; dependency được inject qua constructor/factory. +- Presentation không gọi provider, filesystem repository hoặc MCP client trực tiếp. +- Infrastructure implement port từ domain/application; không import widget. +- Chỉ composition root biết cả concrete UI lẫn concrete infrastructure. +- Trong migration period, adapter tương thích có thể wrap module-level API cũ; dependency rule áp dụng trước cho code mới, sau đó siết dần. + +## 10. Target Architecture + +### 10.1 Boundary mục tiêu + +| Layer | Responsibility | Không nên chứa | +| --- | --- | --- | +| Presentation | Render state/event, collect input, show confirmation, navigation | Provider calls, path resolution, JSON save, tool orchestration | +| Application | Orchestrate one use case, transaction/lifecycle, map DTO, request policy decision | Qt widget code, SDK-specific response, raw config dict mutation | +| Domain & Runtime | Agent events/requests, provider/tool contracts, task/workflow/workspace types, deterministic policies | Filesystem/network/UI/global state | +| Infrastructure | Provider/MCP/REST clients, JSON repositories, config/secret stores, filesystem, sandbox, audit/usage sinks | Product navigation or screen state | +| Platform/Composition | QApplication, QThread/QTimer adapters, lifecycle, DI wiring | Business rules và feature CRUD | + +### 10.2 Core contracts tối thiểu + +Tránh tạo framework DI hoặc repository abstraction cho mọi file. Chỉ introduce contract tại seam đang có nhiều caller/concrete implementation: + +- `ModelProvider`, `ProviderRegistry`, `ProviderDescriptor` +- `RoutingService` request/result +- `ConversationExecutionRequest`, `AgentEvent`, `AgentResult` +- `ToolDescriptor`, `ToolCapability`, `ToolExecutor`, `ToolPolicy` +- `WorkspaceSession`, `WorkspaceRepository`, `ConversationRepository` +- `TaskRepository`, `TaskExecutionService`, `Clock` +- `WorkflowDefinitionRepository`, `WorkflowRunner` +- `ConfigRepository`, typed setting sections, `SecretStore` +- `AuditSink`, `UsageSink` +- `SandboxExecutor` + +### 10.3 Không over-engineer + +- Không dựng event bus toàn ứng dụng. +- Không bắt mọi class có interface. +- Không đổi PySide6 sang web framework. +- Không rewrite đồng thời Cowork, Co4E, Folder và scheduler. +- Không unify Flow/Co4E trước khi semantics được ghi rõ và có contract tests. +- Không tạo microservice hoặc IPC chỉ để có “backend”. +- Ưu tiên dataclass/Protocol nhỏ, constructor injection và adapter trực tiếp. + +## 11. Target Folder Structure + +Tên folder cuối cùng có thể điều chỉnh trong R01 ADR, nhưng dependency shape nên như sau: + +```text +cowork_local/ +├── __main__.py +├── bootstrap.py +├── presentation/ +│ ├── shell/ +│ ├── dashboard/ +│ ├── scheduling/ +│ ├── workspace/ +│ ├── chat/ +│ ├── co4e/ +│ ├── folder/ +│ ├── graph/ +│ ├── monitoring/ +│ ├── settings/ +│ └── shared/ +├── application/ +│ ├── conversations/ +│ ├── model_routing/ +│ ├── workspaces/ +│ ├── scheduling/ +│ ├── workflows/ +│ ├── connectors/ +│ ├── monitoring/ +│ └── settings/ +├── domain/ +│ ├── agents/ +│ ├── models/ +│ ├── tools/ +│ ├── workspaces/ +│ ├── tasks/ +│ ├── workflows/ +│ └── security/ +├── infrastructure/ +│ ├── providers/ +│ ├── mcp/ +│ ├── connectors/ +│ ├── persistence/ +│ │ └── json/ +│ ├── filesystem/ +│ ├── config/ +│ ├── secrets/ +│ ├── sandbox/ +│ ├── telemetry/ +│ └── documents/ +└── platform/ + └── qt/ +``` + +Đây là target state, không phải instruction move tree ngay. Trình tự đúng là: + +1. Tạo contract/service tại vị trí ít disruptive. +2. Wrap implementation hiện tại. +3. Migrate caller. +4. Khi import graph đã sạch mới move module trong PR mechanical riêng. + +## 12. Refactor Strategy + +### 12.1 Strategy A — theo từng screen + +Ưu điểm: + +- Scope nhìn thấy rõ, dễ demo. +- Team UI có thể ownership theo screen. +- Giảm merge conflict giữa các file UI lớn nếu làm tuần tự. + +Nhược điểm với repository này: + +- Chat, Co4E, Folder và Graph đều lặp routing/provider/usage; refactor riêng từng screen sẽ tạo nhiều service gần giống nhau. +- Screen phụ thuộc trực tiếp vào mutable `AppContext`, config và repository; chưa có foundation thì chỉ “move code” chứ chưa đổi boundary. +- Security/tool policy là cross-screen và scheduled runtime, không thể giải quyết screen-by-screen. + +Kết luận: dùng cho phase UI migration, không dùng làm strategy tổng thể. + +### 12.2 Strategy B — theo từng function/class + +Ưu điểm: + +- PR nhỏ. +- Review dễ nếu contract đã rõ. +- Hữu ích để extract pure function và test. + +Nhược điểm: + +- Dễ tối ưu cục bộ trong God class. +- Không giải quyết direction/capability ownership. +- Nhiều contributor có thể tạo abstraction không tương thích. + +Kết luận: dùng làm kích thước task/PR bên trong EPIC, không dùng để định nghĩa roadmap. + +### 12.3 Strategy C — theo subsystem/capability + +Ưu điểm: + +- Khớp với coupling thực tế: provider/routing, workspace/history, tool/security, scheduling/workflow là cross-screen. +- Có thể định nghĩa contract test một lần rồi migrate từng caller. +- Ownership theo EPIC giảm conflict. +- Cho phép parallel work sau khi R01 chốt boundary và contract names. + +Nhược điểm: + +- Cần kỷ luật để không biến thành rewrite cả subsystem. +- Một số EPIC có dependency, không thể mở tất cả cùng lúc. +- Product progress ít “nhìn thấy” trong phase foundation. + +Kết luận: đây là strategy chính. + +### 12.4 Recommended approach + +```text +EPIC / Subsystem + → Module boundary + → Class / Protocol / Adapter + → Function-level migration task + → One caller + tests per PR +``` + +Áp dụng hybrid: + +- subsystem là đơn vị kiến trúc và ownership; +- class/function là đơn vị implement/review; +- screen là đơn vị migrate UI sau khi application service tương ứng sẵn sàng. + +Mỗi task phải có input, work, output và validation; không có task “refactor backend” hoặc “clean architecture”. + +## 13. Refactor EPICs + +| EPIC | Tên | Boundary chính | Giá trị kiến trúc | +| --- | --- | --- | --- | +| R01 | Architecture Foundation & Characterization | Dependency rules, baseline, contracts tối thiểu | Tạo safety net và ngôn ngữ chung trước khi nhiều team sửa | +| R02 | Configuration, Secrets & Persistence | Typed settings, atomic storage, secret references | Giảm global dict/direct write và bảo vệ credential | +| R03 | Model Providers & Routing | Provider catalog/factory/routing use case | Một đường mở rộng provider và một routing flow | +| R04 | Agent Runtime & Conversation Application Service | Immutable request, typed events, runtime ports | Tách turn lifecycle khỏi widget | +| R05 | Tool, MCP & Connector Policy | Tool registry, capability, policy gateway | Một security/approval path cho mọi tool | +| R06 | Workspace, Filesystem & History Isolation | Workspace session/repository/path boundary | Loại bỏ cross-project mutable path/state | +| R07 | Scheduling & Workflow Runtime | Task repository/clock/executor và workflow contracts | Tách Qt timer, persistence và runtime dispatch | +| R08 | UI/Application Separation | Screen presenter/controller/use-case integration | Thu nhỏ God widgets theo từng screen | +| R09 | Security Runtime, Sandbox & Observability | Deterministic policy, sandbox truth, audit/usage | Policy rõ, event schema thống nhất, monitoring đáng tin | +| R10 | Testing, Packaging & Contributor Experience | Test pyramid, dependency manifest, CI, docs | Contributor có thể thay đổi một capability mà không hiểu toàn repo | + +## 14. Tasks under each EPIC + +### R01 — Architecture Foundation & Characterization + +**Objective** + +Chốt dependency direction, tạo safety net cho hành vi hiện tại và cung cấp contract vocabulary tối thiểu trước khi migrate runtime hoặc UI. + +**Current Problems** + +- Không có rule ngăn UI import concrete infrastructure. +- Các module “core” không có ownership rõ. +- Test hiện tại tập trung gần như toàn bộ vào routing. +- Candidate dead/dormant code chưa có quy trình xác nhận. + +**Scope** + +Architecture Decision Record, import graph guardrail, fake provider/tool/repository test doubles, characterization tests cho các seam quan trọng. + +**Affected modules/files** + +`docs/`, `tests/`, package init mới cho contract nếu cần; đọc `app.py`, `state.py`, `config.py`, `core/chat_agent.py`, `providers/*`, `core/tools.py` nhưng chưa migrate production caller. + +**What will be changed** + +- Ghi dependency rules và module ownership. +- Tạo test fixtures dùng chung. +- Characterize event ordering, provider construction, config/persistence shape và tool dispatch hiện tại. +- Tạo allow-list tạm thời cho violation hiện có để không block mọi PR. + +**What will NOT be changed** + +- Không move toàn bộ package. +- Không thay runtime behavior. +- Không xóa candidate dead code. +- Không introduce DI framework. + +**Dependencies on other EPICs:** Không. + +**Risk:** Thấp. Rủi ro chính là test khóa nhầm bug; mỗi characterization phải ghi rõ “behavior to preserve” hay “known defect to replace”. + +**Expected outcome** + +Team có một baseline executable và biết dependency mới nào bị cấm. + +**How to verify completion** + +- Baseline test chạy được không cần network/credential. +- Architecture check báo violation mới, nhưng allow-list rõ violation cũ. +- ADR được link từ `START_CONTRIBUTING.md`. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R01-T01 Current architecture ADR | Source map trong tài liệu này | Viết dependency rules, composition rule, naming và exception process | `docs/architecture/` ADR + module ownership table | Review bởi Cowork Team và FSG AI Core Team | +| R01-T02 Runtime test doubles | `ModelProvider`, `ToolSpec`, agent event callback | Tạo deterministic fake provider/tool executor/event collector | Fixtures không import PySide6/network | Unit test chạy dưới 1 giây và mô phỏng text + tool-call turn | +| R01-T03 Cowork runtime characterization | `run_cowork()` hiện tại | Test text-only, one tool call, failure, context compaction signal và cleanup contract | Event sequence baseline | Test không chạm user config/home và pass ổn định | +| R01-T04 Provider/config/store characterization | Provider factory, `AppConfig`, representative repositories | Test registry mapping, config round-trip, missing/corrupt file và current serialization shape | Contract tests quanh public behavior hiện tại | Existing + new tests pass trên fresh temp dir | +| R01-T05 Import boundary guard | Current CodeGraph/import graph | Thêm static import rule với allow-list debt; cấm code mới presentation → concrete infrastructure | CI architecture check | Một fixture violation mới làm check fail; existing debt được report | +| R01-T06 Dormant-code inventory | Login/account/legacy MCP/security validators | Xác minh entrypoint, dynamic registration, config flag và caller; gắn status active/dormant/unknown | `docs/architecture/dormant-code.md` | Mỗi item có evidence và owner; chưa xóa source | + +### R02 — Configuration, Secrets & Persistence + +**Objective** + +Thay global untyped config/direct JSON writes bằng typed settings facade, atomic persistence primitives và secret references, trong khi giữ tương thích file hiện tại. + +**Current Problems** + +- `AppConfig` là nested dict được mutate từ nhiều UI/core module. +- Save config và phần lớn repository không atomic. +- API keys/tokens được lưu plaintext trong config. +- Không có schema version/migration/locking policy dùng chung. +- Dynamic attributes như `_data`/`_agent_security` có thể được gán nhưng không tạo hiệu lực rõ ràng. + +**Scope** + +Config repository, typed view/facade, atomic JSON/JSONL helpers, secret store contract/adapters, migration policy. + +**Affected modules/files** + +`config.py`, `state.py`, Settings/Jira/connector dialogs, `core/projects.py`, `core/history.py`, `core/tasks.py`, `core/skills.py`, agent/Co4E/flow repositories, routing store làm reference. + +**What will be changed** + +- Common atomic writer với fsync/temp/replace và recovery policy. +- Typed settings sections vẫn đọc được schema JSON hiện tại. +- Secret values chuyển dần sang OS credential store; config lưu reference. +- Repository có explicit path/schema/error behavior. + +**What will NOT be changed** + +- Không đổi tất cả repository trong một PR. +- Không đổi defaults hoặc product settings ngoài migration cần thiết. +- Không yêu cầu database. + +**Dependencies on other EPICs:** R01. + +**Risk:** Trung bình; config migration có thể ảnh hưởng startup. Phải support rollback và preserve unknown keys. + +**Expected outcome** + +Config/persistence có behavior nhất quán, credential không còn mặc định nằm trong plaintext JSON, caller không cần biết file layout. + +**How to verify completion** + +- Round-trip giữ unknown key và current user settings. +- Simulated interrupted write không phá file cũ. +- Upgrade/downgrade fixture có documented behavior. +- Secret không xuất hiện trong config, log hoặc test snapshot. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R02-T01 Atomic JSON primitive | Atomic pattern trong routing AssessmentStore | Extract `AtomicJsonFile`/equivalent với temp, flush, replace, corrupt-file strategy | Infrastructure persistence helper | Fault-injection tests trước/giữa replace | +| R02-T02 Migrate AppConfig storage only | Current `AppConfig.load/save` | Dùng atomic primitive nhưng giữ public dict API/schema | Safer config writes, không đổi caller | Golden config round-trip + startup smoke test | +| R02-T03 Typed settings facade | `DEFAULT_CONFIG` sections | Tạo typed views cho provider, routing, workspace, security, sandbox, UI | Validated accessors + legacy adapter | Invalid value fallback/error tests; unknown key preserved | +| R02-T04 Config repository/composition | Root construction trong `app.run()` | Inject config repository và bỏ path resolution khỏi business caller mới | Explicit config bootstrap seam | Temp-config integration test | +| R02-T05 SecretStore contract | Provider/Jira/connector/MS365 secrets | Define secret reference API; implement OS keyring adapter + explicit fallback policy | `SecretStore` port và adapter | Store/get/delete tests; no plaintext assertion | +| R02-T06 Migrate one credential vertical slice | Một provider API key | Migrate read/write UI + factory qua secret reference; compatibility import một lần | Proven migration pattern | Existing credential upgrade, new save, missing key tests | +| R02-T07 Repository schema policy | Existing JSON stores | Chốt envelope/version/backups/locking conventions; migrate một low-risk store | Repository template/reference implementation | Concurrent/read-corrupt/version tests | + +### R03 — Model Providers & Routing + +**Objective** + +Tạo một catalog duy nhất cho provider/model capabilities và một application flow duy nhất cho routing, để thêm provider không phải sửa nhiều screen/config branch. + +**Current Problems** + +- Registry mapping, labels, defaults và UI metadata phân tán. +- OpenAI-compatible variants được phân biệt bằng config convention. +- Routing confirmation và fallback logic bị lặp ở ba UI lớn. +- Provider implementation tự gắn usage side effect. + +**Scope** + +Provider descriptor/registry/factory, provider config validation, routing request/result coordinator, provider contract tests. + +**Affected modules/files** + +`providers/*`, `core/routing/*`, provider sections trong `config.py`, `state.py`, `ui/settings_dialog.py`, `ui/chat_panel.py`, `ui/co4e_tab.py`, `ui/folder_tab.py`, `ui/structure_graph_view.py`. + +**What will be changed** + +- `ProviderDescriptor` là source of truth cho id, label, implementation kind, required settings và capabilities. +- Factory nhận validated provider config. +- Routing use case trả typed decision/fallback/confirmation request. +- UI chỉ render confirmation và lựa chọn, không tự tái hiện policy. + +**What will NOT be changed** + +- Không đổi API endpoint/model semantics của provider trong phase đầu. +- Không thêm provider mới chỉ để chứng minh architecture. +- Không gộp routing heuristic nếu test hiện tại chưa bảo vệ. + +**Dependencies on other EPICs:** R01; dùng R02 typed settings/secret contract khi sẵn sàng. + +**Risk:** Trung bình do mọi agent path cần provider. Giữ `ProviderFactory.create()` compatibility adapter tới khi caller cuối migrate. + +**Expected outcome** + +Thêm provider chủ yếu bằng một descriptor + implementation + contract tests; routing giống nhau giữa Cowork, Co4E, Folder và scheduled work. + +**How to verify completion** + +- Tất cả provider chạy chung contract suite. +- Registry không có duplicate id/model alias. +- Ba UI không còn private copy của routing policy. +- Offline fake routing tests cover Off/Auto/Manual/fallback. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R03-T01 Provider contract suite | `providers/base.py`, current implementations | Định nghĩa expected chat/tool/stream/error/cancel behavior | Parametrized provider contract tests | Fake transport, không network | +| R03-T02 Provider descriptor registry | Factory registry, labels, defaults | Co-locate metadata/capabilities/config requirements; giữ factory façade | Single provider catalog | Registry completeness/duplicate tests | +| R03-T03 Validated provider construction | Raw config dict | Map typed settings + secret reference vào implementation config | Explicit factory request/error types | Missing/invalid secret/URL/model tests | +| R03-T04 Migrate Settings provider catalog | Provider/model UI listing | Render từ registry; không hard-code provider label/requirements | Settings adapter using registry | Headless presenter/model tests | +| R03-T05 Routing application service | Existing `RoutingService` + three UI copies | Tạo request/result, policy cho Off/Auto/Manual/fallback; confirmation qua port/callback | One orchestration path | Existing routing tests + UI-free coordinator tests | +| R03-T06 Migrate routing callers incrementally | Cowork, Folder, Co4E, Graph/task callers | Mỗi PR migrate một caller và xóa copy tương ứng | No duplicated routing branches | Per-screen smoke/characterization tests | +| R03-T07 Decouple usage from provider | Provider-side `usage_tracker.record` | Inject usage sink/context hoặc emit usage event | Provider không phụ thuộc global usage module | Provider contract captures exactly one usage event | + +### R04 — Agent Runtime & Conversation Application Service + +**Objective** + +Biến một conversation turn thành use case có request/result/event rõ, không phụ thuộc mutable widget/AppContext, và giữ agent loop có thể chạy từ UI, task hoặc workflow. + +**Current Problems** + +- Turn setup/finish nằm trong `ChatPanel`/`CoworkTab`. +- Worker đọc routed provider/model/project policy từ mutable state. +- Event là dict convention, reducer/state transition ngầm trong UI. +- Chat/code loops có concepts lặp nhưng policy không hoàn toàn giống nhau. + +**Scope** + +Execution snapshot, typed events, conversation service, runtime dependency ports, migration Cowork/scheduled/help paths. + +**Affected modules/files** + +`ui/chat_panel.py`, `ui/cowork_tab.py`, `core/chat_agent.py`, `core/code_agent.py`, `core/worker.py`, `core/context_budget.py`, `core/plan.py`, `core/task_executors.py`, `ui/help_agent_widget.py`. + +**What will be changed** + +- Snapshot provider/model/workspace/history/output/security/tool profile trước khi worker chạy. +- Runtime nhận explicit dependencies. +- Application service quản lý start/cancel/result/persist transaction. +- Event schema typed nhưng có compatibility adapter cho dict UI. + +**What will NOT be changed** + +- Không viết lại loop hoặc prompt trong một lần. +- Không đổi UX streaming/queue/confirmation. +- Không bắt chat và code dùng chung toàn bộ behavior. + +**Dependencies on other EPICs:** R01, R03, R05, R06; R02 cho persistence/config adapters. + +**Risk:** Cao; đây là critical path. Migrate một entrypoint mỗi PR và dùng golden event tests. + +**Expected outcome** + +Cowork widget chỉ tạo request, render event và gửi user decision; cùng service có thể được gọi từ scheduler/workflow mà không import UI. + +**How to verify completion** + +- Concurrent turns giữ đúng provider/project/history snapshot. +- Cancel/error/tool/permission event parity với baseline. +- Runtime unit tests không import PySide6. +- No direct provider/MCP/history construction trong migrated widget. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R04-T01 Execution request snapshot | Current `_start_turn`/`build_job` inputs | Define immutable request gồm messages, provider route, workspace session, output, policy/tool profile | `ConversationExecutionRequest` | Mutation-after-start concurrency tests | +| R04-T02 Typed agent events | Dict events từ chat/code runtime | Define event union/value types + legacy dict adapter | Stable event contract | Golden sequence tests và exhaustive reducer test | +| R04-T03 Runtime ports | Provider, tool executor, policy, usage/audit dependencies | Thay global/concrete lookup từng dependency một bằng injected runtime environment | `AgentRuntimeEnvironment` nhỏ | Fake-only runtime tests | +| R04-T04 Conversation application service | Runtime + repositories + output lifecycle | Orchestrate execute/cancel/persist/promote; return events/result | UI-independent service | Success/failure/cancel transaction tests | +| R04-T05 Migrate Cowork turn | `ChatPanel` + `CoworkTab` current path | Migrate một full turn; giữ compatibility event rendering | Cowork uses service | Manual smoke + headless service tests | +| R04-T06 Migrate scheduled/help callers | `task_executors`, HelpAgent | Mỗi caller tạo request/profile thay vì duplicate job setup | Shared runtime entrypoint | Task/help characterization tests | +| R04-T07 Evaluate chat/code kernel extraction | Characterized loops | Chỉ extract truly identical loop mechanics; giữ prompt/policy strategy riêng | Minimal shared kernel hoặc ADR “do not merge” | Contract parity; line movement không phải success metric | + +### R05 — Tool, MCP & Connector Policy + +**Objective** + +Đảm bảo mọi built-in, MCP, REST và MS365 action đi qua cùng capability classification, approval/security decision, audit và executor lifecycle. + +**Current Problems** + +- `execute_tool()` và connector executors dùng giant dispatch. +- Extra MCP/connector tool có thể bypass built-in command/write gate. +- Generic REST connector cho phép method nguy hiểm mà không có capability model. +- MCP client construction/cache/shutdown nằm trong `AppContext`. +- Tool metadata không nói rõ read/write/execute/network/destructive. + +**Scope** + +Tool descriptors/registry, capability model, policy gateway, MCP lifecycle manager, connector descriptors and tests. + +**Affected modules/files** + +`core/tools.py`, `core/chat_agent.py`, `core/code_agent.py`, `core/mcp_client.py`, `core/ext_connectors.py`, `core/ms365_tools.py`, `core/ms365_local.py`, `mcp_servers/ms365_server.py`, `state.py`, Monitoring tool/MCP UI. + +**What will be changed** + +- Tool schema, handler, source và effects/capabilities được đăng ký cùng nhau. +- Một gateway quyết định allow/confirm/deny trước mọi executor. +- MCP/connectors expose descriptors, không chỉ raw schema/callback. +- Lifecycle tách khỏi service locator. + +**What will NOT be changed** + +- Không thay protocol MCP. +- Không redesign connector UX trước khi policy/API ổn định. +- Không mặc định deny toàn bộ existing tools khi chưa có migration mapping. + +**Dependencies on other EPICs:** R01, R02; phối hợp R09 về policy/audit semantics. + +**Risk:** Cao vì sai classification có thể block workflow hoặc cho phép action nguy hiểm. Unknown capability phải có explicit migration policy. + +**Expected outcome** + +Tool mới phải khai báo effects và tự động nhận cùng permission/audit path; MCP/REST không còn là ngoại lệ. + +**How to verify completion** + +- Contract test fail nếu tool thiếu capability. +- Built-in/MCP/REST/MS365 read và write action có expected decision matrix. +- Unknown/destructive action không execute silently. +- MCP clients close deterministically. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R05-T01 Tool/action inventory | Built-in, MCP, REST, MS365 schemas | Lập matrix filesystem/network/process/read/write/delete/install | Reviewed capability catalog | Security/product sign-off | +| R05-T02 ToolDescriptor + registry | `ToolSpec` và `execute_tool` branches | Wrap từng handler với descriptor; compatibility dispatcher giữ API cũ | Registry-based lookup | Existing tool behavior + duplicate/missing handler tests | +| R05-T03 Unified policy gateway | PermissionGate, command classifier, write sets | Define decision input/output và gọi trước executor bất kể source | One enforcement point | Table-driven allow/confirm/deny tests | +| R05-T04 External tool adapter | `extra_tools` callback path | Convert MCP/connector schemas thành descriptors và route qua gateway | No bypass branch in agent loop | Fake destructive MCP tool cannot execute without decision | +| R05-T05 MCP lifecycle service | `AppContext.build_mcp_tools` cache/start/close | Extract source discovery, client ownership, health and shutdown | `McpToolSourceManager` | Start/failure/restart/close tests with fake process | +| R05-T06 REST connector hardening | Generic method/path config | Require action allow-list, capability, timeout, response limit và secret reference | Descriptor-driven REST tools | DELETE/write/host/timeout policy tests | +| R05-T07 MS365 migration | Local/MCP MS365 executors | Map actions to shared capabilities/policy/audit | Same behavior across local/MCP modes | Contract tests for representative read/write actions | + +### R06 — Workspace, Filesystem & History Isolation + +**Objective** + +Biến project/workspace context thành immutable value truyền explicit theo use case, đồng thời tập trung path resolution, history và output lifecycle. + +**Current Problems** + +- `active_project_id` và `_project_history_dir` là mutable global state. +- Completion callback có thể save vào project khác sau context switch. +- Filesystem access/path rules rải ở UI, runtime và repositories. +- Repository trả mutable dict, không có typed identity/version. + +**Scope** + +Workspace session, project/history repositories, output/scratch manager, filesystem port và migration Workspace/Cowork callers. + +**Affected modules/files** + +`state.py`, `config.py`, `core/projects.py`, `core/history.py`, `ui/workspace_tab.py`, `ui/chat_panel.py`, `ui/cowork_tab.py`, `ui/folder_tab.py`, output/doc extraction helpers. + +**What will be changed** + +- `WorkspaceSession` chứa project id/root/history/output/policy snapshot. +- Repository nhận explicit project/session/path. +- UI current selection chỉ là presentation state; background request giữ snapshot riêng. +- Filesystem mutation dùng service với path containment/atomic save. + +**What will NOT be changed** + +- Không đổi workspace layout trên disk trong phase đầu. +- Không rewrite file editor. +- Không đồng bộ cloud. + +**Dependencies on other EPICs:** R01, R02; cung cấp input cho R04/R07/R08. + +**Risk:** Trung bình-cao do path/data migration. Dùng fixtures với nhiều project và không chạm user home. + +**Expected outcome** + +Turn/task/workflow luôn đọc/ghi đúng project dù UI đổi selection; path/security rule có một nơi. + +**How to verify completion** + +- Multi-project concurrency regression tests. +- History/output path không resolve từ global config sau start. +- Project switch không đổi running request. +- Path traversal/atomic save tests. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R06-T01 WorkspaceSession value | Project dict + config-derived paths/policies | Define immutable typed snapshot và factory | Explicit session object | Equality/validation/snapshot tests | +| R06-T02 Explicit history repository | `core/history.py`, dynamic history dir | Repository methods nhận project/session hoặc bound repository | No global history path mutation | A/B project save/load regression | +| R06-T03 Project repository boundary | `core/projects.py` | Separate DTO/validation/storage; preserve disk schema | `ProjectRepository` adapter | CRUD/missing/corrupt/unknown-key tests | +| R06-T04 Output/scratch lifecycle | Per-turn output/promotion/cleanup code | Centralize allocate/promote/cleanup by execution id | `ExecutionWorkspace` service | Failure/cancel/duplicate-name tests | +| R06-T05 WorkspaceTab migration | `_load_current` and child propagation | Selection creates/binds session; remove config path mutation | UI emits workspace session change | Switch while fake turn runs | +| R06-T06 Cowork/history migration | Turn start/finish path | Bind repository/output to snapshot before worker start | Correct project isolation | Concurrent two-project integration test | +| R06-T07 Filesystem service for Folder | Direct `Path` read/write/rename/delete | Introduce bounded FS service and migrate one operation group per PR | UI no longer resolves raw project paths | Containment, encoding, atomic-write tests | + +### R07 — Scheduling & Workflow Runtime + +**Objective** + +Tách task persistence, schedule calculation, Qt timing, task execution và workflow running thành các boundary có thể test độc lập. + +**Current Problems** + +- `core/tasks.py` trộn repository và scheduling math. +- `TaskScheduler` phụ thuộc QTimer/current clock/concrete repository. +- `core/task_executors.py` là giant type dispatch + runtime/persistence/artifact orchestration. +- Co4E và Flow là hai workflow concept không có shared execution contract. +- Co4E UI sở hữu nhiều run lifecycle. + +**Scope** + +Task domain/repository, schedule calculator/clock, task execution service, workflow definitions/runners, Qt scheduler adapter. + +**Affected modules/files** + +`core/tasks.py`, `core/task_scheduler.py`, `core/task_executors.py`, `core/co4e.py`, `core/co4e_runner.py`, `core/co4e_run_manager.py`, `core/flows.py`, `ui/schedule_task_tab.py`, `ui/task_editor_dialog.py`, `ui/co4e_tab.py`. + +**What will be changed** + +- Pure schedule calculation và injectable clock. +- Typed task execution request/result. +- Executor registry thay giant task type branch. +- Workflow runners emit typed events và dùng application runtime service. +- Document rõ khác biệt Flow/Co4E trước khi reuse abstraction. + +**What will NOT be changed** + +- Không merge Flow và Co4E model một cách cưỡng ép. +- Không thay schedule semantics/UX. +- Không thay format task/workflow đồng thời với runtime migration. + +**Dependencies on other EPICs:** R01, R04, R06; R02 repositories; R05 tool policy. + +**Risk:** Cao vì background automation và artifact persistence. Cần fake clock và idempotency tests. + +**Expected outcome** + +Scheduler có thể test không Qt/wall clock; task type mới đăng ký qua executor; workflow run không cần UI class. + +**How to verify completion** + +- Deterministic schedule tests quanh timezone/restart/missed run. +- Duplicate tick không chạy cùng task hai lần. +- Task result/artifact/history behavior parity. +- Co4E run headless với fake provider. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R07-T01 Task model/repository split | `core/tasks.py` | Extract typed task + repository adapter, giữ serialization | Domain model + repo | Golden current task files | +| R07-T02 Schedule calculator + Clock | Due-time logic | Extract pure function/service, inject timezone-aware clock | Deterministic scheduling core | Boundary/timezone/restart test matrix | +| R07-T03 Task executor registry | Branches trong `task_executors` | Mỗi task kind có descriptor/executor; shared artifact/result wrapper | Extensible registry | Unknown/each kind/duplicate id tests | +| R07-T04 TaskExecutionService | Scheduler → worker → executor flow | Orchestrate claim/run/status/result/idempotency | UI-free use case | Crash/failure/retry/double-tick tests | +| R07-T05 Qt scheduler adapter | QTimer scheduler | Adapter chỉ poll service và emit presentation event | Thin platform timer | Fake clock + Qt smoke test | +| R07-T06 Workflow taxonomy/contract | Flow và Co4E models | Document semantics; define smallest common run request/event/result nếu thực sự chung | Explicit workflow ports/ADR | Both runners satisfy agreed contract or exceptions documented | +| R07-T07 Co4E runner migration | Runner/run manager callbacks | Dùng conversation service, typed event, execution snapshot | Headless runner | Multi-node/failure/cancel/usage tests | +| R07-T08 Flow runner migration | `core/flows.py` scheduled path | Implement shared task/workflow execution contract | Consistent result/artifact handling | Flow fixtures + scheduled integration | + +### R08 — UI/Application Separation + +**Objective** + +Thu nhỏ PySide6 screen thành view/presenter/controller, migrate theo từng screen sau khi application services tương ứng sẵn sàng. + +**Current Problems** + +- God widgets chứa orchestration/persistence/provider/filesystem. +- UI state và domain state không phân biệt. +- Modal confirmation, worker wiring và usage/provider helpers bị lặp. +- Một số network test chạy sync trên UI thread. + +**Scope** + +Presentation state, controller/presenter, Qt worker adapters, từng screen migration, cuối cùng MainWindow composition. + +**Affected modules/files** + +Toàn bộ `ui/`, `app.py`, `core/worker.py`; application services từ R03–R07/R09. + +**What will be changed** + +- Screen nhận narrow use-case interfaces. +- View state/event reducer có unit test. +- Blocking work luôn qua Qt execution adapter. +- Shared visual widgets chỉ chứa presentation concern. + +**What will NOT be changed** + +- Không redesign visual/UX toàn diện. +- Không migrate nhiều God screen trong cùng PR. +- Không tạo một “BaseViewModel” khổng lồ. + +**Dependencies on other EPICs:** Progressive; mỗi screen chỉ bắt đầu khi service của nó sẵn sàng. MainWindow làm cuối. + +**Risk:** Trung bình-cao do signal/lifecycle regression. Giữ screenshot/manual smoke checklist và headless presenter tests. + +**Expected outcome** + +Screen có responsibility rõ, không gọi concrete provider/MCP/repository/filesystem; contributor UI không cần hiểu agent loop. + +**How to verify completion** + +- Import rule sạch cho migrated screen. +- Presenter/controller test không tạo real window/network/files. +- UI thread responsiveness smoke tests. +- Signal connection/lifecycle không leak sau close/switch. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R08-T01 Presentation conventions | Current signal/worker/event patterns | Define view-state, command, effect và Qt adapter conventions; sample một small dialog | UI contribution pattern | ADR + sample tests, không base framework | +| R08-T02 Settings screen | R02/R03/R05 settings services | Migrate provider/config/connector save/test; async connection test | Thin Settings/connector dialogs | Save/cancel/test-connection presenter tests | +| R08-T03 Workspace/project/history shell | R06 services | Migrate project selection/history binding | Session-driven WorkspaceTab | A/B switch, empty/deleted project tests | +| R08-T04 Cowork/Chat | R03–R06/R09 services | Move turn lifecycle/event state/persistence khỏi widget | Chat view + presenter/controller | Baseline conversation/manual streaming checklist | +| R08-T05 Schedule/Task editor | R07 services | Move CRUD/validation/run/drafting orchestration | Task list/editor presentation only | Fake clock/repo + dialog validation tests | +| R08-T06 Co4E | R04/R07 services | Split editor, run monitor và chat controllers | Smaller independent components | Headless workflow and UI signal tests | +| R08-T07 Folder | R03/R06 services | Migrate FS and AI edit/image/terminal actions by operation group | Folder UI renders file/diff/result | Temp workspace + cancel/failure tests | +| R08-T08 GraphRAG | Graph index/query application service | Move scan/query/provider prompt/use tracking | Thin graph view | Fake graph/provider tests | +| R08-T09 Dashboard/Monitoring | R09 query services | Migrate telemetry/audit/agent/tool queries và suggestions | Read models + views | Empty/corrupt/large dataset tests | +| R08-T10 Help/admin/skills dialogs | Shared conversation/CRUD services | Migrate active small surfaces; mark dormant ones | Consistent small controllers | Reachability and CRUD tests | +| R08-T11 MainWindow/composition | All migrated screens | Move construction/lifecycle wiring to bootstrap; shell owns nav/tray only | Thin `MainWindow` + composition root | Startup/shutdown/lazy-tab/tray smoke tests | + +### R09 — Security Runtime, Sandbox & Observability + +**Objective** + +Phân biệt hard deterministic enforcement với advisory AI checks, thống nhất sandbox/audit/usage semantics và làm Monitoring phản ánh đúng capability thực tế. + +**Current Problems** + +- Security logic phân tán giữa `core/` và `security/`. +- AI security fail-open nhưng dễ bị hiểu như hard boundary. +- Sandbox config có field/backend không khớp đường chạy thực tế. +- Network blocking của direct backend không phải OS isolation mạnh. +- Hai audit format/store và circular imports security/pricing. +- Usage/audit dựa vào global/thread-local context. + +**Scope** + +Policy vocabulary/decision service, sandbox capability matrix, audit/usage event schema/sinks, monitoring queries, dead security cleanup. + +**Affected modules/files** + +`core/agent_security*.py`, `core/security_rules.py`, `security/*`, `core/sandbox_manager.py`, platform sandbox modules, `core/audit_log.py`, `core/usage_tracker.py`, `core/model_pricing.py`, telemetry and Monitoring UI. + +**What will be changed** + +- Define enforced/advisory/unknown outcomes. +- Deterministic checks fail according to explicit policy; advisory model failure được audit. +- Sandbox reports actual backend/capabilities, không chỉ requested settings. +- Canonical audit/usage events và query services. +- Break module cycles. + +**What will NOT be changed** + +- Không tuyên bố security guarantee chưa được platform test. +- Không thay sandbox backend trên mọi OS trong một PR. +- Không xóa legacy audit data; cần reader/migration. + +**Dependencies on other EPICs:** R01, R02, R05; cung cấp query services cho R08. + +**Risk:** Cao. Security behavior change cần threat-model review và negative tests. + +**Expected outcome** + +Mọi action có explainable decision/audit; Monitoring hiển thị requested và effective protection; telemetry có schema nhất quán. + +**How to verify completion** + +- Threat-model checklist và policy decision matrix pass. +- Platform-specific sandbox integration tests. +- Legacy/current audit records đọc được. +- No circular dependency giữa security alert/policy và pricing/usage. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R09-T01 Security model/ADR | Current prompt/attachment/action/command paths | Chốt asset, trust boundary, enforced vs advisory, fail behavior | Threat model + decision vocabulary | Security review | +| R09-T02 Security decision service | Classifier, rules, AI evaluator | Return typed decision/reasons/events; UI alert là adapter | One policy API used by R05 gateway | Table-driven negative/unknown/provider-down tests | +| R09-T03 Sandbox capability matrix | Direct/integrity/AppContainer/VM code | Detect/report effective fs/network/process isolation per platform | `SandboxCapabilities` + honest config/UI mapping | Platform smoke tests and unsupported-path tests | +| R09-T04 Sandbox config cleanup | Unused/misleading settings | Wire, deprecate hoặc remove từng field với migration; document fallback | No inert security option | Config-to-runtime behavior tests | +| R09-T05 Canonical audit event/store | Two audit loggers/formats | Define event schema, append sink, legacy readers, query API | One audit pipeline | Legacy fixture + concurrency/rotation tests | +| R09-T06 Usage/pricing separation | Circular modules/global context | Pure pricing module + explicit usage event sink/context | Cycle removed, deterministic cost calculation | Golden pricing/aggregation tests | +| R09-T07 Monitoring query services | UI direct file/global queries | Build bounded paginated/filterable read models | UI-independent monitoring APIs | Empty/corrupt/large log tests | +| R09-T08 Legacy security cleanup | Dormant validators/loggers | Deprecate/migrate/remove only after active path coverage | Single authoritative namespace | CodeGraph/import check + full tests | + +### R10 — Testing, Packaging & Contributor Experience + +**Objective** + +Đưa repository tới trạng thái contributor có thể setup, tìm đúng boundary, chạy test phù hợp và mở PR nhỏ với CI feedback đáng tin. + +**Current Problems** + +- Chưa có complete runtime dependency manifest/lock strategy. +- CI chủ yếu syntax + pytest; không có architecture/lint/type/coverage budget. +- Test thiếu runtime/tool/security/persistence/UI presenter/scheduler. +- Không có module ownership/extension recipes. +- `i18n.py` và một số central files dễ conflict. + +**Scope** + +Test taxonomy/fixtures, packaging, CI quality gates incremental, architecture and extension docs, cleanup workflow. + +**Affected modules/files** + +`tests/`, dependency/packaging files, CI workflows, `README.md`, `START_CONTRIBUTING.md`, `CONTRIBUTING.md`, new architecture docs, eventually i18n catalogs. + +**What will be changed** + +- Add deterministic unit/contract/integration/headless-UI layers. +- Declare runtime/dev/test dependencies và supported Python/OS. +- CI checks theo debt budget, không bật strict toàn repo trong một lần. +- Contributor recipes cho provider/tool/MCP/screen/agent behavior. + +**What will NOT be changed** + +- Không theo đuổi coverage percentage như mục tiêu duy nhất. +- Không format/rewrite toàn repo cùng architecture PR. +- Không remove dormant code khi chưa có R01 evidence. + +**Dependencies on other EPICs:** Bắt đầu cùng R01 và chạy xuyên suốt; final cleanup sau R02–R09. + +**Risk:** Thấp-trung bình; strict gate bật quá sớm có thể làm chậm migration. Dùng baseline/debt ratchet. + +**Expected outcome** + +Fresh clone setup reproducible; contributor biết sửa đâu và có test suite cục bộ nhanh; CI ngăn violation mới. + +**How to verify completion** + +- Setup từ fresh environment theo docs. +- PR template map change → required tests. +- CI time hợp lý và không cần external credential. +- Architecture recipes được một contributor mới thực nghiệm. + +| Task | Input | Work | Output | Validation | +| --- | --- | --- | --- | --- | +| R10-T01 Test taxonomy/fixtures | R01 fixtures + subsystem needs | Chia unit/contract/integration/headless-ui/platform; temp config/home helpers | Test guide + reusable fixtures | No test writes real user data | +| R10-T02 Agent/tool/security suites | R03–R05/R09 contracts | Thêm fake-provider event, tool capability, permission và negative security tests | Critical-path safety net | Deterministic offline CI | +| R10-T03 Persistence/scheduler suites | R02/R06/R07 | Fault injection, multi-project, fake-clock/idempotency tests | Data/background safety net | Parallel/repeat runs stable | +| R10-T04 Headless presentation tests | R08 presenters/controllers | Test view state/commands không cần display; Qt smoke subset riêng | Fast UI logic suite | CI headless pass | +| R10-T05 Packaging/dependencies | README install list/current imports | Tạo `pyproject.toml` hoặc equivalent runtime/dev extras + lock policy | Reproducible install | Fresh venv install + import/startup smoke | +| R10-T06 CI quality ratchet | Existing workflows | Add lint/type/architecture/coverage for changed code trước, expand dần | Actionable CI | Intentional violation fixture fails correct job | +| R10-T07 Contributor architecture recipes | Current contribution docs | “add provider/tool/MCP/screen/change agent behavior” step-by-step + ownership | Contributor guide | Dry run bởi developer không tham gia refactor | +| R10-T08 Translation/catalog split | `i18n.py` sau UI migration | Split catalogs by feature while preserving `tr()` API | Lower-conflict localization files | Key uniqueness/missing-language tests | +| R10-T09 Dormant-code removal PRs | R01 inventory + replacements covered | Mỗi PR xóa một isolated dormant feature/path | Reduced maintenance surface | Full tests, package/import smoke, release note | + +## 15. Dependency Between EPICs + +```mermaid +flowchart TD + R01["R01 Foundation"] --> R02["R02 Config / Persistence"] + R01 --> R03["R03 Providers / Routing"] + R01 --> R05["R05 Tools / MCP / Connectors"] + R01 --> R06["R06 Workspace / History"] + + R02 --> R03 + R02 --> R05 + R02 --> R06 + R02 --> R09["R09 Security / Observability"] + + R03 --> R04["R04 Agent / Conversation"] + R05 --> R04 + R06 --> R04 + R05 --> R09 + + R04 --> R07["R07 Scheduling / Workflow"] + R06 --> R07 + R05 --> R07 + + R03 --> R08["R08 UI Separation"] + R04 --> R08 + R05 --> R08 + R06 --> R08 + R07 --> R08 + R09 --> R08 + + R01 --> R10["R10 Testing / Contributor"] + R02 --> R10 + R03 --> R10 + R04 --> R10 + R05 --> R10 + R06 --> R10 + R07 --> R10 + R08 --> R10 + R09 --> R10 +``` + +Dependency không có nghĩa toàn EPIC phải đóng mới được bắt đầu. Dùng milestone contract: + +| Consumer | Milestone prerequisite | +| --- | --- | +| R03 | R02 typed provider settings + secret reference API | +| R04 | Provider registry/routing request; ToolPolicy API; WorkspaceSession/history repository | +| R07 | Conversation service headless; WorkspaceSession; tool policy | +| R08 Settings | R02 + R03 + connector config API | +| R08 Cowork | R03 + R04 + R05 + R06 policy/snapshot services | +| R08 Co4E/Schedule | R04 + R07 | +| R08 Monitoring | R09 query APIs | + +## 16. Recommended Execution Order + +### Phase 0 — Baseline and governance + +1. R01-T01…T05. +2. Bổ sung R10 test guide/fixtures tối thiểu. +3. Freeze rule: code mới không thêm direct UI → provider/repository import ngoài allow-list. + +### Phase 1 — Stable infrastructure seams + +1. R02 atomic config/typed settings/secret API. +2. R03 provider descriptor/contract. +3. R06 WorkspaceSession/history repository. + +Ba stream có thể chạy song song sau khi typed config conventions được chốt, nhưng ownership file phải tách: + +- R02 owner `config.py`/persistence helpers. +- R03 owner `providers`/`core/routing`. +- R06 owner project/history/workspace modules. + +### Phase 2 — Actions and enforcement + +1. R05 tool descriptors/capability inventory/gateway. +2. R09 security decision vocabulary/audit schema. +3. Migrate external MCP/REST/MS365 action qua gateway. + +### Phase 3 — Runtime/application service + +1. R04 execution snapshot và typed events. +2. Conversation application service. +3. Migrate Cowork path đầu tiên. +4. Sau parity mới migrate scheduled/help caller. + +### Phase 4 — Background and workflow + +1. R07 task repository/schedule calculator. +2. Task execution service + Qt adapter. +3. Co4E rồi Flow runner migration. + +### Phase 5 — UI screen migration + +Theo thứ tự ở mục 17. Mỗi screen là một chuỗi PR nhỏ; không mở đồng thời PR lớn trên `ChatPanel`, `Co4ETab` và `MainWindow`. + +### Phase 6 — Consolidation + +1. Move module mechanical khi caller cũ đã hết. +2. Xóa compatibility adapter/debt allow-list. +3. Consolidate security/audit legacy. +4. Split i18n catalogs. +5. Remove dormant code đã xác nhận. +6. Nâng CI ratchet và hoàn thiện contributor docs. + +## 17. UI Refactor Order + +Architecture foundation phải đi trước. Thứ tự UI sau đây tối ưu risk/dependency, không phải độ ưu tiên sản phẩm. + +| Order | Screen | UI responsibility nên giữ | Business logic cần extract | Shared dependencies | Entry criteria | +| --- | --- | --- | --- | --- | --- | +| 1 | Settings + connector dialogs | Form state, validation message, confirm/cancel | Config/secret persistence, provider catalog, connection test | R02 typed settings/secret, R03 registry, R05 connector service | Services có contract tests; connection test async | +| 2 | Workspace + Project Settings + History | Project selection, tab state, render history | Project CRUD, session binding, path/history resolution | R06 WorkspaceSession/repositories | Không còn dynamic history dir | +| 3 | Cowork / Chat | Compose/render message, tool/permission prompt, cancel | Routing, execution request, runtime, persistence, output/usage | R03–R06, R09 audit | Golden event parity và fake-provider service | +| 4 | Schedule + Task Editor | List/form/render status, run/cancel commands | Task validation/CRUD, due calculation, execution, AI drafting | R07, R03/R04 | Fake clock/task service | +| 5 | Co4E | Canvas interaction, node editor, run visualization | Workflow CRUD/run, conversation nodes, usage/result aggregation | R04/R07 | Headless Co4E run passes | +| 6 | Folder | Tree/editor/diff/terminal presentation | FS operations, routing/provider prompts, image/terminal execution | R03/R05/R06 | Bounded filesystem + tool policy | +| 7 | GraphRAG | Graph visualization, question input, streamed answer | Scan/index/query, provider prompt, usage | Graph application service, R03/R06 | Temp-repo graph tests | +| 8 | Dashboard + Monitoring | Render read models, filters, refresh command | Usage/audit/pricing/security/tool queries, AI suggestions | R09 query services, R04 suggestion use case | Canonical audit/usage schema | +| 9 | Help/skills/agents/admin surfaces | Presentation CRUD/chat | Repository/provider/runtime calls | R02/R04 and small CRUD services | Active/dormant status known | +| 10 | MainWindow | Navigation, tray, window lifecycle | Service construction, scheduler ownership, feature coordination | All relevant application services | Screens accept narrow dependencies | + +Refactor một screen theo sequence: + +```text +Characterize screen behavior + → introduce presenter/controller beside current widget + → migrate one concern + → run headless + manual smoke tests + → remove direct dependency + → repeat + → mechanical file move only after import boundary is clean +``` + +## 18. Risks + +| Risk | Probability / Impact | Mitigation | +| --- | --- | --- | +| Behavior drift trong chat streaming/tool loop | Medium / High | Golden event tests, fake provider, one caller per PR, manual cancel/tool/permission checklist | +| User config/history corrupt hoặc migration mất key | Medium / High | Golden real-shape fixtures, preserve unknown keys, atomic replace, backup and rollback | +| Cross-project data leak trong migration | Existing High / High | Immutable session, explicit repo binding, two-project concurrency regression | +| Security regression khi unify tools | Medium / Critical | Capability inventory, default treatment for unknown, negative tests, security review | +| Sandbox overclaim trên platform khác | Existing Medium / High | Effective capability detection, platform CI/smoke, honest UI text | +| MCP/connector compatibility break | Medium / High | Descriptor adapter around current schemas, fake server contract, migrate per connector | +| Scheduler duplicate/missed run | Medium / High | Fake clock, idempotency/claim model, restart/timezone test matrix | +| Merge conflict ở God files/config/i18n | High / Medium | File ownership window, short-lived PRs, service-first extraction, i18n split cuối phase | +| Abstraction over-engineering | Medium / Medium | Contract chỉ ở multi-implementation/cross-layer seam; ADR yêu cầu real caller; no DI framework | +| Compatibility adapters sống vĩnh viễn | High / Medium | Mỗi adapter có owner, removal condition và debt issue/CI allow-list | +| Test suite xanh nhưng không phản ánh GUI lifecycle | Medium / High | Presenter tests + targeted Qt smoke + manual release checklist | +| Dead code bị xóa nhầm dynamic path | Low / High | R01 reachability inventory, config/plugin check, removal PR riêng | +| Secrets migration khóa user khỏi provider | Medium / High | One provider slice, import-once, explicit fallback/recovery UI | + +## 19. Migration Strategy + +### 19.1 Strangler pattern cho từng boundary + +```text +Old concrete path + ↓ +Introduce contract + adapter wrapping old implementation + ↓ +Characterize old behavior + ↓ +Migrate one caller + ↓ +Verify parity and production smoke + ↓ +Migrate remaining callers + ↓ +Block new imports to old path + ↓ +Remove adapter/old path in dedicated PR +``` + +### 19.2 Rules cho incremental migration + +1. Một PR chỉ nên thay một contract hoặc một caller; mechanical move không trộn behavior change. +2. Public compatibility façade giữ tên cũ trong migration (`ProviderFactory.create`, repository function, event dict adapter). +3. Mỗi façade có deprecation owner và removal condition ghi trong EPIC. +4. Không đọc current project/provider/config từ worker sau khi request đã start. +5. Persistence migration phải đọc được old shape trước khi ghi new shape; backup trước irreversible migration. +6. Security gateway được đưa vào “observe/audit mode” để inventory unknown tool trước khi enforce, nhưng destructive unknown không được silently execute. +7. Screen migration giữ current UX; visual redesign là roadmap khác. +8. Feature flag chỉ dùng khi cần rollback production path; không dùng để duy trì hai architecture vô thời hạn. +9. CodeGraph/import checks được chạy sau watcher/index ổn định và CI static rule là source of enforcement. + +### 19.3 Compatibility windows + +| Boundary | Temporary compatibility | Removal condition | +| --- | --- | --- | +| Config | Typed facade delegates current nested dict | All direct mutations migrated; unknown-key round-trip tested | +| Provider | Old factory calls new registry | All provider construction uses typed request | +| Agent events | Typed event converts to current dict | All active presenters consume typed events | +| Tools | `execute_tool()` delegates registry | All runtime/external paths call gateway/registry | +| History/project | Module functions delegate repository | All background work binds WorkspaceSession | +| Audit | Reader accepts legacy + canonical | Retention window passed or migration complete | +| UI worker | Existing `AgentWorker` wraps application service | Screens no longer construct provider/repo inside job | + +## 20. Contributor Experience Improvements + +### 20.1 Hiện trạng từ góc nhìn developer mới + +**Họ có biết bắt đầu từ đâu không?** + +Chỉ một phần. `README.md` và `START_CONTRIBUTING.md` giúp chạy ứng dụng và mô tả contribution flow, nhưng chưa có map “feature → application/runtime/infrastructure owner”. `core/` quá rộng và UI chứa cả business logic. + +**Muốn thêm model provider thì sửa đâu?** + +Hiện phải hiểu và có thể sửa: + +- provider base/implementation/factory; +- config defaults/provider labels/settings; +- routing metadata/probing assumptions; +- UI model/provider listings; +- usage/error behavior. + +Target: một `ProviderDescriptor`, implementation và contract tests; Settings/routing tự đọc registry. + +**Muốn thêm MCP/tool/connector thì sửa đâu?** + +Hiện phải hiểu `AppContext.build_mcp_tools`, MCP client, tool schema/executor, config, Monitoring và security exceptions. Target: đăng ký một `ToolSource`/connector descriptor với capability metadata, secret references và shared contract tests. + +**Muốn thêm màn hình thì sửa đâu?** + +Hiện thêm widget rồi wiring/lazy lifecycle vào `MainWindow`/Workspace/Monitoring tùy loại, đồng thời thường phải tự gọi core. Target: screen package có view + presenter/controller, use-case dependency và một route descriptor được composition root đăng ký. + +**Muốn sửa agent behavior thì sửa đâu?** + +Hiện phải xác định behavior ở `ChatPanel/CoworkTab`, `chat_agent`, `code_agent`, Co4E runner hay task executor; cùng một behavior có thể khác nhau theo entrypoint. Target: agent runtime policy/profile và ConversationApplicationService là điểm bắt đầu; entrypoint chỉ chọn profile. + +**Có cần hiểu toàn repository mới contribute được không?** + +Với thay đổi provider/tool/chat hiện tại, gần như có. Sau refactor, contributor chỉ cần hiểu contract của capability, adapter đang sửa và contract tests. + +### 20.2 Deliverables cho contributor experience + +- `docs/architecture/overview.md`: startup, dependency direction, subsystem owners. +- `docs/architecture/decisions/`: ADR ngắn cho layer names, tool capability, workspace snapshot, Flow vs Co4E. +- `docs/contributing/add-provider.md`. +- `docs/contributing/add-tool-or-mcp.md`. +- `docs/contributing/add-screen.md`. +- `docs/contributing/change-agent-behavior.md`. +- `docs/contributing/persistence-migrations.md`. +- `docs/testing.md`: fast/local/platform/manual suites. +- `CODEOWNERS` hoặc ownership matrix cho provider/runtime/security/UI screens. +- PR template yêu cầu: affected boundary, compatibility path, tests, migration/removal condition. +- Issue templates theo EPIC → module → class/function task. +- Development dependency manifest và one-command setup/test. +- Generated or CI-checked dependency report; không bắt contributor chạy CodeGraph để làm task đơn giản. +- Translation catalogs theo feature để giảm conflict sau khi UI migration ổn định. + +### 20.3 Definition of Ready cho contributor task + +Một task chỉ sẵn sàng assign khi có: + +- current file/symbol và behavior cần preserve; +- boundary/contract đích; +- input/output cụ thể; +- file ownership và out-of-scope; +- test fixture không cần credential; +- dependency EPIC đã đạt milestone; +- migration/rollback note nếu có dữ liệu hoặc security behavior. + +### 20.4 Definition of Done + +- Caller trong scope dùng boundary mới. +- Contract/unit/integration test theo risk pass. +- Không thêm import violation. +- Compatibility/debt entry được cập nhật. +- Docs/extension recipe cập nhật nếu public contributor path đổi. +- Manual smoke checklist hoàn tất cho UI/runtime path. + +## 21. Recommended First 3 Pull Requests + +Ba PR đầu nên tạo safety và seam, chưa đụng UI God class lớn. + +### PR 1 — Characterization Safety Net for Runtime and Boundaries + +**Scope** + +- Thêm fake provider, fake tool executor, event collector và temp config/home fixtures. +- Test `run_cowork()` cho text-only, one-tool-call, failure/cancel contract cơ bản. +- Test provider factory mapping và `AppConfig`/một representative repository round-trip. +- Thêm architecture ADR và import-debt report ở chế độ không cho violation mới. + +**Files dự kiến** + +`tests/`, `docs/architecture/`; production source chỉ có thể cần test seam tối thiểu, không đổi behavior. + +**Risk:** Thấp. + +**Architecture value:** Rất cao; tạo safety net và ngôn ngữ chung cho mọi PR sau. + +**Validation** + +- Toàn bộ test offline, không đọc/ghi `~/.cowork_local`. +- Current 81 tests + new suite pass. +- Intentional new import violation bị check bắt. + +### PR 2 — Atomic AppConfig Persistence + +**Scope** + +- Extract atomic JSON write primitive từ pattern đã được routing store dùng. +- Chỉ migrate `AppConfig.load/save`; giữ nguyên nested schema/public access. +- Preserve unknown keys và thêm corrupt/interrupted-write tests. +- Chưa migrate secrets hoặc các repository khác. + +**Files dự kiến** + +Một infrastructure persistence helper mới, `config.py`, focused tests. + +**Risk:** Thấp nếu golden fixtures và rollback được giữ. + +**Architecture value:** Cao; thiết lập persistence primitive dùng cho các store sau và giảm startup corruption risk. + +**Validation** + +- Golden config round-trip byte/semantic compatible theo policy đã chọn. +- Fault trước replace giữ file cũ hợp lệ. +- Startup smoke với config hiện tại, missing file và corrupt file. + +### PR 3 — Provider Descriptor Registry behind Existing Factory + +**Scope** + +- Introduce `ProviderDescriptor` registry làm source of truth cho id, label, implementation kind và required config. +- `ProviderFactory.create()` vẫn là compatibility façade. +- Migrate chỉ provider listing/labels trong Settings hoặc một read-only consumer. +- Thêm registry completeness/duplicate/contract tests. +- Không thay provider network behavior hoặc routing heuristic. + +**Files dự kiến** + +`providers/`, focused provider catalog consumer, tests. + +**Risk:** Thấp. + +**Architecture value:** Cao; tạo extension point đầu tiên và giảm hard-code trước khi migrate routing/Cowork. + +**Validation** + +- Existing provider ids tạo đúng implementation như trước. +- Duplicate/missing descriptor fail ở test. +- Settings hiển thị cùng provider/model options hiện tại. + +Sau ba PR này, PR tiếp theo nên là `WorkspaceSession` + explicit history repository regression cho cross-project isolation, rồi mới mở migration ConversationApplicationService/Cowork.