CI / test (push) Canceled after 0s
## Summary epic r04 - begin refactor ## Change Type - [x] Cowork feature - [ ] Bug fix - [ ] Core AI contribution - [ ] Test / hardening - [ ] Performance - [ ] Documentation ## Related Work Cowork Task: Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets Core AI Issue: Core Task: Related PR: ## Scope What is intentionally included? What is intentionally NOT included? ## Validation - [ ] Unit tests - [ ] Integration tests - [ ] Manual verification - [ ] Regression check Commands / evidence: ## Security Impact Permission / credential / network / customer data impact: ## Compatibility - [ ] No breaking change - [ ] Breaking change documented ## Reviewer Notes Anything Cowork reviewers should pay attention to. --------- Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com> Co-authored-by: Huong Le Thi Thien <huongltt35@fpt.com> Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com> Co-authored-by: Vu Dam Tuan <vudt15@fpt.com> Co-authored-by: Hiep Ha Van <hiephv3@fpt.com> Co-authored-by: Lam Hoang Van <lamhv7@fpt.com> Reviewed-on: #7 Co-authored-by: Duy Le Huu <duylh19@fpt.com>
7.0 KiB
7.0 KiB
ADR-001: 4-Tier Clean Architecture for Desktop Local Application
- Status: ACCEPTED / ENFORCED
- Date: 2026-08-21
- Deciders: Team Duy (Tech Lead & AI Runtime), Team Nam (Governance & Automation), Team Hoa (Workspace & Scheduling)
- Target Project: Cowork Local (Cowork-Local BamBOO)
1. Context and Problem Statement
Cowork Local is a desktop application written in Python using PySide6 (Qt) and designed for local-first execution. Historically, the codebase suffered from architectural coupling across layers:
- God-Widget Problem: Monolithic UI widgets (e.g.,
ui/chat_panel.py>1,800 LOC,ui/co4e_tab.py>1,400 LOC) mixed UI rendering, network I/O, business rules, filesystem operations, and background worker lifecycle. - Untestable Business Logic: Core algorithms (model routing, conversation turn management, schedule calculation) were tightly coupled to
PySide6widgets orQTimer, making unit testing in headless CI environments impossible without a graphical display server. - Circular Dependencies & Global State Leaks: Uncontrolled module imports (
model_pricing.py↔usage_tracker.py,agent_security.py↔agent_security_alert.py) and mutable global state (state.py::AppContext.active_project_id) caused race conditions in background task runs.
2. Decision: 4-Tier Clean Architecture
We enforce a strict 4-Tier Clean Architecture based on the Dependency Inversion Principle:
┌─────────────────────────────────────────────────────────────┐
│ PRESENTATION │
│ (PySide6 Widgets, Dialogs, Qt Signals/Slots, View Models) │
└──────────────────────────────┬──────────────────────────────┘
│ depends on
▼
┌─────────────────────────────────────────────────────────────┐
│ APPLICATION │
│ (Use Case Services, Turn Orchestrators, Route Dispatchers) │
│ *** STRICTLY PURE PYTHON (0 Qt) *** │
└──────────────────────────────┬──────────────────────────────┘
│ depends on
▼
┌─────────────────────────────────────────────────────────────┐
│ DOMAIN & RUNTIME CORE │
│ (Entities, Value Objects, Domain Events, Tool Descriptors) │
│ *** STRICTLY PURE PYTHON (0 Qt) *** │
└──────────────────────────────▲──────────────────────────────┘
│ implemented by
┌──────────────────────────────┴──────────────────────────────┐
│ INFRASTRUCTURE │
│ (LLM Providers, Keyring Secrets, Atomic Persistence, MCP) │
└─────────────────────────────────────────────────────────────┘
3. Layer Definitions and Responsibilities
Tier 1: Presentation Layer (presentation/)
- Responsibilities: UI component layout, user event capture, progress display, visual animations, confirmation dialog triggers.
- Allowed Imports:
PySide6.*,application.*,domain.*. - Forbidden: Direct database queries, raw LLM API calls, disk writes outside UI cache, executing tool commands directly.
- Constraints: Every widget file must strictly be under 400 lines of code (LOC).
Tier 2: Application Layer (application/)
- Responsibilities: Orchestrate single use cases (e.g.
ConversationApplicationService,RoutingApplicationService,TaskApplicationService). Convert UI requests into domain requests, coordinate domain services with infrastructure adapters. - Allowed Imports:
domain.*,infrastructure.*interfaces/contracts, standard Python libraries. - Forbidden:
PySide6,PyQt5,PyQt6,ui.*,app.*. - Nature: 100% Pure Python. Must be executable and testable in headless CI environments without a display driver.
Tier 3: Domain Layer (domain/)
- Responsibilities: Core domain models, frozen DTO snapshots (
ConversationExecutionRequest), typed event streams (AgentEvent), descriptors (ToolDescriptor,ProviderDescriptor), deterministic calculation algorithms (ScheduleCalculator). - Allowed Imports: Standard Python library only (
dataclasses,typing,enum,datetime,pathlib,abc). - Forbidden:
PySide6,PyQt*,requests,sqlalchemy, filesystem mutations, OS network calls. - Nature: Completely isolated and zero-dependency core.
Tier 4: Infrastructure Layer (infrastructure/)
- Responsibilities: Adapters for external systems (OpenAI/Anthropic/Ollama/FPT providers, OS Keyring via
SecretStore,AtomicJsonFilepersistence, MCP child processes, filesystem tools). - Allowed Imports: Third-party SDKs, OS libraries,
domain.*. - Forbidden:
presentation.*,PySide6.QtWidgets.
4. Architectural Rules and Non-Negotiable Invariants
- Zero Qt in Business Logic:
domain/andapplication/must never importPySide6orPyQt*.- Verified via AST parser script
scripts/check_imports.py.
- Immutable Request Snapshots:
- Turns are initiated using immutable frozen dataclasses (
ConversationExecutionRequest) to decouple runtime state from mutable UI state.
- Turns are initiated using immutable frozen dataclasses (
- Thread Safety and Signal Decoupling:
- AI generation and tool calls run asynchronously in worker threads.
- UI updates occur strictly on the Qt main thread by consuming
AgentEventstreams through Qt Signal bridges.
- Single Responsibility and Modularity:
- Production files must stay within 400 LOC.
- English In-Code Comments:
- Every modified or created line/block must include concise English comments explaining design decisions and processing logic.
5. Consequences and Compliance
- Positive:
- Full testability: Unit tests run in milliseconds without GUI or network mocks.
- Zero circular dependencies: Clear top-down data flow.
- Resilience: UI crashes do not corrupt background tasks or files.
- Verification:
- Automated CI gate:
python scripts/check_imports.pyandpython scripts/check_loc.py.
- Automated CI gate: