1de3336970c48df3a6e342c737632506d7246327
18
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1de3336970 | merge: merge origin/feature/teamhoa/r05-r06 (R07/R08) into feature/delta-team/epic-R04 | ||
|
|
0e51356a7d |
feat(R08): split ScheduleTaskTab, FolderTab, DashboardTab, StructureGraphView
Team Hoa, EPIC R08 (UI/Application Separation) - Team Hoa scope only
(R08-T11 -> T14; R08-T01->T10 belong to Team Duy/Team Nam).
- R08-T11: ui/schedule_task_tab.py (795 lines) -> presentation/scheduling/
{kanban_board_widget,calendar_view_widget,ai_task_creator_dialog,
ai_task_import_dialog,run_history_dialog}.py + schedule_task_tab.py
shell. Kanban CRUD/drag-drop now goes through
application/scheduling/task_application_service.py (R07-T04) instead of
~30 lines of inline if/elif per drag target.
- R08-T12: ui/folder_tab.py (1587 lines, the largest of the four) ->
presentation/folder/{workspace_file_tree,document_preview_manager,
code_editor,office_document_renderer,ai_file_editor_dialog,
ai_edit_model_resolver,ai_edit_pipeline}.py + folder_tab.py shell.
Closes the R06-T05 loop: FileWorkspaceService existed since R06 with
zero production call sites (confirmed by grep); every plain-text write
(save/create/write_content) now goes through it, gaining path
containment and a Python-syntax warning the original code never had.
Pure helpers (_read_text, _is_probably_text, _pptx_available,
_split_code_block, _parse_ai_output) moved to
application/workspaces/{file_preview_helpers,ai_edit_output}.py.
- R08-T13: ui/dashboard_tab.py (437 lines) -> presentation/dashboard/
{token_usage_card_widget,usage_chart_widget,habits_widget}.py +
dashboard_tab.py shell, backed by a new
application/monitoring/dashboard_query_service.py (pricing/period/
summary queries the three widgets used to each recompute separately).
Directory-ownership note left in the checklist for Team Nam.
- R08-T14: ui/structure_graph_view.py (1035 lines) ->
presentation/graph/{graph_scene_items,graph_renderer,
graph_messages_view,graph_qa_widget}.py + structure_graph_view.py
shell. Extraction helpers (_pdf_to_markdown, _extract_file_contents)
moved to application/workspaces/graph_index_service.py (pure Python).
Renderer and Q&A panel talk only through signals
(node_selected/graph_rendered/raw_json_ready/project_changed) - neither
imports the other.
- presentation/shared/web_engine_support.py: HAS_WEB_ENGINE, previously
duplicated (folder_tab imported it FROM structure_graph_view.py) - now
one shared flag instead of one screen importing another screen's module.
All four old ui/*.py files deleted; app.py and ui/workspace_tab.py updated
to the new import paths (each god-file only had 1-2 real construction
sites, so import sites were updated directly rather than kept as a
strangler-fig shim - unlike core/tools.py at R05, which had dozens).
pytest: 377 pass (+94 vs the R07 baseline of 328; same 4 pre-existing
failures as the R05/R06 baseline, unrelated to this work).
scripts/check_imports.py: PASS. python -c "import cowork_local.app": OK.
Every new file < 400 lines (largest: graph_renderer.py, 391).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
69ab8e125b |
feat(R07): task repository, schedule calculator, Qt clock adapter, task/AI-planner services
Team Hoa, EPIC R07 (Scheduling & Workflow Runtime) - Team Hoa scope only (R07-T01 -> T05; R07-T06 Co4EWorkflowService is Team Nam's). - R07-T01: infrastructure/persistence/json/task_repository_impl.py wraps core/tasks.py's CRUD; core/tasks.py::save_task now writes through atomic_write.write_json (same durability fix as R06-T02, save_task was still doing a plain write_text). - R07-T02: domain/tasks/schedule_calculator.py::ScheduleCalculator - the cron/interval/daily/weekly/monthly due-time math extracted from core/tasks.py, pure Python with is_holiday/make_cron injected so domain/ never imports core (ADR-001 I2). core/tasks.py keeps its old function names as thin wrappers so every existing caller is unchanged. This was previously untested; now has its own unit suite. - R07-T03: infrastructure/qt/qt_scheduler_clock.py::QtSchedulerClock wraps the QTimer TaskScheduler used to own directly, injected via a new `clock=` constructor param (defaults to a real one). Originally planned at platform/qt/... ; moved after confirming that name shadows the stdlib platform module (used by core/windows_sandbox_vm.py, core/appcontainer_sandbox.py) whenever the repo root is on sys.path. tests/fakes/fake_clock.py lets scheduler dispatch be tested tick-by-tick with no Qt event loop. - R07-T04: application/scheduling/task_application_service.py centralizes run_now/duplicate/pause/delete/bulk_delete and the Kanban drag-drop business rules (move_to_status), currently only reachable by driving the real ui/schedule_task_tab.py widget. - R07-T05: application/scheduling/ai_task_planner_service.py wraps core/ai_task_planner.py::plan_tasks and core/task_import.py::import_tasks as a seam, plus the attachment-stamping step that used to only exist inside the AI-create dialog's worker closure. pytest: 328 pass (same 4 pre-existing failures as the R05/R06 baseline, unrelated to this work - see docs/refactor/BaoCao_TeamHoa_R05_R06.md). scripts/check_imports.py: PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f8e22f5f5b | merge: merge origin/gamma/refactor and origin/feature/teamhoa/r05-r06 into feature/delta-team/epic-R04 | ||
|
|
af8a3712e2 |
fix(co4e): 4 chỗ ghi JSON của Gamma đi qua AtomicJsonFile — tiêu chí nghiệm thu A
Soát lại plan.md thì thấy CASAN là NĂM tiêu chí C-A-S-A-N, không phải ba. Tiêu chí A có hai vế, tôi mới đạt vế đầu: vế 1 0 API key plaintext trong JSON -> đã đạt từ 25/08 vế 2 MỌI thao tác ghi tệp đi qua AtomicJsonFile -> CHƯA Toàn repo còn 15 chỗ ghi JSON thẳng. Bốn trong đó là của Gamma (vùng Co4E): core/co4e.py:236 lưu workflow ghi thẳng, không nguyên tử gì cả core/co4e.py:310 lưu agent ghi thẳng core/co4e_run_manager.py:156 tmp + replace tự viết application/workflows/co4e_workflow_service.py:178 tmp + replace tự viết Hai chỗ đầu nguy hơn: tắt máy giữa lúc lưu là mất luôn workflow hoặc agent. Hai chỗ sau nhìn thì có vẻ ổn vì đã tmp + replace, nhưng thiếu hai thứ: * không fsync — dữ liệu có thể còn nằm trong bộ đệm ổ đĩa khi mất điện, nên "nguyên tử" chỉ đúng với crash tiến trình, không đúng với mất điện; * dùng thẳng Path.replace, đúng chỗ dính PermissionError [WinError 5] mà tôi vá hôm 25/08 — Defender giữ handle file vừa tạo. Tần suất đo được khoảng 1/140 lần lưu, nhân với số lần lưu lịch sử chạy flow. 11 chỗ còn lại thuộc team khác (accounts, admin_agents, custom_agents, flows, groups, history, projects, skills, tasks). Không đụng vào; cần báo lên vì tiêu chí A là tiêu chí TOÀN DỰ ÁN, Gamma sạch không cứu được cổng. Đã kiểm application/ vẫn không kéo PySide6 vào sau khi thêm import mới (tiêu chí C). 714 test xanh, 24/24 checker qua. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
72ed3b4147 | Merge remote-tracking branch 'origin/gamma/refactor' | ||
|
|
40b12ecb15 |
refactor(monitoring): N2 - tach monitoring_tab.py, CanonicalAuditLogger, MonitoringQueryService, go circular import, sandbox matrix
- ui/monitoring_tab.py (1546 dong) tach thanh presentation/monitoring/** (container + 7 tab/card + shared helper), ui/monitoring_tab.py con lai re-export shim de app.py khong doi. - infrastructure/telemetry/audit_logger.py: CanonicalAuditLogger, core/audit_log.py thanh wrapper mong, tuong thich nguoc 100% voi schema .jsonl cu. - application/monitoring/monitoring_query_service.py: MonitoringQueryService read-only, filter/sort/pagination, khong import PySide6. - Go circular import model_pricing<->usage_tracker va agent_security<-> agent_security_alert (core/agent_security_types.py moi). - infrastructure/sandbox/sandbox_capabilities.py: SandboxCapabilityMatrix theo OS (Windows/Linux/macOS), chua dau noi vao core/sandbox_manager.py. - conftest.py: sua loi checkout khong ten cowork_local khien pytest import nham thu muc khac. - 77 test moi, 167/167 pass. QA da xac nhan UI/business logic khong doi (xem evidence/report/unified_report.html). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
c890a20f45 |
merge: đồng bộ origin/gamma/refactor (R01/R03/R04 — routing unification,
conversation application service, AtomicJsonFile fix) vào sau khi tách 6 widget UI Co4E (N3) Đã kiểm trước khi merge: ui/co4e_tab.py và ui/routing_toggle.py đều bị 2 bên cùng đụng, nhưng ở vùng dòng khác nhau hoàn toàn (bên kia sửa _apply_co4e_routing/RoutingToggle cho R03-T05, N3 chỉ đụng phần dựng sidebar/canvas/chat) — không có xung đột logic thật. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
0631abf85f |
feat(co4e): tách 6 widget UI khỏi ui/co4e_tab.py sang presentation/co4e/*
Lane N3 (Co4E Studio) — dùng bộ workflow refactor-god-file, mỗi bước có characterization test trước khi tách, hậu kiểm ranh giới tầng sau mỗi bước: - skills_list_panel.py / agent_list_panel.py — 2 khu vực sidebar - co4e_canvas_widget.py + canvas_items.py + canvas_interaction_mixin.py — Co4ECanvas tách 3 file (vượt 400 dòng nếu đứng một mình) - node_property_panel.py + node_property_actions_mixin.py + step_config_section.py — StepConfigPanel, cùng lý do - co4e_run_control_widget.py — RunsPagePanel (trang Flow Status) - co4e_chat_view.py — ChatPanel + _ChatInput + helper autocomplete - palette_list.py — _PaletteList dời khỏi ui/co4e_tab.py, hết import ngược presentation -> ui (agent/skills panel giờ import top-level) ui/co4e_tab.py giảm 2089 -> 1878 dòng, chỉ còn phần wiring + business logic (Co4ERunManager/AgentWorker chưa đổi — nằm ngoài phạm vi này, xem docstring presentation/co4e/co4e_tab.py). ui/co4e_canvas.py và ui/co4e_config_panel.py còn lại là compat shim re-export, không đổi API cho bên gọi. Thêm tests/test_co4e_integration.py — dựng thật Co4ETab qua build_co4e_tab(), lái luồng qua nhiều panel trong cùng instance (thêm node, mở/gập chat, chuyển trang Flow Status rồi quay lại không mất state canvas) — bắt lỗi wiring xuyên-panel mà characterization test từng panel riêng không thấy được. Đã xác minh: pytest 348 passed/1 skipped, tools/check_co4e.py sạch, không file nào >400 dòng, domain/application không import PySide6, và so pixel before/after (git worktree tại HEAD cũ) ra 0/1.125.000 pixel khác biệt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
dcf2e8f995 |
merge: kéo Delta epic-R04 (gồm cả R01 và R03) vào gamma/refactor
Nam chốt: không chờ Delta merge vào main, lấy sớm để va chạm nhỏ và sửa ngay, thay vì dồn một cục lúc cả hai cùng lên main. R04 chứa trọn R01 và R03 nên một lần merge là đủ cả ba: 96 file, +8260 dòng. Xung đột chỉ 5 file, đều là __init__.py add/add — hai team cùng dựng khung thư mục nên đụng docstring. Giữ docstring của Gamma (nói rõ ràng buộc "không import PySide6"), giữ mọi phần code của Delta. Riêng tests/fakes/__init__.py: bỏ hai dòng import háo hức của Delta (fake_provider, fake_tool_executor). fake_provider dùng `from providers.base import ...` — import tuyệt đối, chỉ chạy được khi cwd là gốc repo — nên nó làm đứt bài test "dùng fake mà không nạp config thật". Không ai import ở cấp package; test của Delta gọi thẳng module nên bỏ đi không ảnh hưởng họ. Đã ghi lý do vào docstring của gói. Delta cũng xoá preview-desktop và "requirements (cloud copy).txt". 430 test xanh sau merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3665135c38 |
feat(R04): run every Cowork turn through ConversationApplicationService
R04-T03 — the turn lifecycle, extracted from `core/chat_agent.py::run_cowork` into `application/conversations/`. The 260-line body mixed the lifecycle (step budget, cancel checks, guard -> preview -> gate -> execute ordering, sandbox tidy-up) with the machinery doing each step, and reaching any of it meant standing up a Qt widget and a worker thread. It is now a plain object driven through two Protocols and six callables (`turn_runtime.py`), with the concrete `core/*` wiring confined to `core_runtime_adapter.py` — the same shape R03 used for routing. Faithful port, not an improvement pass: where the original had a quirk (the step-ceiling note only merges into the answer when the last message is the assistant's) the quirk is preserved and commented. R04-T04 — `ui/cowork_tab.py::build_job` no longer calls run_cowork. It captures the widget's state at submit time, builds the request via the new `cowork_turn_request.py` and executes it. `execute(..., messages=...)` hands the widget's own list over because `_reattach_running_turn` replays from it WHILE the worker appends and `_finalize_turn` slices it afterwards — a private list would break both silently. R04-T05 — `core/task_executors.py`'s cowork branch shares the same engine. All five unattended-run behaviours stay put (plan reminder, history_ready, History autosave per assistant message, timeout notice, plan_incomplete_reason), and `_unattended_prompt` now expresses the load-bearing prefix order in one readable call instead of three successive rebindings. Verification: 74 new tests (364 passed, 1 skipped overall; check_imports PASS). The two that matter most: - `test_conversation_service_parity.py` runs the same scripted turn through run_cowork AND the service and compares the event stream, the resulting conversation and the advertised tool list across 7 scenarios; - `test_task_executor_turn.py` was written BEFORE the migration and passed 8/8 against the old code, then unchanged against the new. Known: `ui/cowork_tab.py` (416 -> 455) and `core/task_executors.py` (476 -> 524) stay above the 400-LOC limit. Both were already over it before this change; bringing them under needs the R08 / R07 decompositions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f61c5474b0 |
feat(R03): unify model routing and centralise the provider catalogue
EPIC R03 (Team Duy) — Model Providers & Routing. All six tasks done.
R03-T02 — Provider catalogue
domain/models/provider_descriptor.py ProviderDescriptor (frozen), WireProtocol, AuthKind
infrastructure/providers/provider_registry.py
thread-safe registry: id/alias lookup, dynamic
lookup by model id, adapter selection by protocol
providers/factory.py drops its own _REGISTRY table and delegates to the
registry, still raising ProviderError for callers
R03-T03 — RoutingApplicationService (pure Python, 4 modes)
application/model_routing/routing_models.py
RoutingMode (off/auto/manual/fallback),
RoutingRequest (immutable snapshot), RouteEvaluation,
RoutingOutcome
application/model_routing/routing_application_service.py
the single decision flow, reached through two narrow
ports plus a caller-supplied confirm callback, so no
Qt import is needed
application/model_routing/core_routing_adapter.py
binds the ports to core/routing and AppContext
Fallback is a new resilience mode: keep the selected model while it can serve the turn,
re-route only when it cannot. Wired end to end through config.py, state.py,
ui/routing_toggle.py and i18n.py (EN/JA/VI).
R03-T04 / T05 — Remove the duplicated routing flow
ui/chat_panel.py (#L638), ui/co4e_tab.py, ui/folder_tab.py each drop ~35 lines of copied
logic and call the shared service; the widgets now only build a RoutingRequest, host the
Manual-mode modal and render the outcome.
R03-T06 — Token usage as an event
infrastructure/telemetry/usage_sink.py UsageEvent + UsageEventSink protocol, with tracker,
in-memory and composite sinks
providers/openai_compat.py, providers/anthropic.py
publish a UsageEvent instead of writing to the
usage tracker themselves
core/usage_tracker.py adds current_context() so a sink can borrow and
restore a thread's attribution
R03-T01 — Contract tests
tests/contracts/test_providers.py parametrises over every provider in the registry: chat()
signature, canonical assistant message, normalised tool calls, response closed, tool schema
translation, ProviderError, list_models/test_connection, one UsageEvent per turn.
Test infrastructure fix (required to verify any of the above): tests/conftest.py used to put
the repository's PARENT directory on sys.path, so `import cowork_local.*` resolved against
whichever sibling folder happened to carry that name — on a dev machine, an unrelated older
checkout. The suite reported green while exercising different code. The conftest now binds
this checkout to the cowork_local name in sys.modules.
Verification
pytest tests/ 236 passed in ~1.8s (102 before this change)
scripts/check_imports.py PASS, 0 forbidden imports in domain/ and application/
new production files largest is 288 lines, all under the 400 LOC ceiling
new tests 134 (50 contract, 70 unit, 14 integration), all offline
scripts/run_quality_gate.py does not exist yet (R10-T02), so DoD item 7 was covered by
check_imports.py plus the full suite.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
cf542b7416 |
feat(R06): workspace session snapshot, atomic persistence, history-dir race fix
EPIC R06 (Team Hoa) - workspace/filesystem isolation, no cross-project
mutable state.
R06-T01 domain/workspaces/workspace_session.py
WorkspaceSession - project_id/workspace_root/sandbox_dir/allowed_paths
frozen snapshot + is_allowed(path), same "capture once at submit time"
shape as R04's ConversationExecutionRequest.
R06-T02 infrastructure/persistence/json/{atomic_write,workspace_repository_impl,conversation_repository_impl}.py
Real bug fixed: core/projects.py::save_project and core/history.py's
save_conversation/rename_conversation/set_pinned did a plain
path.write_text(json.dumps(...)) - two syscalls, no atomicity. A crash
between them leaves a half-written file that load_project/load_conversation
then silently treat as "missing". All four now write through
atomic_write.write_json (temp file + os.replace). WorkspaceRepository/
ConversationRepository are thin object-shaped facades over the same
(now-atomic) functions, for future application-layer callers.
NOTE: atomic_write.py is deliberately NOT named atomic_json_file.py -
R02-T01 (Team Nam) claims that filename for the same purpose app-wide;
see the checklist for the consolidation TODO.
R06-T03 infrastructure/filesystem/execution_workspace.py
ExecutionWorkspace names the output_dir/scratch_dir split that already
exists (core/chat_agent.py's flat workspace_root/.scratch) - does not
move anything.
R06-T04 ui/chat_panel.py
The actual race: ChatPanel._persist_session (saves a BACKGROUND turn's
conversation) resolved its save directory via a live
self.ctx.config.history_dir() read at save time. ui/workspace_tab.py::
_load_current mutates that same config field on every project switch, so
a turn still running when the user switched projects got saved into the
NEW project's history folder. Fixed by adding "home_history_dir" to the
per-turn ctx dict (same "home_*" snapshot convention already used for
session id/messages/title), captured at submit time. Verified with a real
offscreen-Qt test, not just a unit double:
tests/integration/test_history_dir_race.py.
R06-T05 application/workspaces/file_workspace_service.py
FileWorkspaceService - the File Explorer / AI Editor entry point for the
same safe read/write/edit operations the agent tool loop has, by calling
core/tools.py::execute_tool directly (same dispatch, same ToolContext
containment, same audit log) rather than reimplementing any of it.
New tests: tests/unit/test_workspace_session.py,
test_atomic_write_and_repositories.py, test_execution_workspace.py,
test_file_workspace_service.py, tests/integration/test_history_dir_race.py
(29 new tests, incl. 2 real offscreen-Qt integration tests).
Suite: 283 passed, 4 pre-existing failures unrelated to R05/R06 (see
checklist). check_imports: PASS. All new files < 400 LOC.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
ae4fe72b2e |
feat(R05): tool capability registry, unified policy gateway, MCP lifecycle manager
EPIC R05 (Team Hoa) - one security/approval path for every tool call.
R05-T01 domain/tools/{tool_descriptor,tool_registry}.py
ToolCapability (READ/WRITE/EXECUTE/NETWORK, composable) + ToolDescriptor +
ToolRegistry, replacing three independently-maintained gating lists
(core/tools.py::WRITE_TOOLS, code_agent.py's WRITE_TOOLS|MS365_WRITE_TOOLS,
chat_agent.py's literal ("run_command","install_package") tuple) with one
capability lookup.
R05-T02 infrastructure/filesystem/{file_tools,command_tools,fetch_tools,tool_context}.py
core/tools.py's execute_tool if/elif chain split into per-concern modules.
core/tools.py is now a strangler-fig shim: re-exports ToolContext/ToolError,
dispatches through a {name: handler} dict built from the split modules.
core/tools.py: 566 -> 291 lines.
R05-T03 application/conversations/tool_policy_gateway.py
ToolPolicyGateway.allow(name, gate, payload) - capability-driven ALLOW vs
ask-the-gate decision. Wired into both chat_agent.py::run_cowork and
code_agent.py::run_code, replacing their separate hand-rolled checks.
Verified equivalent to the old hardcoded sets by test.
R05-T04 (behavior change, not just refactor)
MCP/connector tools (core/mcp_client.py, core/ext_connectors.py) reached
chat_agent.py via extra_executor(name, args) with NO permission check at
all. They are now tagged with a conservative default capability
(WRITE|EXECUTE|NETWORK - no MCP tool self-declares risk) and routed through
the SAME ToolPolicyGateway as built-ins. When "confirm before running
commands" is on, MCP/connector calls now prompt like run_command already
did - a real gap closed, and a user-visible change worth calling out.
R05-T05 infrastructure/mcp/mcp_source_manager.py
McpToolSourceManager extracts the connection cache/lock/start-or-skip
lifecycle out of state.py::AppContext (_mcp_connections/_conn_lock) into a
standalone, directly-testable class. AppContext.build_mcp_tools and
_ms365_builtin_connection now call ensure()/stop(); _ext_connections
(unified Connectors) is out of scope for this task and keeps its own lock.
New tests: tests/unit/test_tool_registry_and_policy.py,
test_code_agent_tool_policy.py, test_cowork_extra_tool_policy.py,
test_mcp_source_manager.py (26 new tests).
Suite: 254 passed, 4 pre-existing failures unrelated to R05 (2 EPIC R02
config-security, 2 environment-dependent routing tests - see checklist).
check_imports: PASS. All new files < 400 LOC.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
8a9ee5f875 |
chore(refactor): mục chung của Team Gamma — khung, hợp đồng, cổng CASAN
Sáu việc trong "mục chung" của bản phân công, làm trước khi ba nhánh tính năng tách ra. 1. Khung 5 tầng theo đúng đường dẫn plan.md: domain/ application/ infrastructure/ presentation/ platform/ + tests/fakes/ — 38 __init__.py. Trước đó là 0 file, mà mọi task của cả ba người đều ghi vào đây. Đã kiểm platform/ không che khuất module platform của stdlib. 2. Hợp đồng SecretStore và ConfigRepository (Protocol, chưa cài đặt) + fake chạy trong bộ nhớ. Danh sách thuộc tính không bịa: đếm 156 lời gọi ctx.config.* trong 29 file rồi lấy những cái dùng thật, xếp theo số lần. Cố ý bỏ config.data (36 lời gọi, nhiều nhất) — bê dict thô sang kiến trúc mới là bê nguyên vấn đề cũ. 3. tests/test_contracts.py — bài nghiệm thu, không phải test cho vui. Bài chính chạy tiến trình riêng và khẳng định dùng fake KHÔNG kéo theo cowork_local.config lẫn PySide6; đó là điều kiện để N2 và N3 code ngay hôm nay thay vì đợi bản thật ngày 23 và 26/08. 4. scripts/audit_security.py — CASAN Check 1, Gamma chủ trì (hạn 30/08). Viết sớm để kiểm liên tục trong lúc chuyển API key, không đợi tới ngày cổng. Lần chạy đầu ra 3 báo động giả (secret_in_output là tên quy tắc, api_key="x" là dữ liệu test) nên đã siết: ngưỡng độ dài, hằng liệt kê, hình dạng khoá i18n, và dấu "# casan: allow" làm lối thoát chuẩn. --self-test cắm 4 credential thật + 5 mẫu vô hại để chứng minh nó còn cắn được — một máy quét không tìm thấy gì chỉ có giá trị nếu chứng minh được nó biết tìm. 5. Ba check CASAN vào CI, chạy mọi PR thay vì dồn tới 30/08. Check 2 và 3 thuộc Team Hoa và Team Duy, chưa có script — bước CI bỏ qua nếu file chưa tồn tại, để thêm cổng không làm đỏ CI của hai team kia. 6. docs/refactor/GammaTeam_decisions.md — hai quyết định chờ nhóm trưởng chốt: provider_conf() còn trả api_key hay không (ảnh hưởng 5 nơi, 3 nằm ngoài team), và số phận 24 checker UI sẽ vỡ khi file bị dời. 96 test xanh (90 cũ + 6 mới). CASAN Check 1: 0 credential lộ. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
10739f19aa | breakdown folder tree for epic R01 | ||
|
|
a53163ebaf |
feat(R04): immutable turn snapshot, typed agent events, conversation service
EPIC R04 (Team Duy) - the turn lifecycle leaves the widget. R04-T01 domain/agents/conversation_execution_request.py Frozen snapshot of one turn, captured on the UI thread at submit time. The job closure used to read widget/workspace state from inside the worker thread, so a turn could run on a mix of submit-time and later state depending on thread timing. R04-T02 domain/agents/agent_event.py 13 frozen event types replacing untyped emit() dicts, with a two-way bridge so existing widgets keep consuming the legacy shape until EPIC R08. Adds TurnCompletedEvent - the end-of-turn signal the engine never had, which is why a cancelled turn and a failed turn look identical to the UI today. R04-T03 application/conversations/conversation_application_service.py Runs a turn from a request and reports typed events. Never raises across the worker boundary; TurnResult.raise_if_failed() preserves the existing exception-based failure path. begin_turn()/execute_turn() expose the live message list for callers that autosave history mid-run. R04-T04 ui/cowork_tab.py::build_job -> snapshot + service. R04-T05 core/task_executors.py::_run_agent -> same service (was a second, slightly different assembly of the same call). Caught while wiring the bridge: the first event vocabulary had no "notice" event, so Agent Security warnings and auto-compaction notices would have been silently swallowed. Added NoticeEvent plus a test that scans the engine sources for emit() tags and fails when one has no typed counterpart. New: tests/integration/ - real offscreen CoworkTab running a scripted turn end to end (7 tests), including a characterisation of the extra provider call Agent Security spends reviewing each request. Suite: 225 passed, 2.74s. check_imports: PASS. All new files < 400 LOC. 2 pre-existing failures remain in test_config_security.py (EPIC R02/Team Nam). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
96bec976e7 |
feat(R03): unify provider catalogue, routing decisions and usage telemetry
EPIC R03 (Team Duy) - one provider catalogue, one routing flow, one usage seam.
R03-T01 tests/contracts/test_providers.py
29 contract tests every provider must satisfy: canonical assistant message,
streamed text == returned content, reasoning never joins the answer, parsed
tool arguments, ProviderError for every failure. Real adapters exercised
offline by stubbing Provider._request.
R03-T02 domain/models/provider_descriptor.py
infrastructure/providers/provider_registry.py
Provider facts declared once (was split across providers/factory.py,
DEFAULT_CONFIG and PROVIDER_LABELS). ProviderRegistry.build() also stamps the
descriptor id onto the instance, so ollama/github_copilot/codex usage is no
longer all attributed to "openai_compat", and never mutates the caller config.
R03-T03 application/model_routing/routing_application_service.py
Pure-Python routing policy with four modes: Off, Auto, Manual and the new
Fallback (switch only AFTER the current model fails). Depends on a RoutingPort
protocol; production wires the existing core.routing engine underneath.
R03-T04/T05 ui/chat_panel.py, ui/co4e_tab.py, ui/folder_tab.py
Three near-identical routing copies (~40 lines each) replaced by a call to
ctx.routing_application() plus a confirm callback. Mode vocabulary now lives
in one place (normalize_mode/is_valid_mode) instead of four literal tuples.
R03-T06 infrastructure/telemetry/usage_sink.py
Token usage extracted from both providers into UsageEvent + UsageEventSink.
Estimation pinned against core.usage_tracker so no recorded number changes.
Also fixes a deadlock introduced while wiring AppContext: routing_application()
held _routing_lock and called routing(), which takes the same non-reentrant lock.
Suite: 186 passed, 1.22s. check_imports: PASS. All new files < 400 LOC.
2 pre-existing failures remain in test_config_security.py (EPIC R02/Team Nam).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|