#!/usr/bin/env python3
"""Generate docs/查价系统-工程任务拆解-v1.2.md from v1.1."""

from __future__ import annotations

import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "docs" / "查价系统-工程任务拆解-v1.1.md"
DST = ROOT / "docs" / "查价系统-工程任务拆解-v1.2.md"

ABOLISHED = {75, 76, 77, 78}
V12_NOTE_TASKS = {22, 23, 28, 73, 110, 117, 88}

TASK_119_120 = """## task-119

- **ID**：task-119
- **状态**：待执行
- **模块**：Lib/Infra
- **目标**：v0.6 RPA 环境变量模板（GD-15）
- **输入**：PRD §8.2.1；技术设计 §6.2 CHG-T03
- **输出**：`.env.example` 增 `MOTHERSHIP_QUOTE_URLS`、`RPA_STORAGE_STATE_PATH`、`RPA_SELECTOR_*`（8 项）、`RPA_USE_PATCHRIGHT`
- **实现范围**：禁止内置 dashboard / `/quote` 默认 URL；缺 `MOTHERSHIP_QUOTE_URLS` 时 rpa-worker fail-fast
- **验证**：`.env.example` 含全部 RPA 必填项；未配置 URL 列表时 worker 启动报错退出
---

## task-120

- **ID**：task-120
- **状态**：待执行
- **模块**：Lib/Infra
- **目标**：Docker RPA 持久化（storageState volume）
- **输入**：技术设计 §6.1 §7.5 CHG-T04
- **输出**：`docker-compose.yml` rpa-worker 注入 RPA env + `rpa_state` volume → `/app/.rpa`
- **实现范围**：volume 挂载 + env 透传；不含业务逻辑
- **验证**：`docker compose up -d` 后 `.rpa/mothership-storage.json` 跨容器重启保留
---

"""

TASK_121_122 = """## task-121

- **ID**：task-121
- **状态**：待执行
- **模块**：RPA
- **目标**：Playwright codegen 录制入口脚本
- **输入**：PRD §8.2.3 GD-15；技术设计 §9.2
- **输出**：`scripts/record-mothership.sh`（headed，`RPA_HEADLESS=false`）
- **实现范围**：启动 codegen；禁止 dashboard.mothership.com / www.mothership.com/quote
- **验证**：脚本可执行；录制产出 goto URL 与 selector 可提取
---

## task-122

- **ID**：task-122
- **状态**：待执行
- **模块**：RPA
- **目标**：录制 SOP 与 env 产出 checklist
- **输入**：task-121；PRD §8.2.3 LA→Dallas 标准样例
- **输出**：`docs/rpa-recording-sop.md`；URL→`MOTHERSHIP_QUOTE_URLS`、selector→`RPA_SELECTOR_*` 映射表
- **实现范围**：文档化人工录制流程；不含自动化提取工具
- **验证**：人工 checklist：env 填齐 8 个 selector 后可跑 probe
---

"""

PHASE_5_V12 = """# Phase 5 — RPA v1.2 重构（PRD v0.6）

> 执行顺序：task-123 → task-124 → task-125 → task-126 → task-127 → task-128 → task-129 → task-130 → task-131  
> **里程碑 M2（v1.2）**：`RPA_MOCK_MODE=false` 下 `scripts/probe-rpa.ts` 连续 3 次 exit 0，四档 `source_type=rpa`。

## task-123

- **ID**：task-123
- **状态**：待执行
- **模块**：RPA
- **目标**：实现 QuotePageAdapter 多 URL 探测
- **输入**：技术设计 §7.2.3 CHG-T05/T06；task-122
- **输出**：`workers/rpa/quote-page-adapter.ts`：`resolveQuoteEntry` / `preCheck` / `isLoginWithoutCredentials`
- **实现范围**：按 `MOTHERSHIP_QUOTE_URLS` 顺序 goto + preCheck；全失败 → QUOTE_ENTRY_UNAVAILABLE
- **验证**：单测 mock 多 URL；首个可用 URL 写入 activeUrl；全失败抛 QUOTE_ENTRY_UNAVAILABLE
---

## task-124

- **ID**：task-124
- **状态**：待执行
- **模块**：RPA
- **目标**：storageState 生命周期（§7.5）
- **输入**：技术设计 §7.5 CHG-T09；task-120
- **输出**：重构 `workers/rpa/session-manager.ts`：`createContext` load、`persistContext` writeback、`invalidateStorageState`
- **实现范围**：成功查价写回；login 无凭据先 invalidate 再重试 goto
- **验证**：单测：存在 state 文件时 load；成功后 persist；invalidate 删除文件
---

## task-125

- **ID**：task-125
- **状态**：待执行
- **模块**：RPA
- **目标**：地址联想 selector env 化
- **输入**：技术设计 §7.2.1 CHG-T07；task-123
- **输出**：`workers/rpa/mothership.ts` `fillAddress` 改用 `RPA_SELECTOR_PICKUP/DELIVERY/ADDRESS_SUGGESTION`
- **实现范围**：失败 → ADDRESS_SUGGESTION_NOT_FOUND；不重试
- **验证**：mock 页面：联想成功锁定；无下拉 → ADDRESS_SUGGESTION_NOT_FOUND
---

## task-126

- **ID**：task-126
- **状态**：待执行
- **模块**：RPA
- **目标**：表单填写与提交 selector env 化
- **输入**：技术设计 §7.2 CHG-T07；task-125
- **输出**：`fillCargo` + submit 改用 `RPA_SELECTOR_SUBMIT` 等 env
- **实现范围**：移除硬编码 data-testid；全部读 `process.env.RPA_SELECTOR_*`
- **验证**：录制回放：字段填入正确；submit 点击成功
---

## task-127

- **ID**：task-127
- **状态**：待执行
- **模块**：RPA
- **目标**：四档抓取 selector env 化
- **输入**：技术设计 §7.2 步骤 7 CHG-T07；task-126
- **输出**：`scrapeQuotes` 改用 `RPA_SELECTOR_STANDARD/GUARANTEED/LOWEST/FASTEST/PRICE`
- **实现范围**：standard/guaranteed × lowest/fastest 各抓取一次；items.length===4
- **验证**：mock 结果页返回 4 档；每档 rawFreight>0
---

## task-128

- **ID**：task-128
- **状态**：待执行
- **模块**：RPA
- **目标**：错误分类 v0.6（入口 vs 抓取）
- **输入**：PRD §5.6 §11.5 CHG-P03/P04；技术设计 §7.3 CHG-T08
- **输出**：`workers/rpa/error-mapper.ts` + job-handler：QUOTE_ENTRY_UNAVAILABLE；login 无凭据 → STRUCT_CHANGE
- **实现范围**：入口/地址错误不重试；SESSION_EXPIRED 仅已配置凭据且曾成功登录
- **验证**：单测各错误分支映射；QUOTE_ENTRY_UNAVAILABLE 不触发 job 重试
---

## task-129

- **ID**：task-129
- **状态**：待执行
- **模块**：Quote Engine
- **目标**：Fallback 入口错误处理
- **输入**：PRD §2.5 CHG-P03；task-128
- **输出**：增补 `modules/quote/fallback-orchestrator.ts`：入口类错误不消耗 RPA job 重试配额
- **实现范围**：QUOTE_ENTRY_UNAVAILABLE / ADDRESS_SUGGESTION_NOT_FOUND 直接走 L3 或 400
- **验证**：单测：入口错误 job attempts=1；PAGE_LOAD_TIMEOUT 仍可重试 1 次
---

## task-130

- **ID**：task-130
- **状态**：待执行
- **模块**：RPA
- **目标**：升级 probe 探针（连续 3 次 exit 0）
- **输入**：PRD TC-601 §12.7 CHG-P08/P09；技术设计 CHG-T02
- **输出**：升级 `scripts/probe-rpa.ts` + `scripts/probe-rpa-3x.sh`；断言 items.length===4
- **实现范围**：`RPA_MOCK_MODE=false` 真实探测；3x 脚本循环调用
- **验证**：`bash scripts/probe-rpa-3x.sh` 连续 3 次 exit 0；输出 4 档 JSON
---

## task-131

- **ID**：task-131
- **状态**：待执行
- **模块**：RPA
- **目标**：Patchright 可选驱动（P1）
- **输入**：技术设计 §6.2 `RPA_USE_PATCHRIGHT` CHG-T03
- **输出**：`workers/rpa/session-manager.ts` 支持 `RPA_USE_PATCHRIGHT=true` 切换浏览器
- **实现范围**：默认 Playwright；Patchright 为可选降级路径
- **验证**：`RPA_USE_PATCHRIGHT=true` 时 worker 启动无报错；false 时行为不变
---

"""

TASK_132 = """## task-132

- **ID**：task-132
- **状态**：待执行
- **模块**：Frontend
- **目标**：实现 /admin/queues Bull Board 队列监控页（P1）
- **输入**：技术设计 §8.2 CHG-T10；task-021
- **输出**：`app/admin/queues/page.tsx` + Bull Board 挂载；admin RBAC
- **实现范围**：展示 quote-rpa 队列深度、失败 job、延迟；文案全中文
- **验证**：admin → 页面渲染队列指标；非 admin → 403
---

"""

TASK_133_135 = """## task-133

- **ID**：task-133
- **状态**：待执行
- **模块**：Test
- **目标**：TC-601 修订（四档 + probe 对齐 PRD v0.6）
- **输入**：PRD TC-601 CHG-P08；task-130
- **输出**：修订 `e2e/rpa.test.ts` / `__tests__/integration/rpa-probe.test.ts`；items=4 断言
- **实现范围**：mock 关闭时 probe 四档；文档对齐 v0.6 口径
- **验证**：TC-601 items.length===4；非 2 条
---

## task-134

- **ID**：task-134
- **状态**：待执行
- **模块**：Test
- **目标**：Go-No-Go probe 3/3 门禁
- **输入**：PRD §12.7 CHG-P09；task-130
- **输出**：`scripts/go-no-go-check.ts` 增 probe 3/3 条件（`RPA_MOCK_MODE=false` 时启用）
- **实现范围**：probe 失败 → Go-No-Go FAIL；mock 模式跳过 probe 门禁
- **验证**：mock 模式 PASS；真实 env 下 probe 3/3 才 PASS
---

## task-135

- **ID**：task-135
- **状态**：待执行
- **模块**：Test
- **目标**：CI nightly probe 步骤
- **输入**：task-134；task-118
- **输出**：`.github/workflows/e2e-nightly.yml` 可选 headed probe 步骤（secrets 配 MOTHERSHIP env）
- **实现范围**：nightly 不阻断 merge；probe 失败上传 artifact
- **验证**：workflow 语法有效；secrets 缺失时跳过 probe 步骤
---

"""

HEADER_V12 = """# 查价系统 工程任务拆解清单 v1.2

| 版本 | 日期 | 说明 |
|------|------|------|
| v1.0 | 2026-06-16 | 首版原子任务拆解 |
| v1.1 | 2026-06-16 | 对照 Traceability Matrix 补齐；口径对齐 PRD v0.4 |
| v1.1.1 | 2026-06-16 | **按推荐开发依赖顺序重排任务章节**（非 Task ID 数字序） |
| v1.2 | 2026-06-16 | 对齐 PRD v0.6 + 技术设计 v1.2；基线 001–118 已完成；增量 119–135 |

> **当前版本请使用本文件（v1.2）。** v1.1 文件保留作历史对照。

> 配套文档：[查价系统-PRD.md](./查价系统-PRD.md)（v0.6）· [查价系统-技术设计.md](./查价系统-技术设计.md)（v1.2）· [查价系统-UI设计.md](./查价系统-UI设计.md) · [查价系统-Traceability-Matrix-v1.0.md](./查价系统-Traceability-Matrix-v1.0.md)  
> **v1.1 基线（task-001~118，除废止）= 已完成；v1.2 增量（task-119~135）= PRD v0.6 + 技术设计 v1.2 待交付。**

---

## 开发顺序总览（自上而下执行）

| Phase | 名称 | Task 序列 | 状态 |
|-------|------|-----------|------|
| 0 | 环境与底座 | 072→073→**119→120**→070→071→097→030 | 072–030 已完成；119–120 待执行 |
| 1 | 基础设施与缓存 | 096→031~036→035-ip | 已完成 |
| 2 | 鉴权 | 001~005→098 | 已完成 |
| 3 | 领域逻辑 | 040~044→010~014,092,095,109,111,019 | 已完成 |
| 4 | API 层 | 015~017→042~043→018 | 已完成 |
| 5.0 | RPA 录制前置 | **121→122** | 待执行 |
| 5 | RPA v1.2 重构 | **123→131**（基线 020–029,110,093,099,100 已完成） | 123–131 待执行 |
| 6 | 预警/审计 | 050~057→094→105 | 已完成 |
| 7 | 观测指标 | 101→102 | 已完成 |
| 8 | 前端 | 060~069→106→063,064,079,103,104→**132**→080 | 132 待执行 |
| 9 | 测试/CI | 081~118→**133→135**→091 | 133–135 待执行 |
| — | 已废止 | 075~078 | — |

**里程碑 M1（Phase 0~4）**：已完成 — `POST /quotes` L2 命中、幂等、校验 400。  
**里程碑 M2（v1.2）**：`RPA_MOCK_MODE=false` 下 `scripts/probe-rpa.ts` **连续 3 次 exit 0**，四档 `source_type=rpa`（TC-601 + §12.7 Go/No-Go）。

---

## 模块索引（按职能归类，非执行顺序）

| 模块 | Task ID | 数量 |
|------|---------|------|
| 数据库（DB） | 070–073 | 4 |
| 基础设施（Lib） | 096–098, **119–120** | 5 |
| 缓存系统 | 030–036, 035-ip | 8 |
| 用户系统（Auth） | 001–005 | 5 |
| 加价系统（Markup） | 040–044 | 5 |
| 查价核心（Quote Engine） | 010–019, 092, 095, 109, 111, **129** | 15 |
| API 路由 | 015–018, 042–043 | 6 |
| RPA 系统 | 020–029, 093, 099–100, 110, **121–131** | 23 |
| 预警系统（Alert） | 050–057, 094, 105 | 10 |
| 观测与指标 | 101–102 | 2 |
| 前端 UI | 060–080, 103–104, 106, **132** | 19 |
| 测试系统 | 081–091, 112–118, **133–135** | 21 |
| **合计（可执行）** | | **~119** |
| **已废止** | 075–078 | 4 |

## 技术栈约定

- Next.js 15 App Router + TypeScript
- MySQL 8.0 + Prisma ORM
- Redis 7 + BullMQ
- Playwright（RPA Worker）
- Tailwind CSS + shadcn/ui + phosphor-icons

## v1.1 口径冻结（对齐 PRD v0.4，基线已完成）

| 决策 | 规则 | 任务影响 |
|------|------|----------|
| GD-11 嵌入形态 | 查价 UI 为**宿主内嵌组件**，中台仅 admin 管理端 | task-106 替代 075–077；task-064 仅 admin |
| §2.3 加价配置 | 中台**不提供**运营加价 UI，由宿主调 API | task-078 **废止**；task-042/043 保留 |
| 四档报价 | GD-1/TC-102 为准（quotes=4） | task-088/111 按 4 档验收 |
| Fallback | 独立 FallbackOrchestrator 模块 | task-092 |
| 管理端 RPA | §3.1 预警 + RPA/开发进度 | task-093, 103, 104 |
| audit / metrics | §10.6 audit log + GD-4 三率 | task-094, 101, 102, 117 |

## v1.2 口径冻结（对齐 PRD v0.6 / 技术设计 v1.2）

| 决策 | 规则 | 任务影响 |
|------|------|----------|
| GD-15 入口 URL | `MOTHERSHIP_QUOTE_URLS` headed 录制；禁止 dashboard / `/quote` | task-119, 121, 122, 123 |
| 入口 vs 抓取错误 | 入口错误与抓取错误分开分类；地址未锁定单独处理 | task-125, 128, 129 |
| 新错误码 | `QUOTE_ENTRY_UNAVAILABLE`、`ADDRESS_SUGGESTION_NOT_FOUND` | task-128, 110（基线） |
| QuotePageAdapter | 多 URL 探测 + storageState + login 无凭据→STRUCT_CHANGE | task-123, 124 |
| Selector env 化 | 全部 `RPA_SELECTOR_*`，禁止手猜 selector | task-125–127 |
| probe 门禁 | 连续 3 次 exit 0 + 四档 | task-130, 133–135 |
| Bull Board | `/admin/queues` 队列监控（P1） | task-132 |

## v1.0 → v1.1 变更摘要

| 类型 | Task | 说明 |
|------|------|------|
| 新增 | 092–118（除重复编号） | 见各 Phase 章节 |
| 修订 | 005, 014, 016, 018, 029, 050, 064, 065, 066, 079, 085, 091 | 补 RBAC/置信度/Fallback 引用等 |
| 废止 | 075, 076, 077, 078 | PRD v0.4 口径下不交付 |
| 替代 | 106 | 宿主内嵌查价组件（替代 075） |
| 排序 | v1.1.1 | 正文按 Phase 0→9 开发顺序排列 |

## v1.1 → v1.2 变更摘要

| CHG ID | 类型 | Task | 说明 |
|--------|------|------|------|
| CHG-P02/T03 | 新增 | 119, 121, 122 | GD-15 env + 录制前置 |
| CHG-T04 | 新增 | 120 | docker rpa_state volume |
| CHG-P05/T05/T06 | 新增 | 123 | QuotePageAdapter |
| CHG-T09 | 新增 | 124 | storageState 生命周期 |
| CHG-T07 | 新增 | 125–127 | selector env 化 |
| CHG-P03/P04/T08 | 新增 | 128, 129 | 错误分类 v0.6 |
| CHG-P08/T02 | 新增 | 130 | probe 3/3 |
| CHG-T03 P1 | 新增 | 131 | Patchright 可选 |
| CHG-T10 | 新增 | 132 | /admin/queues Bull Board |
| CHG-P08/P09 | 新增 | 133–135 | TC-601 + Go-No-Go + CI |
| — | 状态 | 001–118 | 全部标「已完成」（废止除外） |
| — | 说明 | 022, 023, 028, 073, 110, 117, 088 | 基线已实现；行为变更由 task-12x 承接 |

---

"""

APPENDIX_A = """## 附录 A：验收用例 → Task 映射（v1.2 全覆盖）

| TC | 主验证 Task | 辅助 Task |
|----|-------------|-----------|
| TC-101~108 | 085, 112 | 014, 032, 013, 011, 012 |
| TC-201~204 | 082, 010 | — |
| TC-205~206 | 115, 092, **129** | 052, 053 |
| TC-207 | 084, 013 | — |
| TC-208~209 | 018, 028, 036, **128** | 092 |
| TC-210~212 | 087, 051 | — |
| TC-301~304 | 090, 018, 021 | — |
| TC-401 | 113 | 032, 051 |
| TC-402~404 | 084, 019 | 013 |
| TC-403 | 114 | 041 |
| TC-501~506 | 086, 094, 035-ip | 004, 010 |
| TC-601~605 | 088, 115, **130, 133** | 026, 027, 092, 123–127 |
| Go-No-Go | 117, 101, 102, **134** | 090, **130** |
| probe 3/3 | **130, 134, 135** | 121, 122 |

---

"""

APPENDIX_B = """## 附录 B：完整性矩阵（PRD v0.6 + 技术设计 v1.2）

### B.1 维度覆盖

| 维度 | v1.1 基线 Task | v1.2 增量 Task |
|------|----------------|----------------|
| PRD 功能点 | 001–118（除废止） | GD-15(119–122)、错误码(128–129)、probe(130,133–135)、Bull Board(132) |
| 技术模块 | 各 Phase 已覆盖 | quote-page-adapter(123)、storageState(124)、selector env(125–127)、probe(130) |
| UI 页面 | 106 + admin 6 页 | `/admin/queues`(132) |
| API（§8.5 七接口 + RPA admin） | 015–018, 042–043, 056–057, 029/093/099/100 | 无新增 REST |
| 数据表（6 张） | 070–073 | 无新增表 |

### B.2 PRD v0.6 变更 → Task

| CHG ID | 章节 | Task |
|--------|------|------|
| CHG-P02 | GD-15 | 119, 121, 122 |
| CHG-P03 | §2.5 | 128, 129 |
| CHG-P04 | §5.6 | 128 |
| CHG-P05 | §8.2 | 123, 124 |
| CHG-P06 | §8.2.1~8.2.3 | 119, 121, 122, 125–127 |
| CHG-P07 | §11.5 | 124, 128 |
| CHG-P08 | TC-601 | 130, 133 |
| CHG-P09 | §12.7 | 134, 135 |

### B.3 技术设计 v1.2 变更 → Task

| CHG ID | 章节 | Task |
|--------|------|------|
| CHG-T02 | §5 目录 | 121, 130 |
| CHG-T03 | §6.2 env | 119, 131 |
| CHG-T04 | §6.1 compose | 120 |
| CHG-T05~T07 | §7.2 | 123–127 |
| CHG-T08 | §7.3 | 128 |
| CHG-T09 | §7.5 | 124, 120 |
| CHG-T10 | §8.2 | 132 |
| CHG-T11~T12 | §9.2 | 121, 122 |

### B.4 v1.1 Traceability Matrix 缺口（已闭合，基线）

| Matrix 缺口 | Task |
|-------------|------|
| Fallback 编排无独立 Task | task-092, 115 |
| GET /api/rpa/status + /admin/rpa | task-093, 103 |
| audit log | task-070(schema), 094 |
| confidence_score | task-095 |
| lib/response.ts / lib/prisma.ts | task-096, 097 |
| GD-4 metrics | task-101, 102, 104, 117 |
| IP 限流 | task-035-ip |
| 503 retry | task-098 |
| 管理员暂停 RPA | task-099, 103 |
| 人工兜底录入 | task-100, 079 |
| display_unit | task-065 |
| 客户端退避 | task-066 |
| 宿主嵌入 vs 独立页 | task-106（废止 075~077） |
| 中台加价 UI 漂移 | 废止 078 |
| TC-108/302/401/403 | task-112~114 |
| quote_id 冲突 | task-109 |
| CARRIER/ADDRESS 错误码 | task-110 |
| BR-5.5 四档齐全 | task-111 |
| SESSION_EXPIRED/SECURITY | task-105 |
| rpa:operate RBAC | task-005 |
"""


def task_num_from_heading(line: str) -> int | None:
    m = re.match(r"^## (?:~~)?task-(\d+)", line)
    return int(m.group(1)) if m else None


def process_task_block(block: str, num: int) -> str:
    if num in ABOLISHED:
        return block

    lines = block.split("\n")
    out: list[str] = []
    id_inserted = False
    for line in lines:
        out.append(line)
        if not id_inserted and line.startswith("- **ID**："):
            out.append("- **状态**：已完成")
            id_inserted = True

    if num in V12_NOTE_TASKS:
        inserted = False
        for i, line in enumerate(out):
            if (
                line.strip() == "---"
                and i + 2 < len(out)
                and out[i + 1].strip() == ""
                and out[i + 2].startswith("## task-")
            ):
                out.insert(i, "")
                out.insert(i, "- **v1.2 说明**：基线已实现；行为变更由 task-12x 承接")
                inserted = True
                break
        if not inserted:
            out.append("")
            out.append("- **v1.2 说明**：基线已实现；行为变更由 task-12x 承接")

    return "\n".join(out)


def split_tasks(body: str) -> list[tuple[str | None, str]]:
    """Split body into (task_num, block) segments. task_num None for non-task blocks."""
    parts = re.split(r"(?=^## (?:~~)?task-\d+)", body, flags=re.MULTILINE)
    result: list[tuple[str | None, str]] = []
    for part in parts:
        if not part.strip():
            continue
        first_line = part.split("\n", 1)[0]
        num = task_num_from_heading(first_line)
        result.append((num, part))
    return result


def main() -> None:
    src_text = SRC.read_text(encoding="utf-8")

    # Find where Phase 0 body starts (after header section)
    phase0_marker = "# Phase 0 — 环境与底座"
    idx = src_text.find(phase0_marker)
    if idx < 0:
        raise SystemExit("Phase 0 marker not found")

    header_old = src_text[:idx]
    body = src_text[idx:]

    # Split appendices
    appendix_a_marker = "## 附录 A："
    app_idx = body.find(appendix_a_marker)
    if app_idx < 0:
        raise SystemExit("Appendix A not found")
    task_body = body[:app_idx]

    # Update Phase 0 header line
    task_body = task_body.replace(
        "> 执行顺序：task-072 → task-073 → task-070 → task-071 → task-097 → task-030",
        "> 执行顺序：task-072 → task-073 → **task-119 → task-120** → task-070 → task-071 → task-097 → task-030",
        1,
    )

    # Process tasks and rebuild
    segments = split_tasks(task_body)
    rebuilt: list[str] = []
    i = 0
    while i < len(segments):
        num, block = segments[i]
        if num is None:
            rebuilt.append(block)
            i += 1
            continue

        processed = process_task_block(block, num)

        # Insert 119-120 before task-070 (after task-073 section)
        if num == 70:
            rebuilt.append(TASK_119_120)

        # Phase 5.0 header + 121-122 before baseline; v1.2 block after task-100
        if num == 18:
            processed = processed.replace(
                "# Phase 5 — RPA（W2）",
                "# Phase 5.0 — RPA 录制前置（W2 前置，CHG-T11/T12）\n\n"
                "> 执行顺序：task-121 → task-122  \n"
                "> **必须在 task-123 之前完成**：无 env 则 adapter/probe 无法验收。\n\n"
                + TASK_121_122
                + "\n# Phase 5 — RPA 基线（W2，已完成）",
                1,
            )
            processed = processed.replace(
                "> 执行顺序：task-020 → task-021 → task-022 → task-023 → task-024 → task-025 → task-026 → task-027 → task-028 → task-110 → task-029 → task-093 → task-099 → task-100",
                "> 执行顺序：task-020 → … → task-100（**全部已完成**；v1.2 增量见下方 Phase 5 v1.2 重构）",
                1,
            )

        if num == 100:
            phase6_marker = "\n# Phase 6 — 预警"
            if phase6_marker in processed:
                processed = processed.replace(
                    phase6_marker,
                    "\n\n" + PHASE_5_V12.rstrip() + "\n\n" + phase6_marker.lstrip("\n"),
                    1,
                )
            else:
                processed = processed + "\n\n" + PHASE_5_V12

        rebuilt.append(processed)

        if num == 104:
            rebuilt.append(TASK_132)

        if num == 118:
            rebuilt.append(TASK_133_135)

        i += 1

    final_body = "".join(rebuilt)
    final_text = HEADER_V12 + final_body + APPENDIX_A + APPENDIX_B + "\n"

    DST.write_text(final_text, encoding="utf-8")
    print(f"Wrote {DST} ({len(final_text)} chars)")


if __name__ == "__main__":
    main()
