You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
22 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/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-121PRD §8.2.3 LA→Dallas 标准样例
- **输出**`docs/rpa-recording-sop.md`URL→`MOTHERSHIP_QUOTE_URLS`、selector→`RPA_SELECTOR_*` 映射表
- **实现范围**:文档化人工录制流程;不含自动化提取工具
- **验证**:人工 checklistenv 填齐 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
> **里程碑 M2v1.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/T06task-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-T09task-120
- **输出**:重构 `workers/rpa/session-manager.ts``createContext` load、`persistContext` writeback、`invalidateStorageState`
- **实现范围**成功查价写回login 无凭据先 invalidate 再重试 goto
- **验证**:单测:存在 state 文件时 load成功后 persistinvalidate 删除文件
---
## task-125
- **ID**task-125
- **状态**:待执行
- **模块**RPA
- **目标**:地址联想 selector env 化
- **输入**:技术设计 §7.2.1 CHG-T07task-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-T07task-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-T07task-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-handlerQUOTE_ENTRY_UNAVAILABLElogin 无凭据 → STRUCT_CHANGE
- **实现范围**:入口/地址错误不重试SESSION_EXPIRED 仅已配置凭据且曾成功登录
- **验证**单测各错误分支映射QUOTE_ENTRY_UNAVAILABLE 不触发 job 重试
---
## task-129
- **ID**task-129
- **状态**:待执行
- **模块**Quote Engine
- **目标**Fallback 入口错误处理
- **输入**PRD §2.5 CHG-P03task-128
- **输出**:增补 `modules/quote/fallback-orchestrator.ts`:入口类错误不消耗 RPA job 重试配额
- **实现范围**QUOTE_ENTRY_UNAVAILABLE / ADDRESS_SUGGESTION_NOT_FOUND 直接走 L3 或 400
- **验证**:单测:入口错误 job attempts=1PAGE_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` 切换浏览器
- **实现范围**:默认 PlaywrightPatchright 为可选降级路径
- **验证**`RPA_USE_PATCHRIGHT=true` 时 worker 启动无报错false 时行为不变
---
"""
TASK_132 = """## task-132
- **ID**task-132
- **状态**:待执行
- **模块**Frontend
- **目标**:实现 /admin/queues Bull Board 队列监控页P1
- **输入**:技术设计 §8.2 CHG-T10task-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-P08task-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-P09task-130
- **输出**`scripts/go-no-go-check.ts` 增 probe 3/3 条件(`RPA_MOCK_MODE=false` 时启用)
- **实现范围**probe 失败 → Go-No-Go FAILmock 模式跳过 probe 门禁
- **验证**mock 模式 PASS真实 env 下 probe 3/3 才 PASS
---
## task-135
- **ID**task-135
- **状态**:待执行
- **模块**Test
- **目标**CI nightly probe 步骤
- **输入**task-134task-118
- **输出**`.github/workflows/e2e-nightly.yml` 可选 headed probe 步骤secrets 配 MOTHERSHIP env
- **实现范围**nightly 不阻断 mergeprobe 失败上传 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;基线 001118 已完成;增量 119135 |
> **当前版本请使用本文件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 | 072030 已完成119120 待执行 |
| 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**(基线 020029,110,093,099,100 已完成) | 123131 待执行 |
| 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 | 133135 待执行 |
| — | 已废止 | 075~078 | — |
**里程碑 M1Phase 0~4**:已完成 — `POST /quotes` L2 命中、幂等、校验 400。
**里程碑 M2v1.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 | 070073 | 4 |
| 基础设施Lib | 096098, **119120** | 5 |
| 缓存系统 | 030036, 035-ip | 8 |
| 用户系统Auth | 001005 | 5 |
| 加价系统Markup | 040044 | 5 |
| 查价核心Quote Engine | 010019, 092, 095, 109, 111, **129** | 15 |
| API 路由 | 015018, 042043 | 6 |
| RPA 系统 | 020029, 093, 099100, 110, **121131** | 23 |
| 预警系统Alert | 050057, 094, 105 | 10 |
| 观测与指标 | 101102 | 2 |
| 前端 UI | 060080, 103104, 106, **132** | 19 |
| 测试系统 | 081091, 112118, **133135** | 21 |
| **合计(可执行)** | | **~119** |
| **已废止** | 075078 | 4 |
## 技术栈约定
- Next.js 15 App Router + TypeScript
- MySQL 8.0 + Prisma ORM
- Redis 7 + BullMQ
- PlaywrightRPA Worker
- Tailwind CSS + shadcn/ui + phosphor-icons
## v1.1 口径冻结(对齐 PRD v0.4,基线已完成)
| 决策 | 规则 | 任务影响 |
|------|------|----------|
| GD-11 嵌入形态 | 查价 UI 为**宿主内嵌组件**,中台仅 admin 管理端 | task-106 替代 075077task-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-125127 |
| probe 门禁 | 连续 3 次 exit 0 + 四档 | task-130, 133135 |
| Bull Board | `/admin/queues` 队列监控P1 | task-132 |
## v1.0 → v1.1 变更摘要
| 类型 | Task | 说明 |
|------|------|------|
| 新增 | 092118除重复编号 | 见各 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 | 新增 | 125127 | 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 | 新增 | 133135 | TC-601 + Go-No-Go + CI |
| — | 状态 | 001118 | 全部标「已完成」(废止除外) |
| — | 说明 | 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, 123127 |
| 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 功能点 | 001118除废止 | GD-15(119122)、错误码(128129)、probe(130,133135)、Bull Board(132) |
| 技术模块 | 各 Phase 已覆盖 | quote-page-adapter(123)、storageState(124)、selector env(125127)、probe(130) |
| UI 页面 | 106 + admin 6 页 | `/admin/queues`(132) |
| API§8.5 七接口 + RPA admin | 015018, 042043, 056057, 029/093/099/100 | 无新增 REST |
| 数据表6 张) | 070073 | 无新增表 |
### 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, 125127 |
| 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 | 123127 |
| 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 — RPAW2",
"# 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()