# Current Work Items

## 用途

只記這一輪正在做的事情。方向看 `ROADMAP`，分階段交付看 `EXECUTION_PLAN`。

## 規格重置（2026-03-22）

這輪以你最新決策為準：

1. 實驗抓取：URL 規則 + 裝置限制
2. 建立 Experiment 同步建立原始 Variant
3. 移除 `is_control`
4. 移除 `variant_changes.enabled`
5. key 改系統生成：`EX+timestamp` / `VA+timestamp`
6. Variant 移除 `status`，使用者只調 `name` / `traffic_weight`

## 目前進行中

### A. 文件與契約（✅ 完成）

- [x] `SYSTEM_SPEC_MASTER` 已寫入 6 條新規格
- [x] `EXPERIMENT_SYSTEM_SPEC` 已更新為新流程
- [x] `API_CONTRACT_MASTER` 已更新欄位約束
- [x] `docs/MIGRATION_NOTE.md` 已建立：`is_control` / `variants.status` / `variant_changes.enabled` 移除策略與 DB 清理建議

### B. Backend 實作調整（✅ 完成）

- [x] `domain/keys.py` 新建：`generate_experiment_key()` / `generate_variant_key()` → `EXxxxxxx` / `VAxxxxxx`
- [x] `ExperimentCreate` 移除 `experiment_key` 欄位；service 層改為系統生成
- [x] `VariantCreate` 移除 `variant_key` 欄位；service 層改為系統生成
- [x] 建立 Experiment 時自動建立「原始版本」Variant
- [x] `domain/admin.py` Variant 移除 `status`、`is_control`
- [x] `domain/editor.py` VariantChange 移除 `enabled`
- [x] `domain/editor_builder.py` 移除 enabled 過濾
- [x] `schemas/admin.py` VariantRead / VariantCreate / VariantUpdate 同步更新
- [x] `repositories/directus/variants.py` `default_fields` 移除 status / is_control
- [x] `repositories/directus/variant_changes.py` `default_fields` 移除 enabled（修復 CORS/500 bug）
- [x] `schemas/editor.py` `EditorChangeRead` / `EditorChangeWrite` 已移除 `enabled`
- [x] `application/admin/releases.py` 移除 enabled / is_control 依賴；加 archive_release()
- [x] `application/editor/service.py` build_preview 移除 enabled=item.enabled
- [x] Variant 流量權重加總 = 100 驗證（`_assert_weights_sum_100`）
- [x] `repositories/directus/activity.py` 新建：Directus built-in `/activity` 查詢
- [x] `application/admin/activity.py` 新建：`ActivityService.list_for_experiment()`
- [x] `api/admin/experiments.py` 加 `GET /{id}/activity` 端點
- [x] `api/admin/releases.py` 加 `POST /{id}/archive` 端點

### C. Frontend 實作調整（✅ 完成）

- [x] `VariantFormDialog.vue` 簡化為只保留 `name` + `traffic_weight`
- [x] `variant-view-model.js` 移除 `status`、`isControl`、`buildVariantStatusTag`
- [x] `experiment-view-model.js` `mapVariantItem` 移除 `status`、`isControl`；`mapReleaseItem` 加 `versionNo`
- [x] `experiment/detail.vue` 改寫為 5 tab 設計（實驗設定 / 變體列表 / 版本列表 / 目標設定 / 操作紀錄）
- [x] `variant/detail.vue` 移除狀態/角色 metric card；完整 change set 摘要已存在
- [x] `use-variant-detail-page.js` 移除 `roleLabel`、`variantStatusTag`
- [x] `use-experiment-detail-page.js` 完整重寫：含 activityLog、release lifecycle、experiment settings
- [x] `release-api.js` 加 `archiveRelease()`
- [x] `experiment-api.js` 加 `listActivity()`
- [x] `dashboard/home.vue` 已有真實實驗統計摘要
- [x] 清理未使用的 `openFirstVariantEditor` / `statusTypeMap` 從 composable return

### D. 驗證清單（規劃項）

- [ ] 建立實驗後自動產生原始 Variant 的 E2E 測試
- [ ] Key 自動生成格式測試：`EX+timestamp` / `VA+timestamp`
- [ ] URL + device targeting 命中測試
- [ ] Release build / publish / rollback / archive 回歸測試
- [ ] Directus Activity log 在真實環境顯示正常

### E. Runtime 實作修正（✅ 完成）

- [x] `domain/runtime.py` 移除 `RuntimeVariantCandidate.is_control`
- [x] `schemas/runtime.py` 移除 `RuntimeVariantCandidateInput.is_control`
- [x] `application/runtime/assignment.py` `bootstrap()` 移除 variant `filter[status]` 查詢（variants 已無 status 欄位）
- [x] `application/runtime/assignment.py` 移除所有 `is_control=variant.is_control` 引用
- [x] `application/runtime/assignment.py` `_matches_targeting()` 實作完整 URL rule 匹配：
  - `contains` / `equals` / `starts_with` / `regex` 四種 operator
  - `device_targets` 裝置限制（mobile / tablet / desktop via user-agent 偵測）
  - 空 url_rules 時 fallback 到 `base_url` startswith 檢查

### F. Staging 真實環境驗證（✅ 完成，2026-03-23）

- [x] Auth flow：`/api/auth/me` → 確認 is_admin + 完整 permissions
- [x] Site 查詢：`ose-demo-local` site 可讀
- [x] Experiment 建立：key 自動生成（`EX1774195099342`）
- [x] 原始版本 Variant 自動建立（`VA1774195099525`，weight=50）
- [x] 第二個 Variant 建立（weight=50，總計=100）
- [x] 權重驗證：嘗試新增 weight=1 的第三個 variant → 正確回傳 400
- [x] Variant change 儲存：`replace_text` 操作可寫入
- [x] Release build：`runtime_payload` 格式正確，operations 包含 selector + action + payload
- [x] Publish / Rollback / Archive 鏈路全部可跑
- [x] Experiment 設為 running + targeting_config 儲存
- [x] Runtime bootstrap：URL rule 命中正確（`example.com` ✓，`other-site.com` → 0 candidates ✓）
- [x] Activity log：6 筆操作紀錄正確回傳（建立/更新/版本/變體）

### G. Code Review 待修（✅ 完成，2026-03-23）

- [x] `P0` Release lifecycle 修正：`publish()` 先 unpublish 同實驗其他 published release，`rollback()` 設自身為 draft 並自動升版前一個 draft release。
- [x] `P0` Editor preview API 契約對齊：前端 `buildPreview()` 改送 `items`（原為 `changes`），與 `BuildPreviewRequest.items` 一致。
- [x] `P0` `save_changes()` 改為完整覆蓋語意：先刪除 DB 中不在 request items 的舊 change，再 upsert。
- [x] `P1` 移除 `variant_changes.enabled`：`EditorChangeRead` / `EditorChangeWrite` schema 刪除欄位；frontend `editor-workspace-model.js` 同步清除。
- [x] `P1` 建立 Experiment 時前端不再送 `experiment_key`（`ExperimentFormDialog` 移除 `autoFillKey`、`_auto_key`、`_generated_key`）。
- [x] `P1` Runtime bootstrap 改為從 release snapshot 讀取 `traffic_weight` / `variant_key`，避免即時 variant 異動造成分流不一致。
- [x] `P1` Editor bridge snippet `handleMessage` 加 `event.source === window.parent` 驗證；`EditorCanvasFrame` 捕捉 `event.origin` 並存入 `canvasOrigin`，postMessage 改用具體 targetOrigin（fallback `"*"`）。
- [ ] `P1` Release rollback 邊界條件補強：限制只能 rollback `published` release，並在 rollback 流程最後再次保證同一 experiment 僅有一個 `published`。
- [ ] `P2` 補自動化測試：Backend API 契約、Editor flow、Runtime targeting/assignment、Release lifecycle 回歸。
- [ ] `P2` 文件狀態一致化：`ROADMAP`、`CURRENT_WORK_ITEMS`、`VALIDATION_EXECUTION_LOG` 的完成狀態同步。

## 系統狀態

**Phase A–G 主線已完成（2026-03-23），目前剩餘：1 項 P1 邊界條件 + 2 項 P2 強化。**

目前系統可運作；P1/P2 完成後可進一步提高一致性與可回歸性。

## 延後項目

- 大型 UI polish
- `ose-card` 深度重構
- `conutdown-timer` 深度重構
