Feature/delta team/epic r04 (#7)
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>
This commit was merged in pull request #7.
This commit is contained in:
2026-08-31 05:15:13 +00:00
committed by gitea-admin
co-authored by anhtnm1 huongltt35 Nam Pham Dinh Thanh vudt15 Hiep Ha Van lamhv7
parent 86c27e2e79
commit f9f6bc01fd
496 changed files with 68421 additions and 19688 deletions
@@ -0,0 +1,102 @@
# Bản đồ tách `StepConfigPanel` (`ui/co4e_config_panel.py` → `presentation/co4e/`)
- **Phạm vi lượt này:** chỉ `StepConfigPanel` (nguyên bản dòng 1-528 của
`ui/co4e_config_panel.py`). Không đụng file nào khác thuộc làn N1
(`ui/co4e_tab.py`, `ui/co4e_canvas.py`, `docs/architecture/co4e-split-map.md`/`.json`).
- **Lý do phải tách thêm, dù chỉ 1 class:** `StepConfigPanel` một mình đã 396
dòng (133-528); cộng thêm module docstring + khối import của một file riêng
sẽ vượt trần 400 dòng (CASAN Check 2). Giải pháp: cắt-dán (không viết lại
logic) thành 3 file theo trách nhiệm.
## File đích
| symbol | dòng gốc | file đích | ghi chú |
|---|---|---|---|
| `_SECTION_ANIM_MS` | 27 | `presentation/co4e/step_config_section.py` | hằng số dùng bởi `_add_section` |
| `_SectionHeader` | 30-52 | `presentation/co4e/step_config_section.py` | `QLabel` clickable, không có hành vi nghiệp vụ riêng |
| `_add_section` | 55-130 | `presentation/co4e/step_config_section.py` | khung ▶/▼ dùng chung cho 4 nhóm trường của `StepConfigPanel`; không đọc/ghi state của panel |
| `StepConfigPanel` (Signal + `__init__`) | 133-313 | `presentation/co4e/node_property_panel.py` | 4 Signal (`changed`/`run_node`/`run_from`/`delete_node`) + dựng toàn bộ form |
| `StepConfigPanel.load_step` | 316-354 | `presentation/co4e/node_property_panel.py` | nạp `Step` vào form |
| `StepConfigPanel.clear_step` | 356-359 | `presentation/co4e/node_property_panel.py` | xoá state, tắt panel |
| `StepConfigPanel._on_edit` | 362-378 | `presentation/co4e/node_property_panel.py` | ghi field UI ngược vào `Step` |
| `StepConfigPanel._available_agent_names` | 380-390 | `presentation/co4e/node_property_actions_mixin.py` (`_StepConfigActionsMixin`) | staticmethod, dùng bởi `_add_subagent`/`_edit_subagent` |
| `StepConfigPanel._add_subagent` | 392-408 | `presentation/co4e/node_property_actions_mixin.py` | |
| `StepConfigPanel._edit_subagent` | 410-428 | `presentation/co4e/node_property_actions_mixin.py` | |
| `StepConfigPanel._del_subagent` | 430-437 | `presentation/co4e/node_property_actions_mixin.py` | |
| `StepConfigPanel._add_attachment` | 439-453 | `presentation/co4e/node_property_actions_mixin.py` | |
| `StepConfigPanel._del_attachment` | 455-462 | `presentation/co4e/node_property_actions_mixin.py` | |
| `StepConfigPanel._ai_draft` | 464-498 | `presentation/co4e/node_property_actions_mixin.py` | dùng `AgentWorker` thật (không mock trong `__init__`) |
| `StepConfigPanel._load_models` | 500-528 | `presentation/co4e/node_property_actions_mixin.py` | dùng `AgentWorker` thật |
## Cách ghép lại: mixin + đa kế thừa
`node_property_panel.py`:
```python
class StepConfigPanel(_StepConfigActionsMixin, QScrollArea):
...
```
`_StepConfigActionsMixin` là mixin THUẦN — không `__init__` riêng, chỉ đọc/ghi
state có sẵn trên `self` do `StepConfigPanel.__init__` định nghĩa
(`self._step`, `self._node_id`, `self.ctx`, `self.sub_list`, `self.attach_list`,
`self.instructions_edit`, `self.gen_btn`, `self.model_combo`,
`self.load_models_btn`).
Khác với bước `co4e_canvas_widget.py` (Co4ECanvas override nhiều method Qt như
`paintEvent`/`mousePressEvent`, nên thứ tự mixin-trước-base là **bắt buộc** để
MRO ưu tiên override của mixin): ở đây **không có method nào của
`_StepConfigActionsMixin` trùng tên với `QScrollArea`**, nên thứ tự kế thừa
không ảnh hưởng hành vi. Giữ thứ tự mixin-trước chỉ để nhất quán quy ước, không
phải yêu cầu kỹ thuật bắt buộc.
## Import thừa cố ý giữ nguyên
`PROVIDER_LABELS` (nguyên bản dòng 21, `from ..config import PROVIDER_LABELS`)
không được dùng ở đâu trong toàn bộ `ui/co4e_config_panel.py` gốc (đã xác minh
bằng grep). Vẫn giữ nguyên import này trong `node_property_panel.py` (chỉ đổi
số cấp `..` → `...`), không xoá, để đúng phạm vi "chỉ dời chỗ" của lượt tách
này — xoá một import "thừa" là một quyết định dọn dẹp ngoài phạm vi được giao.
## Thay đổi comment/test ngoài phạm vi "chỉ dời chỗ" (ghi riêng, không lẫn vào phần move)
1. **Docstring module của 3 file mới** (`step_config_section.py`,
`node_property_actions_mixin.py`, `node_property_panel.py`) — viết MỚI hoàn
toàn bằng tiếng Việt theo quy ước CASAN cho file mới trong `presentation/`
(mẫu `infrastructure/persistence/json/atomic_json_file.py`). Đây không phải
sửa một comment cũ bị sai do dời chỗ — module docstring nguyên bản (dòng
1-9 của `ui/co4e_config_panel.py`) mô tả cả file cũ (đã bị chia làm 3), nên
mỗi file mới cần một docstring kiến trúc riêng thay vì copy y hệt bản gốc.
2. **`ui/co4e_config_panel.py`** (file cũ) — docstring được viết lại (vẫn
tiếng Anh, khớp quy ước "sửa file cũ tiếng Anh thì giữ tiếng Anh") để nói rõ
`StepConfigPanel` đã dời đi đâu, thay vì mô tả hành vi như thể class còn
định nghĩa tại chỗ — comment cũ sẽ SAI (nói rằng lớp "ở đây" trong khi
không còn) nếu giữ nguyên.
3. **`tests/characterization/test_node_property_panel.py`** (dòng ~296-307
nguyên bản) — SỬA kỹ thuật patch/restore của case
`CASE_ADD_SUBAGENT_EMPTY_NAMES_USES_GETTEXT_QUIRK_OK`, không đổi bất kỳ
assert/hành vi nào. Bản gốc dùng
`StepConfigPanel.__dict__["_available_agent_names"]` để lưu lại method gốc
trước khi monkey-patch, rồi gán lại y hệt lúc restore. Sau khi
`_available_agent_names` chuyển vào `_StepConfigActionsMixin` (mixin riêng),
nó không còn nằm trong `StepConfigPanel.__dict__` (chỉ được kế thừa qua
MRO) → `KeyError`. Thay bằng: gán đè trực tiếp lên `StepConfigPanel` (vẫn
shadow đúng như cũ), và khi xong dùng `del StepConfigPanel._available_agent_names`
để nó rơi trở lại đúng method kế thừa từ mixin — hành vi quan sát được của
test (các assert `sub_agents`) giữ nguyên 100%, chỉ đổi CÁCH lưu/khôi phục
attribute bị monkey-patch. Đây là hệ quả tất yếu của yêu cầu tách mixin
trong lượt này (test được viết khi class còn nguyên khối), không phải sửa
test để che một thay đổi hành vi.
## Xác minh
- `.venv/Scripts/python.exe tools/check_co4e.py` — chạy TRƯỚC và SAU khi sửa,
output giống hệt nhau cả 2 lần (`KET QUA: Co4E sap xep lai, khong mat control nao`).
- `.venv/Scripts/python.exe -m pytest tests/characterization/test_node_property_panel.py -q`
— `1 passed` cả trước (đo trên code gốc, class còn ở `ui/co4e_config_panel.py`)
lẫn sau khi tách.
- `.venv/Scripts/python.exe -m pytest tests -q --tb=short -rf --continue-on-collection-errors`
— `287 passed, 1 skipped` sau khi tách (không có test nào khác vỡ vì import
`StepConfigPanel` từ `ui/co4e_config_panel.py`).
- AST-scan `domain/`+`application/` cho import PySide6/PyQt: `KHONG CO`.
- Số dòng file mới: `node_property_panel.py` 293, `node_property_actions_mixin.py`
202, `step_config_section.py` 134 — cả 3 đều ≤ 400.