# 🟢 START HERE — FR-038 Q1：準備期 per-AO My Jobs（設計定稿 + 地基已驗，接手實作 5 增量）

> **給下個 session 的 prompt**：「讀 `docs/features/FR-038-2606-oscal-redesign/handoff/2026-06-15-Q1-prep-jobs-START-HERE-handoff.md`，先過 §0 讀序硬 gate 懂 Q1 要解決什麼（requirement §4.3b + spec `q1-prep-workflow-job-design.md`），能答冷接自檢 4 問再碰 code。跑 §6 pre-flight + §7 verify，接手 Q1 實作 5 增量。」
> 本檔自包含。狀態為 **2026-06-15 verified**（現場跑真 CMMC L1 匯入 + B5 矩陣 + pytest）。

> ## 🔖 交接現況（2026-06-15 換 session 當下）
> | 項目 | 值 |
> |------|----|
> | **進度** | Wave 2B：B1✅ B2✅ B3a✅ B4.1✅ **B4.2✅ B5(.1~.6)✅ OSCAL匯出✅ B5 AO收斂fix✅**。**Q1 設計定稿 + 地基驗證完成**（spec committed）。**下一棒 = Q1 實作（5 增量）** |
> | 主專案 branch / HEAD | `feature/oscal-refactor` / **`d8b8d47f`**（本 session 10 commits）|
> | 主專案 working tree | **乾淨，只有 `M pyproject.toml`**（jedi-oscal-v2 dev path-dep，照規範勿 commit）|
> | ⚠️ **v2 套件未 commit dev 改動（B1 留下，本 session 沒動套件）** | repo `~/Projects/Jedicogy/module/jedi-python-package`（branch `feature/oscal-refactor`）：`M catalog_service.py`、`M framework_service.py`、`?? tests/catalog/test_catalog_service_import.py`。**dev path-dep，BE 重啟即生效；發版等整 feature 完成 + user 明示。別搞丟。** |
> | 跑得起來嗎 | `create_app()` BOOT OK；`python -m pytest test/` = **56 failed + 50 errors**（持平 2A baseline、零新回歸）+ 9 skipped |
> | push | **未 push**，等 user 明示 |
> | dev DB 新增真資料 | 本 session 匯入真 CMMC L1：framework id `169`（code `CMMC_L1_VFY_*`）/ **catalog `729`**（17 控制 / 59 assessment-objective / 273 method）。Q1 smoke 直接用 catalog 729 當資源庫底材。 |

---

## 🧭 開工前必懂：Q1 要解決什麼 + 本棒在大圖位置（先懂才准碰 code）

**一句話**：FR-038 把舊「AP 兼當稽核輪次」重寫成正式 OSCAL 模型。**Q1 = 受評公司在「稽核前」的準備工作（My Jobs）**——準備 SSP / 收證據（PM 教材：合規工作八成在準備期、證據在 SSP 階段就備好）。這塊在 2A 翻地基時被卡住（見下），是 Wave 2B 唯一還沒做的 BE 功能。

**Q1 目標模型（requirement §4.3b 定案）**：
- 「任務執行 / My Jobs」= 受評公司準備 SSP / 收證據的工作，**與 AP / 稽核輪次無關**（稽核員 Phase 3 走 AR 判定，不走 job 引擎）。
- job 綁在**專案 SSP 控制項**的層級 —— **經 user 2026-06-15 拍板細化為：綁在 per-AO（assessment-objective）層**（不是控制層）。每個 AO 一個準備 job，專案成立時就建（clone 資源庫 workflow 設定）。
- workflow 引擎（jedi-flow-engine）保留，綁定點從舊「AP task」改為「**專案 catalog 的 assessment-objective part**」。

**Q1 為何之前被卡（2A 留下的洞）**：舊「control→workflow template」設定（`profile_assessment_workflow_mapping`）依賴 v1 entity，v2 切換後 dark；新資源庫 `module_frames.template_uid` 全 NULL；`vw_user_job_queue` 的 control_* 留 NULL 佔位等 2B 接。**本 session 把架構決策 + 資料地基都敲定/驗證完了**，下一棒純實作。

> **冷接自檢 4 問**（答不出回 §0 讀序）：① Q1 的 job 綁在哪個資料實體上、為什麼是 AO 不是控制層？② 「AO」在新模型 = 哪張表的哪種 row、part_id 長怎樣？③ 為什麼設定用「單一預設 template / 資源庫」（A1）而非 per-AO 設定？④ 為什麼要「**重建**」`workflow_execution_control_mapping` 而不是「加欄」？

---

## §0 接手讀序（按序，1~2 是硬 gate）

1. 本檔「🧭」節 + 通讀本檔
2. 🔒 gate：[`q1-prep-workflow-job-design.md`](../q1-prep-workflow-job-design.md)（**Q1 spec，全讀** — 決策 D-Q1-1~7、資料模型、流程、view、scope）
3. 🔒 gate：[`requirement-analysis.md`](../requirement-analysis.md) §4.3b（Q1 定案）+ §6「任務執行」列 + [`design.md`](../design.md) §4.4（主專案↔套件邊界：workflow/job 綁 SSP 控制項留主專案）
4. 本 session 的 B5 AO 推導當範本：`app/grc/service/assessment_result_app_service.py` 的 `_derive_ao_map` / `_project_catalog_controls`（Q1 要用**同一套 AO 來源**，建議抽共用 helper）
5. flow-engine 既有 instantiate 邏輯參考：`app/flow_engine/service/workflow_execution_service.py`（不直接用、走 direct insert，見 §3）

---

## §1 本 session 做了什麼（2026-06-15，全 verified）

### B4.2 — AP 編輯（commit `6886ccec`）
AP 三件事接 v2 `set_reviewed_controls` / `set_assessment_subjects` / `set_tasks` + 重生草稿；auditor 守門（ap_uid → round → project 解析）。tasks 的 methods 落 props、timing 原樣 JSONB。

### B5（.1~.6）— 完整稽核生命週期（commits `987948cd` `fb8ea7a8` `49d94704` `c138de79` `f9e61129` `cac9b844`）
- **B5.1** start-auditing 建 engagement AR + ar_result + **AO 全量矩陣**（AO 推導：AP→凍結SSP→profile→專案 catalog→各控制 assessment-objective part；無 AO 走控制層 fallback）
- **B5.2** 逐 AO 判定（met/not_met/pending）+ observation（證據引用不複製）
- **B5.3** 系統風險總結（多對多 finding 關聯，severity 存 characterizations）
- **B5.4** AR finalize（無 not_met→closed / 有 not_met→remediation + 自動生 POA&M）+ migration `poam_id`（已套 dev）
- **B5.5** POA&M item 列表/詳情 + 整改計畫 + 里程碑（三層 D-4b，assignee enrich + 180 天告警）
- **B5.6** close-round + launch-reverify（覆核連動關母輪）
- 全 B5 子端點 **nested under `round_uid`**（非 contract 扁平 `/ar-finding/{uid}`，避免改套件 — v2 query entity 無 uuid 欄）

### OSCAL 匯出（commit `f28f3d9c`）
`GET /oscal/export/<doc_type>/<uid>`（catalog/ssp/assessment-results/poam）回裸 OSCAL JSON 不包 envelope。權限暫 jwt-only（per-project authz 為 follow-up）。

### B5 AO 收斂 fix（commit `a971e81b`）— **本 session 後段真資料驗出的真 bug**
B5.1 用套件 `list_aos`，但 `list_aos` 回 `AO_PART_NAMES`（assessment-objective **+ assessment-method + assessment-objects + objective**）全集 → 矩陣把「查核方法」也誤算一筆判定。**實測真 L1：59 objective vs 273 method → 矩陣會建 332 筆而非 59**（超量 5.6x）。修成 `get_by_control` + filter `name=='assessment-objective'`（不動套件）。**Q1 必須用同一個 AO 定義。**

### Q1 設計 + 地基驗證（spec commit `d8b8d47f`）
見 §3。

---

## §2 ⚠️ 會讓你做錯的陷阱 / 已定決策（先看）

1. **AO = 只算 `assessment-objective` part**（user 拍板）。`list_aos` 不能用（含 method/objects）；用 `CatalogControlPartRepoImpl.get_by_control(cc.id)` + filter `name=='assessment-objective'`。**B5 與 Q1 共用此定義**（建議把 B5 的 `_derive_ao_map` 抽成共用 helper 給 Q1 用，避免兩邊 AO 兜不起來）。
2. **AO 是專案自有資料**：專案 catalog 是 B2 clone（邊界②），其 `catalog_control_parts` 是 clone 來的、專案專屬，可掛 job。**已驗 clone 有保留 AO parts**（catalog 729 建專案後矩陣正確展 59 AO）。
3. **part_id 含控制前綴**（`AC.L1-3.1.1_obj.2`）→ 跨控制不撞名，可安全當 ao_part_id 識別。
4. **⚠️ 綁定表不存在 / FK 壞**（**本棒最關鍵的地基發現**）：`compliance.workflow_execution_control_mapping` **DB 沒這張表**（只有 ORM model），且 model 的 `version_id` FK 指向**已被 drop 的** `oscal.oscal_framework_versions`（v2 改名 `framework_versions`）。→ **要「建」這張表**（shape 改 `workflow_execution_id + control_id + ao_part_id`、丟掉壞 version FK），不是「加欄」。對齊 model/entity/mapper/repo（`infra/flow_engine/models/workflow_execution_control_mapping.py` 等）。
5. **task_assignees 不能 unassigned**：PK = (project_id, control_id<Integer>, task_id, user_id<NN>)。指派是 FE Wave 3，**不在本棒 scope**。本棒只建 job + 綁 AO，view rebind 讓「指派後」能顯示 control+AO。
6. **同步建、direct insert**（user 拍板 sync）：per-AO job 在 project_start @transaction 內當場建。**避免 320× BPMN parse** —— BPMN 只 parse 一次拿 user-task id（或用 seed BPMN 的固定 task id），per-AO 走 `WorkflowExecutionDomainService.create_workflow_execution` + `JobExecutionDomainService.create_job_execution` direct insert。
7. **pytest 用 `python -m pytest test/`**；boot 要補 dummy GITLAB/GITHUB env（見 §6）。
8. **plan 假設先 verify**（v2 簽章 / 欄位 / 表存在性）才開工。不晶晶體。

---

## §3 Q1 設計定稿（locked）+ 地基驗證結果

### 決策（全 locked，細節見 spec）
| # | 決策 | 值 |
|---|------|----|
| D-Q1-1 | 綁定粒度 | **per-AO**（每 assessment-objective part 一個準備 job）|
| D-Q1-2 | AO 定義 | 只算 `assessment-objective`（與 B5 共用）|
| D-Q1-3 | 設定粒度 | **A1：單一預設 template / 資源庫**（用 `module_frames.template_uid`）|
| D-Q1-4 | template | seed 一個最簡「收證據」BPMN（單一 user task）|
| D-Q1-5 | 生成時機 | **同步**（project_start @transaction 內，direct insert）|
| D-Q1-6 | 執行綁定 | **建** `workflow_execution_control_mapping`（workflow_execution_id + control_id + ao_part_id；丟壞 version FK）|
| D-Q1-7 | 指派 | task_assignees（建立時不指派，PM 之後；FE Wave 3）|

### 地基驗證（真 CMMC L1，2026-06-15）
- 真匯入經正規 BE pipeline（`framework_app_service.import_framework_version` → `import_catalog_from_pdf`，`framework_code="CMMC_2"`，L1/L2 共用同一 parser）→ catalog 729：17 控制 / **59 assessment-objective** / 273 method / 17 statement。part_id `AC.L1-3.1.1_obj.2`。
- 以 catalog 729 建資源庫→專案→輪次→start-auditing：AO 矩陣 total=**59**（B5 fix 後；fix 前 332）。**證明 per-AO pipeline 通 + clone 保留 AO parts**。

### flow-engine 關鍵事實（實作要用）
- **master template** 落 `compliance.workflow_templates`（欄：`uid`/`name`/`type`/`version`/`provider`/`xml`=BPMN/`enable`）。最簡 BPMN = 單一 `<bpmn:userTask id="collect_evidence" name="收證據">`（start→userTask→end）。
- **WorkflowExecution** model（jedi-flow-engine）必填：`template_id`(NN)、`name`、`status`(WorkflowStatus)、`type`(WorkflowType)；`main_workflow_execution_id` nullable。建：`WorkflowExecutionDomainService.create_workflow_execution(entity)`。
- **JobExecution** model 必填：`workflow_execution_id`(NN)、`main_workflow_execution_id`(NN)、`template_id`(NN)、`template_job_id`(NN=BPMN task id)、`status`(JobStatus)、`type`(JobType)；`name`/`description` 可放 AO label。建：`JobExecutionDomainService.create_job_execution(entity)`（direct insert，不 parse BPMN）。
- **container**：`di_containers/flow_engine/workflow_excution_containers.py` 暴露 `workflow_execution_domain_service` / `job_execution_domain_service` / `workflow_execution_control_mapping_domain_service` / `workflow_template_repo`。
- **My Jobs view**：`scripts/sql/view/vw_user_job_queue.sql` — control_* 全 NULL 佔位；rebind = job(b) → `workflow_execution_control_mapping`(by `b.workflow_execution_id`) → `control_id` + `ao_part_id` → 專案 catalog `catalog_controls` / `catalog_control_parts`。

---

## §4 開工順位（5 增量，每增量 smoke + 顯式 git add commit）

> 每增量照 canonical：改 code → BOOT OK → 真資料 smoke（用 catalog 729）→ pytest 不多紅 → 顯式 git add commit。

1. **Q1.1 — seed template + 建綁定表**
   - migration A：**CREATE** `compliance.workflow_execution_control_mapping`（`workflow_execution_id bigint`, `control_id varchar`, `ao_part_id varchar`，PK 視需要；GRANT cm_app；INSERT schema_migrations）。對齊 model/entity/mapper/repo（去 version FK、加 ao_part_id）。
   - migration B（seed）：INSERT 一筆 master「收證據」`workflow_templates`（固定 uid + 最簡 BPMN，task id `collect_evidence`）+ `UPDATE compliance.module_frames SET template_uid=<該 uid> WHERE "group"='resource-library' AND template_uid IS NULL`。
2. **Q1.2 — AO 推導共用 helper**：把 B5 `_derive_ao_map` / `_project_catalog_controls` 抽成共用（如 `app/grc/service/_ao_derivation.py` 或 util），B5 + Q1 共用「assessment-objective only」來源。
3. **Q1.3 — project_start per-AO job 生成**：`project_start_app_service.start_project` 在 `_init_ssp_control_implementations` 後，解析資源庫 `template_uid`（無→log skip 不擋成立）→ 對每個 in-scope 控制的每個 assessment-objective part：direct insert workflow_execution + job_execution + `workflow_execution_control_mapping(ao_part_id, control_id)`。注入 flow-engine domain services + workflow_template_repo + part repo。
4. **Q1.4 — vw_user_job_queue rebind**：control_* 經 mapping → 專案 catalog control + AO（part_id）。migration（view 可移植）+ 套 dev。
5. **Q1.5 — 真資料 smoke + commit**：用 catalog 729 建資源庫→專案→斷言每 assessment-objective part 各一 job + mapping（ao_part_id）+ vw_user_job_queue 能查到該 project 的 job（含 control+AO）。量測專案成立耗時（59 AO；L2 ~320 的話留意，spec §5 量考量）。

---

## §5 該讀 / 預期改動的檔案

| 檔案 | 為何 |
|------|------|
| `app/project/service/project_start_app_service.py` | Q1.3 加 per-AO job 生成（`_init_ssp_control_implementations` line ~159 / `start_project` line ~203）|
| `app/grc/service/assessment_result_app_service.py` | `_derive_ao_map` 抽共用 helper（Q1.2）|
| `infra/flow_engine/models/workflow_execution_control_mapping.py` + entity/mapper/repo（`domain/flow_engine/...` `infra/flow_engine/...`）| Q1.1 重建表 shape（去 version FK、加 ao_part_id）|
| `di_containers/flow_engine/workflow_excution_containers.py` / `di_containers/project/project_containers.py` | wire flow-engine domain services 進 project_start |
| `scripts/sql/view/vw_user_job_queue.sql` | Q1.4 rebind control_* |
| `~/Projects/Jedicogy/.../jedi-flow-engine/.../models/{workflow_execution,job_execution}.py` | 必填欄位參考（direct insert）|

---

## §6 Pre-flight（必跑，可複製貼）

```bash
cd /Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be
git branch --show-current                      # feature/oscal-refactor
git status --short                             # 僅 ' M pyproject.toml'
git log --oneline -3                            # d8b8d47f / a971e81b / f28f3d9c
( cd ~/Projects/Jedicogy/module/jedi-python-package && git status -sb | head -6 )  # 套件 dev 改動還在
poetry run python -c "import jedi_oscal_v2; print('v2 OK')"
set -a; source .env; set +a 2>/dev/null
export GITLAB_API_VERSION=4 GITLAB_URL=http://localhost GITLAB_PRIVATE_TOKEN=dummy GITHUB_PRIVATE_TOKEN=dummy
poetry run python -c "import eventlet; eventlet.monkey_patch(all=False, socket=True); import sys; sys.setrecursionlimit(5000); from core.app_factory import create_app; create_app(); print('BOOT OK')"
poetry run python -m pytest test/ -q -p no:cacheprovider --continue-on-collection-errors 2>&1 | tail -1  # 56 failed,...,50 errors（持平）
```
> `.env` 在 shell `source` 會在 JSON 行報 parse error；跑 python script 改用 `from dotenv import load_dotenv; load_dotenv()`。

---

## §7 Verify B4.2/B5 + Q1 地基（確認現況，可複製貼）

```bash
cd /Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be
PW=$(poetry run python -c "from dotenv import load_dotenv; load_dotenv(); import os,json; print(json.loads(os.environ['DB_SECRET'])['rds_master_password'])" 2>/dev/null)
# 真 L1 catalog 729 的 AO 結構（Q1 smoke 底材）
PGPASSWORD="$PW" psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tA -c "
SELECT p.name, count(*) FROM oscal.catalog_control_parts p
JOIN oscal.catalog_controls cc ON p.catalog_control_id=cc.id
WHERE cc.catalog_id=729 GROUP BY p.name ORDER BY 2 DESC;"   # assessment-method 273 / assessment-objective 59 / statement 17
# 綁定表不存在（Q1.1 要建）→ 應回空 / NULL
PGPASSWORD="$PW" psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tA -c "SELECT to_regclass('compliance.workflow_execution_control_mapping');"  # 空 = 表不存在，要 CREATE
PGPASSWORD="$PW" psql -h 192.168.50.188 -p 25432 -U cmmgr -d guidant_ai_dev -tA -c "SELECT to_regclass('oscal.framework_versions'), to_regclass('oscal.oscal_framework_versions');"  # 前者存在 / 後者 NULL（壞 FK 別接）
```
B4.2/B5 端到端 smoke（可選複跑）：見本 session B5 各 commit message 的 verify 段；canonical 流程 = 建合成 catalog→資源庫→專案→輪次→launch-audit→start-auditing→judge→risk→finalize→poam→close→reverify。

---

## §8 行為規範重要提醒（適用本棒）

- **不切 branch**（兩 repo 都在 `feature/oscal-refactor`；branch 不對停下問 user）。
- **可自行階段性 commit**（顯式 `git add` 檔名、**禁 `-am`**；各 repo 分開）；**push / 收尾 / 套件發版等 user 明示**。
- `pyproject.toml` path-dep **勿 commit**；v2 套件 dev 改動別搞丟、別發版。
- **改 BE 後提醒 user 重啟 BE**（無 hot reload）；服務 user 自己起。
- 跨 schema FK 字串帶 schema 前綴（記憶 `feedback_cross_schema_fk_must_qualify`）。
- SQL migration：cmmgr + `--single-transaction -v ON_ERROR_STOP=1`，新表 GRANT cm_app + sequence、收尾 INSERT schema_migrations；**本期 migration 只套 dev**（stg/poc 待辦）。
- **遇到架構/資料模型取捨、需選方案、scope 邊界 → 停下問 user**（本 arc 已有多次：living-triple / SSP 控制項來源 / Q1 粒度與綁定 / AO 定義 / 同步vs背景）。
- **量考量**：per-AO L2 ~320，同步建走 direct insert、量測專案成立耗時；過慢再議背景（spec §5，本期 YAGNI）。

---

## §9 收尾流程（Q1 做完 + user 明示才做）

盤點 commits → changelog（type=feat）→ analysis（Q1 per-AO 綁定 + 重建綁定表 + 同步建 取捨）→ SUMMARY → 回頭更新本 handoff ✓ + spec §狀態 + design §4.4 + api-contract（My Jobs/§3.2 job_count）→ memory feedback（≥1 條：如「list_aos 含 method 會超量、AO 只算 assessment-objective」「綁定表 DB 不存在要先驗 to_regclass」）→ Notion。**push 等 user。**

> **本 session 自身的收尾（B4.2/B5/匯出/AO fix 的 changelog / SUMMARY / analysis / memory / Notion）也都還沒做** —— user 還沒下收尾命令，全留著。下一棒若 user 要收 Wave 2B 全弧，一起補。

---

## §10 不在本期 scope（別順手做）

- **FE Wave 3**（資源庫 workflow 設定畫面、My Jobs 指派 UI、AP/AR/POA&M 畫面、輪次切換）。
- **job 自動指派**：task_assignees 由 PM 手動（FE）；本棒只建 job + 綁 AO。
- **背景建**：同步建為主，過慢才議（follow-up）。
- **per-control / per-AO 差異化 template**（A2/A3，未來 override）。
- **套件發 Nexus**、`pyproject.toml` 改回 pin（整 feature 完成 + user 明示）。
- 正式環境 schema 遷移（stg/poc/prod；本期所有 migration 只套 dev）。
- ISO/NIST（本期 CMMC-only）；import-ssp 套件實作（defer）。
- **B4.2/B5/匯出/AO-fix 的收尾文件**（等 user 下收尾命令）。

---

## §11 本 session commits（branch `feature/oscal-refactor`，未 push）

```
d8b8d47f docs(FR-038): Q1 準備期 per-AO My Jobs 設計定稿（spec）
a971e81b fix(FR-038): Wave 2B B5 — AO 矩陣只取 assessment-objective（修 method 超量 5.6x）
f28f3d9c feat(FR-038): Wave 2B B5 — OSCAL 匯出端點（catalog/ssp/assessment-results/poam）
cac9b844 feat(FR-038): Wave 2B B5.6 — close-round + launch-reverify（覆核連動，完整生命週期收口）
f9e61129 feat(FR-038): Wave 2B B5.5 — POA&M item 列表/詳情 + 整改計畫 + 里程碑（三層 D-4b）
c138de79 feat(FR-038): Wave 2B B5.4 — AR finalize（定版）+ 有 not_met 自動生 POA&M
49d94704 feat(FR-038): Wave 2B B5.3 — 系統風險總結（多對多 finding 關聯）
fb8ea7a8 feat(FR-038): Wave 2B B5.2 — AO 逐項判定 + observation（證據引用不複製）
987948cd feat(FR-038): Wave 2B B5.1 — start-auditing 建 engagement AR + ar_result + AO 全量矩陣
6886ccec feat(FR-038): Wave 2B B4.2 — AP 編輯端點接 v2 set_*
```
- migration 已套 **dev**（stg/poc 待辦）：`2026-06-15-fr038-audit-rounds-poam-id.sql`（B5.4）。前置（前 session）：`2026-06-15-fr038-project-extensions-living-ssp.sql` / `2026-06-15-fr038-audit-rounds-uid.sql`。
- dev DB 另有真 L1 import（framework 169 / catalog 729）+ 多筆 smoke 合成資料（無害）。

---

## §12 給 fresh session 的超短 prompt

```
讀 docs/features/FR-038-2606-oscal-redesign/handoff/2026-06-15-Q1-prep-jobs-START-HERE-handoff.md。
先過「🧭 開工前必懂」+ §0 讀序硬 gate（q1-prep-workflow-job-design.md 全讀 + requirement §4.3b + design §4.4），
能答冷接自檢 4 問（job 綁哪/為何 AO 層 / AO=哪張表 / 為何 A1 / 為何重建綁定表）才往下。
跑 §6 pre-flight（BOOT OK + pytest 56f/50e 持平）+ §7 verify（catalog 729 AO 結構 + 綁定表不存在）。
接手 Q1 實作 5 增量：Q1.1 seed template+建綁定表 → Q1.2 AO 推導共用 helper → Q1.3 project_start
per-AO job direct insert → Q1.4 vw_user_job_queue rebind → Q1.5 真資料 smoke(catalog 729/59 AO)+commit。
每增量 smoke + 顯式 git add commit。push/收尾/套件發版等 user 明示；不切 branch；pyproject.toml dev path-dep 勿 commit。
```

---
### 冷接可行性自檢 ✅
看本檔 + §0 讀序 + 跑 §6/§7 → 能確認現況（B4.2/B5/匯出/AO-fix shipped + commits + 套件 dev 改動 + 真 L1 catalog 729）、懂 Q1 WHY（準備期 per-AO My Jobs、為何 AO 層、為何卡）、知道 5 增量怎麼接、知道地基發現（綁定表 DB 不存在要建、壞 version FK 別接）、知道規範界線。不需 user 額外解釋即可開工。
