# CodePlanet 项目目标与架构终点

> **文档性质**：平台级「北极星」——描述视觉检测设备的终态架构、模块边界与演进路线。  
> **当前基线**：运维工具（Ops）`CodeEditor.exe`，AST 运行时 P0～P5 已结案（见 `docs/AST审计执行报告/`）。  
> **版本**：v1.5（2026-05-24）  
> **状态**：Q1～Q10、**T1～T38** 已确认；**R0/R1/R1.5/R2 已结案**（见各阶段交付报告）；R3 目标冻结。

---

## 1. 愿景与定位

### 1.1 业务目标

本项目面向 **工业视觉检测设备**：多相机硬触发采集 → 传统图像处理（OpenCV / HALCON）→ 深度学习模型（Python 统一 runner）→ IO/通讯联动 → **跨工位/跨相机汇总判定**（如多路 OK 后驱动下一气缸）。

**一台设备可挂载多个产品项目**（不同相机参数、脚本、模型），通过 **切换 yslib 项目** 统一管理，而非「一条线一个软件」。

### 1.2 平台与环境（T1:A）

| 项 | 决策 |
|----|------|
| 目标 OS | **Windows 10 / 11 x64 工控机**（首期不支持 Linux / IoT） |
| 编译 | MSVC + Qt 5.11+（与现仓库一致） |
| 部署根 | 安装包根目录下 `{InstallRoot}/`（见 §3.4） |

### 1.3 三端产品形态（Ops + Runtime + Launcher）

| 产品 | exe（规划名） | 角色 |
|------|----------------|------|
| **启动器（Launcher）** | `CodePlanetr.exe` | 启动前 **预检**、监控 Runtime 启动、完整性/版本/更新；**避免静默闪退**（**T7**） |
| **运行软件（Runtime）** | `CodeRuntime.exe` | 产线运行：加载 yslib、多相机硬触发、主/子任务、状态 UI |
| **运维工具（Ops）** | `CodeEditor.exe` | 项目树、编辑 `.ys`/`.yslib`、调试脚本、Ctrl+B |

三者共享 **`core` / `services` / 插件接口**，单 monorepo（**Q1:A**）。  
**产线默认入口**：桌面/开机自启 → **Launcher** → 通过预检后 **拉起 Runtime**；工程师维护走 **Ops**。

### 1.4 终态模块（可独立发版）

| 模块 | 形态 | 职责 |
|------|------|------|
| **启动器** | `CodePlanetr.exe` | 项目完整性、插件清单、版本/更新、Runtime 监护与日志（§1.5） |
| **运行软件** | `CodeRuntime.exe` | 多相机硬触发、主/子任务、汇总与 IO |
| **运维工具** | `CodeEditor.exe` | 项目树、多 tab、yslib JSON 编辑 |
| **硬件驱动** | `plugins/hardware/*` | 多相机、光源、IO |
| **通讯配置** | `plugins/comm/*` | Modbus/TCP/串口 + 写队列 |
| **模型配置** | `plugins/models/*` | 统一 Python runner + `config.yaml`（**T4:B**） |
| **算法库** | `plugins/algorithms/opencv`、`halcon` | 含 XLD/HOBJECT（§4） |
| **共享 core** | 库 + 源码 | AST、VisionObject、yslib、GlobalBroker、ProjectValidator |

### 1.5 启动器 Launcher（T7 — 独立 exe）

**背景**：Runtime 启动需加载 yslib、多插件、相机/模型/通讯，任一步失败若 **无界面直接闪退**，现场无法定位。Launcher 作为 **轻量、稳定、先启动** 的壳，专门做「能启动再启动」。

| 能力 | 说明 |
|------|------|
| **项目完整性** | 校验 yslib JSON Schema；`scripts[]` 路径存在；`assets/`、`models/` 引用有效；相对路径可解析 |
| **核心插件清单** | 对照 yslib / 清单 manifest，检查 `bin/plugins/` 必需 DLL 是否存在、Qt 版本匹配 |
| **预加载探测** | 可选：Python 环境、相机 SDK 注册、关键 DLL `LoadLibrary` 烟雾测试（不初始化重型硬件） |
| **启动 Runtime** | `CreateProcess` 拉起 `CodePlanetRuntime.exe --project <yslib>`；捕获 **退出码**；超时未出现主窗口则报错 |
| **监护与日志** | Runtime 崩溃/快速退出 → Launcher **弹窗 + 写 `%AppData%/CodePlanet/launcher.log`**；可选 mini dump 路径提示 |
| **版本与更新（T13:B + T21）** | **在线** + **U 盘离线**（见 §3.5）；项目 zip + manifest 校验后解压覆盖（保留 `logs/`） |
| **崩溃诊断（T14:B）** | 记录 **exit code**；引导查看 `launcher.log` / Runtime 日志；启用 **Windows mini dump**（`%AppData%/CodePlanet/dumps/`） |
| **换型** | 用户选择 `projects/` 下另一 yslib → 预检通过 → **结束旧 Runtime 进程** → 启动新 Runtime（**T7:A 重启**） |
| **开机自启（T19:B）** | 仅 **Launcher** 注册开机自启；**禁止** 产线绕过 Launcher 直启 Runtime |
| **启动倒计时与修复模式（T19:B）** | 自启后 **5 秒倒计时** 再进入预检/拉起 Runtime；倒计时内按 **F8** → **修复模式**（见下） |

**修复模式（T22:B）**（F8 进入，R1.5）：

- 手动选择/切换 **yslib 项目**；打开 **日志 / dump** 目录  
- **可跳过「核心插件清单」预检**，在用户确认风险后 **仍拉起 Runtime**（其它项如 yslib 可读性默认保留）  
- **不自动倒计时启动**；由用户点击「启动 Runtime」  
- **不含** 内置 yslib 编辑器（编辑走 Ops）  

**Runtime 启动约束（T27:B + T28:C）**：Launcher 拉起时传入 `--parent-pid=<launcherPid>`（或等价令牌）；Runtime 校验 **父进程为 Launcher**，否则拒绝启动。  
**开发豁免（T28:C）**：设置环境变量 **`CODEPLANET_DEV=1`** 时（Ops 调试、本机开发），**跳过** 父进程校验；产线 Launcher **不得** 注入该变量。

**R1.5 已交付补充（2026-05-24）**：

- 启动参数 `--project=` → Ops 自动打开 yslib；`ParentProcessGuard` + nonce 统一 `%LOCALAPPDATA%/CodePlanet/`
- 仓库布局 / `CODEPLANET_DEV=1` 下可回退拉起 `CodePlanet.exe`（仍经 Launcher 注入 parent/nonce）
- `UiLocaleService`：Launcher 与 Ops 共用 `ui/locale`；Launcher 右上角 CH/EN 切换；**启动 Runtime 时附加 `--locale=zh_CN|en`（点击「立即启动」快照，Runtime 进程内不再随 Launcher 切换）**
- 本地 staging：`scripts/deploy_staging.ps1` → `dist/CodePlanet/bin/`（gitignore）
- 更新检查：U 盘优先 → HTTPS `manifest.json` → RSA 验签；**Apply 下载/解压留 R3**

**完整性校验（T17:A）**：Launcher 与 Ops **共用** `ProjectValidator`（`src/core/project/`），Ctrl+B 与启动预检 **同一套规则**。

**不做的事**：Launcher **不** 跑 AST、不采图、不替代 Runtime；保持 exe 小、依赖少，降低「守门人也崩溃」的概率。

```mermaid
flowchart LR
    User[操作员/开机] --> L[CodePlanetLauncher]
    L --> V[完整性/插件/版本预检]
    V -->|失败| Err[对话框 + 日志]
    V -->|通过| R[CodePlanetRuntime.exe]
    R -->|异常退出| L
    Eng[工程师] --> Ops[CodePlanetOps.exe]
```

**与 `app_settings` 关系**：Launcher 与 Runtime 共用 SQLite；`default_project_path` 由 Launcher 或 Ops 写入。

---

## 2. 已确认战略选型

### 2.1 Q1～Q10（架构）

| 编号 | 决策 | 说明 |
|------|------|------|
| Q1 | A monorepo | 共享 core，Ops/Runtime 分 exe |
| Q2 | A 首里程碑 Ops 产品化 | 项目树 + yslib（R1） |
| Q3 | A yslib = **JSON** | Schema + Ctrl+B |
| Q4 | A 默认项目 → **`app_settings` 表** | 指针指向 yslib 路径 |
| Q5 | B Python **常驻 Worker + IPC** | |
| Q6 | A OpenCV/HALCON **独立插件** + ImageRuntime | |
| Q7 | A 每任务 **RuntimeWorker** + **global 跨任务通讯** | §5 |
| Q8 | Modbus **独立线程 + 写队列** | §6 |
| Q9 | A R0 参数/CI；拆 lib 跟 R2 | |
| Q10 | C Python 开发明文 / 量产加密 | §7 |

### 2.2 T1～T6（产品与数据）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T1** | **A** | Win10/11 x64 工控机 |
| **T2** | **完整项目** | 一 yslib = **一整台设备上的完整检测方案**；**多工位、多相机** 为常态；需显式建模 **跨相机/跨工位数据汇总**（§5.3） |
| **T3** | **A** | **硬触发为主**；子任务默认由相机触发，未绑定子任务的相机触发后不执行脚本 |
| **T4** | **B** | **统一 Python runner + 每模型 `config.yaml`**，非每模型独立入口脚本 |
| **T5** | **见 §3.4** | 安装根下 `/projects/{project_name}/` 目录树（采纳并补充规范） |
| **T6** | **B** | 语言层新增 **`global` 关键字** → `ProjectGlobalStore` / GlobalBroker（与 `static` 区分，§5.2） |

### 2.3 T7～T12（启动、汇总、模块、资产）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T7** | **A + 独立 Launcher exe** | 非仅「重启 Runtime」：见 §1.5 预检、监护、版本/更新；通过后拉起 Runtime |
| **T8** | **A** | 子任务间 **不传图像/XLD**；仅 **global 标量/小结构** |
| **T9** | **A** | **主任务脚本手写汇总**；不用 yslib 自动 aggregate 引擎（§5.3 输送带论证） |
| **T10** | **A** | **IO/气缸仅主任务** 经 IO 插件 + Comm 写队列输出 |
| **T11** | **B** | **`import "path.ys"` 模块语法**；yslib 与任意 `.ys` 均可 import 同目录树内子脚本 |
| **T12** | **B** | 标定/ROI → `assets/*.json`（等），yslib **引用路径** |

### 2.4 T13～T20（更新、诊断、import、定时器、自启）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T13** | **B** | 在线更新以 **项目包 zip** 为主（产线换型/修脚本）；整包安装可选 |
| **T14** | **B** | Runtime 异常：**exit code + 日志 + Windows mini dump** |
| **T15** | **B** | `import` 允许 **`../shared/foo.ys`** 等跨任务目录；**禁止绝对路径** |
| **T16** | **不适用** | 原「epoch 清零平台信号」属 T9:B；现 **T9:A**，清零/对齐 **全部由主任务脚本** 实现，平台不配置 |
| **T17** | **A** | Launcher / Ops **共用 `ProjectValidator`** |
| **T18** | **B** | global 命名约定 **`{camId}_{metric}`** + Ops/静态 **linter 警告**（非强制白名单） |
| **T19** | **B** | 仅 Launcher 自启；**5 秒倒计时**；**F8 → 修复模式** |
| **T20** | **B** | **`import` 与 `#include` 过渡期并存**；`#include` = 文本展开，`import` = 模块符号表 |

### 2.5 T21～T27（更新源、修复模式、定时器、UI、语义、防绕过）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T21** | **A + C** | **在线** HTTPS 更新站 + **U 盘离线**；见 §3.5 |
| **T22** | **B** | 修复模式可 **跳过插件预检** 后启 Runtime |
| **T23** | **B** | 定时器用 **`QElapsedTimer` 单调时钟**，非墙钟 |
| **T24** | **B** | 定时器 id 为 **字符串名**（如 `"reject_pulse"`） |
| **T25** | **C** | Runtime UI：**日志 + global 表 + processGroups 树状状态**（R2 首期） |
| **T26** | **A** | **R1 一次性 breaking** 迁移；语义见 §5.2（用户最终定义） |
| **T27** | **B** | Runtime **无 Launcher 父进程则拒绝启动** |

### 2.6 T28～T34（开发豁免、更新策略、UI 细项、R0）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T28** | **C** | `CODEPLANET_DEV=1` 跳过 T27 父进程校验（仅开发） |
| **T29** | **B** | 更新 manifest / zip：**RSA 签名校验**（量产） |
| **T30** | **C** | manifest 含：**项目 zip + Runtime 安装包版本 + 插件 DLL 最低版本** |
| **T31** | **A+B（建议性更新）** | 更新 **非强制**；失败/跳过 → **提示可用 U 盘**；准备 U 盘前 **继续用旧版** 正常生产 |
| **T32** | **B** | processGroups 树叶节点：**global 值 + 子任务最后触发时间** |
| **T33** | **B** | 主任务 **`loopIntervalMs` 默认 20**（yslib 可改） |
| **T34** | **A** | 编写 **`R0-执行提示词.md`**（已创建） |

### 2.7 T35～T38（更新实施、Ops 首屏 — 已确认）

| 编号 | 决策 | 要点 |
|------|------|------|
| **T35** | **`resources/config/update.pub`** | RSA 公钥随安装包分发；`UpdateManifestVerifier` 读取此路径（R0 stub，R1.5 实装） |
| **T36** | **仅警告** | 插件/Runtime 版本 **低于** manifest 要求 → **Warning**，不阻断启动（与 T31 一致） |
| **T37** | **manifest + 1 个示例 zip** | `conbos.cn/CodePlanetr/Update/` 首批：`manifest.json` + 一个示例项目包（如 `demo-1.0.0.zip`）；Setup 包可后续追加 |
| **T38** | **B** | Ops 启动首屏：**最近打开的 yslib 列表**（+ 仍可浏览 `projects/` 树） |

---

## 3. 文件与项目模型

### 3.1 `.ys` — 脚本

- 程序逻辑；AST 管线不变。
- 可在项目目录内 **任意层级** 存放；由 yslib **登记路径与角色**。
- 模块：**`import "相对路径.ys"`**（**T11:B**）；路径相对 **当前 .ys 文件**（**T15:B**），允许 `import "../shared/align_utils.ys"`。
- **禁止** `import "C:/..."` 等绝对路径；静态检查报错。
- **`#include`**（**T20:B**）：预处理 **文本展开**，无模块隔离；与 `import` **并存**，新代码优先 `import`。
- 建议目录：`projects/{name}/shared/` 放跨任务公共脚本。
- Parser：模块表 + **循环依赖检测**；未在 yslib `scripts[]` 登记的 import 目标 → Ctrl+B **警告**。

### 3.2 `.yslib` — 项目清单（JSON）

**项目唯一真相源**（除运行时瞬态外）。包含：项目元信息、**全部脚本注册**、任务入口、**相机/工位/工艺组绑定**、硬件、模型、通讯。

路径：**一律相对 yslib 所在目录**（便于整包拷贝、换机）。

### 3.3 yslib 结构 v1（多相机 / 多工位）

```json
{
  "schemaVersion": 1,
  "project": {
    "name": "product_A",
    "displayName": "产品 A 检测方案",
    "createdAt": "2026-05-21T08:00:00Z",
    "customer": "…"
  },
  "layout": {
    "root": ".",
    "yslibFile": "product_A.yslib"
  },
  "scripts": [
    { "id": "main", "path": "taskmain_name.ys", "role": "main" },
    { "id": "sub_cyl1_camA", "path": "tasksub_cyl1/tasksub_cyl1.ys", "role": "sub" },
    { "id": "mod_helper", "path": "tasksub_cyl1/sub_name.ys", "role": "module" }
  ],
  "tasks": {
    "main": {
      "entryScriptId": "main",
      "loopIntervalMs": 20,
      "description": "汇总各工位/相机结果，驱动气缸2等（loopIntervalMs 默认 20，T33:B）"
    },
    "subs": [
      {
        "id": "sub_camA_cyl1",
        "entryScriptId": "sub_cyl1_camA",
        "trigger": { "type": "camera", "cameraId": "camA", "edge": "hardware" },
        "processGroup": "cylinder1_reject",
        "writesGlobals": ["camA_ok", "camA_seq"]
      }
    ]
  },
  "processGroups": [
    {
      "id": "cylinder1_reject",
      "description": "相机 A/B/C 负责气缸1 剔除逻辑（仅分组/文档/UI，不自动汇总）",
      "cameraIds": ["camA", "camB", "camC"]
    },
    {
      "id": "station_pair",
      "description": "D/E/F/G 负责两工位结果（汇总逻辑在主任务脚本）",
      "cameraIds": ["camD", "camE", "camF", "camG"]
    }
  ],
  "hardware": {
    "cameras": [
      {
        "id": "camA",
        "driver": "hikvision",
        "configPath": "assets/camA.device.json",
        "calibPath": "assets/camA.calib.json",
        "roiPath": "assets/camA.roi.json"
      }
    ],
    "lights": [],
    "ioModules": []
  },
  "models": {
    "runner": "models/runner.py",
    "configs": [
      { "id": "defect1", "configPath": "models/defect1/config.yaml", "enabled": true }
    ]
  },
  "communications": { "modbus": [], "tcp": [], "serial": [] }
}
```

说明：

- **`processGroups`**：表达「多相机同属一个工艺意图」（ABC 剔除、DEFG 两工位），供 **Ops/Runtime UI 分组展示** 与文档化；**不** 内置自动汇总（**T9:A**）。  
- 汇总、对齐、**清零/矫正** **全部由主任务 `.ys` 实现**（**T16 不适用**）。  
- **T18:B**：`writesGlobals` 为文档/静态检查辅助；命名推荐 `{camId}_{metric}`（如 `camA_ok`），linter 对不符合约定 **警告**。

#### 3.3.1 标定与 ROI（T12:B）

```json
"hardware": {
  "cameras": [
    {
      "id": "camA",
      "driver": "hikvision",
      "configPath": "assets/camA.device.json",
      "calibPath": "assets/camA.calib.json",
      "roiPath": "assets/camA.roi.json"
    }
  ]
}
```

- 大 JSON/标定矩阵 **不进 yslib 本体**，仅 **相对路径引用**。  
- Launcher 完整性检查：上述文件 **存在且 Schema 合法**。

### 3.4 项目目录布局（T5 — 采纳与规范）

#### 3.4.1 你提出的结构（规范化）

安装包根目录 `{InstallRoot}` 下：

```text
{InstallRoot}/
  projects/
    {project_name}/                    # 如 product_A、product_B（换型=换项目）
      {project_name}.yslib             # 项目入口（文件名可自定义，须在 app_settings 登记）
      taskmain_name.ys                 # 主任务入口
      tasksub1_name/
        tasksub1_name.ys               # 子任务入口（可被相机触发）
        sub_name.ys                    # 被 tasksub1_name.ys #include
      tasksub2_name/
        tasksub2_name.ys
        sub1_name.ys
        sub2_name.ys
      models/                          # 【建议新增】该产品的模型 config.yaml + 权重
      assets/                          # 【建议新增】标定、ROI 模板、Halcon 参考图
      logs/                            # 【建议新增】运行时日志（gitignore）
    {project_name2}/
      …
```

**命名**：带 `_name` 处均可自定义；**yslib 内用相对路径引用**，不依赖文件夹必须叫 `tasksub1_name`。

#### 3.4.2 对你方案的评价与建议

| 你的做法 | 评价 | 建议 |
|----------|------|------|
| 每产品一个 `{project_name}` 目录 | ✅ 正确 | 换型 = 切换 `default_project_path` 或 Runtime 菜单选项目 |
| yslib 与 ys 同目录树 | ✅ 正确 | yslib 内路径 **相对 yslib 文件** |
| 子目录 + 被 include 的 ys | ✅ 正确 | yslib `scripts[]` **登记全部 .ys**（含 module），Ops 树与 Ctrl+B 不遗漏 |
| 仅按文件夹约定、不登记 | ⚠️ 风险 | **必须** yslib 显式列表或「扫描 + 校验未登记文件」警告 |
| 安装根 `/project` | ⚠️ 小改 | 推荐 `{InstallRoot}/projects/`（复数），与 `bin/` 并列；`AppPaths::projectsRoot()` |
| 多产品共存 | ✅ | `app_settings` 存默认项目；**recent_projects** 存多个 yslib 路径 |
| 运行时写日志/缓存 | 缺 | 增加 `logs/`、`cache/` 子目录，避免污染脚本目录 |

#### 3.4.3 默认项目指针（Q4:A）

- `app_settings.default_project_path` = 如 `C:/Program Files/CodePlanet/projects/product_A/product_A.yslib`  
- 相对路径解析：相对 **yslib 文件所在目录**，非 `bin` 目录。

#### 3.4.4 Ops 首屏与最近项目（T38:B，R1）

| 主题 | 约定 |
|------|------|
| **启动首屏** | **最近 yslib 列表**（路径、显示名、`openedAt`）；列表为空时引导打开 `projects/` 或 `demo.yslib` |
| **持久化** | SQLite `recent_projects`（或 `app_settings` JSON 数组）：最多 **20** 条，去重、按时间倒序 |
| **与项目树关系** | 左侧 **ProjectTreeWidget**（R0）保留；双击最近项 = 打开 yslib 并刷新树选中 |
| **默认项目** | 仍用 `app_settings.default_project_path`（Q4）；「设为默认」菜单写库 |

#### 3.4.5 Ops IDE 布局与用户配置（R0 落地，R1 完善）

| 主题 | 约定 |
|------|------|
| **USER 目录** | 开发态 `%ProjectRoot%/USER`：`config/editor.json`（`activeLayout` + `layouts` blob）、`projects/` |
| **目标 Dock 网格** | ADE / BDE / CFF（A=图片 B=图参 C=数参 D=编辑 E=项目 F=调试）；调试区横跨 D+E 底行 |
| **出厂默认** | **仅** `resources/config/editor.default.json` → `layouts.__default__`；USER `editor.json` **不**再存 `__default__` blob |
| **可选 Dock** | 项目结构/迁移提示 **不**参与 `ensureCorePanelsVisible`；打开 yslib **不**自动弹出项目结构 |
| **布局持久化** | `EditorPreferencesService` + `QMainWindow::saveState/restoreState`；**仅「保存当前布局」写 blob**；`activeLayout` 记录上次选用项 |
| **legacy `panels`** | R0 字段；**R1 起废弃**（layoutVersion≥6 以 blob 为准） |
| **手动调整** | 须 **取消「锁定布局」** 后方可拖拽；调整后 **视图→布局→保存当前布局**（可覆盖当前自定义布局） |
| **回归** | `scripts/run_r0_regression.ps1` + `scripts/run_r1_regression.ps1` |

### 3.5 项目更新分发（T21: A + C）

| 通道 | 说明 | 状态 |
|------|------|------|
| **在线（A）** | 基址 **`https://www.conbos.cn/CodePlanetr/Update/`** | **客户端 R1.5 已就绪**；站点部署与 Apply 实装 **R3**（见 [`维护文件/在线更新站部署规范.md`](./维护文件/在线更新站部署规范.md)） |
| **离线（C）** | U 盘 `CodePlanetrUpdate/manifest.json` + 相对路径 zip | **客户端 R1.5 已就绪**；Apply 实装 **R3**（见 [`维护文件/U盘离线更新部署规范.md`](./维护文件/U盘离线更新部署规范.md)） |

**在线目录规划**（manifest 驱动，与 T13 项目包 zip 一致）：

```text
https://www.conbos.cn/CodePlanetr/Update/
  manifest.json              # 平台/项目版本索引、sha256、下载 URL
  projects/
    product_A/
      product_A-1.2.3.zip
    product_B/
      …
  runtime/                   # 可选：整包安装程序
    CodePlanetSetup-2.x.exe
```

**更新策略（T31 — 建议性，非强制）**：

| 原则 | 行为 |
|------|------|
| **非阻断** | 有新版本时 **提示**「建议更新」；用户可 **忽略** 并继续启动 |
| **在线失败 / 无网** | **提示**「可使用 U 盘更新」；**不阻止** 使用当前已安装项目/Runtime **继续生产** |
| **未准备 U 盘前** | 保持 **旧版本** 运行，直至用户主动完成 U 盘或在线更新 |
| **禁止** | 因更新检查失败而 **拒绝启动** Runtime（与强制升级相反） |

**manifest.json 粒度（T30:C）** 示例字段：

```json
{
  "schemaVersion": 1,
  "publishedAt": "2026-05-19T12:00:00Z",
  "signature": "<RSA-SHA256 over canonical json>",
  "runtime": {
    "minVersion": "2.0.0",
    "setupUrl": "runtime/CodePlanetSetup-2.0.1.exe",
    "setupSha256": "…"
  },
  "plugins": [
    { "id": "BuiltinFunctions", "minVersion": "1.4.0", "path": "bin/plugins/BuiltinFunctions.dll" }
  ],
  "projects": [
    {
      "name": "product_A",
      "version": "1.2.3",
      "zipUrl": "projects/product_A/product_A-1.2.3.zip",
      "zipSha256": "…"
    }
  ]
}
```

- Launcher：拉取 manifest → **RSA 验签（T29:B，公钥 T35）** → 对比本地版本 → **建议性** 提示 → 用户确认后下载 → **ProjectValidator** → 解压（保留 `logs/`）。  
- 插件/Runtime 版本 **低于** manifest：**仅警告（T36）**，不阻断生产（T31）。

**RSA 公钥（T35）**：`resources/config/update.pub`（随安装包复制到 `{InstallRoot}/resources/config/`）；验签失败 → 拒绝应用该 manifest/zip，但不影响继续用本地旧版。

**更新站首批（T37）**：

```text
https://www.conbos.cn/CodePlanetr/Update/
  manifest.json
  projects/demo/demo-1.0.0.zip    # 与 examples/projects/demo 对齐的示例包
```

**U 盘离线布局**（`zipUrl` 相对 `CodePlanetrUpdate/manifest.json`）：

```text
{Volume}/CodePlanetrUpdate/
  manifest.json
  projects/
    demo/
      demo-1.0.0.zip
```

- 插入 U 盘后 Launcher **优先**读 U 盘 manifest；验签规则与线上一致；公钥用安装目录 `config/update.pub`（T35）。

---

## 4. 视觉数据与 HALCON XLD / HOBJECT

（与 v0.1 一致，摘要）

- 不用 `QImage` 存 XLD；用 **`VisionObjectStore`（每 TaskWorker 一份）** + 类型 `Raster/Region/Xld/...`。  
- **HOBJECT 仅 Halcon 插件私有持有**；UI 通过 polyline JSON 等轻量导出显示。  
- **跨任务传递图像/XLD**：**禁止**（**T8:A**）；仅 **判定结果** 写入 `global` 标量/小结构（§5.4）。

---

## 5. 任务、线程、global 与多工位数据（T2 / T6 / T3）

### 5.1 任务与触发（T3:A）

| 类型 | 线程 | 触发 |
|------|------|------|
| **主任务** | `MainTaskWorker` | 循环执行 `taskmain_name.ys` |
| **子任务** | 每 sub 一个 `SubTaskWorker` | **相机硬触发**（yslib `trigger.cameraId`） |
| **未绑定 sub 的相机** | — | 触发后 **仅采图/缓存（可选）**，**不执行脚本** |

相机插件：硬触发到达 → 投递到对应 `SubTaskWorker` 队列（与 UI 线程分离）。

### 5.2 `static` 与 `global`（T6:B + T26:A — 最终语义）

| 关键字 | 语义（**用户定义，T26**） | 存储 | 可见范围 |
|--------|---------------------------|------|----------|
| **`static`** | **子任务（或主任务）内部的保持型变量** — 同一 TaskWorker 多次触发仍保留 | `TaskWorker` 局部表 | **仅本 Worker**，不跨任务 |
| **`global`** | **跨任务的保持型变量** — 主任务 ↔ 子任务 ↔ 子任务间共享 | `ProjectGlobalStore` | 全项目；写经 **GlobalVariableBroker** |
| 局部变量 | 单次触发 / 单次函数调用 | 栈/帧 | 本 Worker |

> **Ops 单脚本调试补充（R2 约束）**：若未绑定 `ProjectGlobalStore`（例如直接调试单个 `.ys`），`global` 变量读写回退到参数槽，保证 F5/F6/F10 与 Ctrl+B 语义一致，不出现“已声明但运行时报未定义”。

```ys
global int camA_ok = 0;          // 跨任务：子任务写、主任务读
static int trigger_count = 0;      // 本子任务内：每次硬触发累计

function on_camA() {
    trigger_count = trigger_count + 1;
    // … 检测 …
    global camA_ok = 1;
}
```

**迁移（T26:A）**：

- **R1 一次性 breaking**：现 AST 将 `static` 当作 scope 0（类全局）的行为 **删除**；scope 0 **仅** `global`。  
- 旧脚本：凡需跨任务共享的变量 → 改为 **`global`**；仅本子任务累计的 → 保持 **`static`**（新语义）。  
- 提供 **`docs/迁移-static-global.md`** + Ops 打开旧项目时 **一次性告警列表**（不做长期双语义，T26 否决 B/C）。

- Lexer/Parser：**新增 `KwGlobal`**；`static` 绑定 TaskWorker 存储；Catalog / 高亮同步更新。

### 5.3 多相机汇总：主任务负责（T9:A）与输送带场景

#### 5.3.1 为何不用「自动 aggregate」（原方案 B）

典型场景：**输送带**上，相机 **A/B 在前端**、**C 在后端**，物理位置不同 → 同一时刻各相机看到的 **不是同一件产品**。若简单取「各相机最新一次结果」对齐，**必然乱套**。

进一步约束：

- 多数现场 **无法稳定追踪产品 ID**（无 RFID、无唯一视觉码）。  
- 用 **累加计数** 当伪 ID 易 **累积误差**，一次错位后续全错。  
- 需要 **周期清零/矫正**（如每 5 分钟或光电/编码器零位），逻辑因线而异。

因此 **T9:A（主任务手写汇总）合理**：平台 **不提供** 臃肿的自动对齐引擎；`processGroups` 仅作 **分组与 UI**；对齐策略写在 **`taskmain_name.ys`**，由懂工艺的工程师维护。

#### 5.3.2 平台建议（增强 A，而非回到 B）

在仍由主任务写逻辑的前提下，平台提供 **小粒度机制**，避免重复造轮子：

| 机制 | 用途 |
|------|------|
| **`global inspection_epoch`** | 主任务定时或 IO 信号 **递增 epoch**；子任务写结果时带 `global xxx_epoch = inspection_epoch`，主任务 **忽略过期 epoch** |
| **`global_int_inc("camA_count")`** | Broker 内原子自增，减少读-改-写竞态 |
| **环形槽位 globals** | 如 `global slot0_ab_ok`… 主任务维护 `write_idx % N`（文档提供 **范例**，非引擎） |
| **清零/矫正** | **仅主任务脚本**（读 IO、定时、计数重置）；平台 **不** 提供 T9:B 式「平台级清零信号」配置 |
| **禁止** | 平台 **不** 假设「三相机各 ok 即 ready」；**不** 自动 merge 最新结果 |
| **主任务定时器** | 见 **§5.7**（DO 保持 2 秒等时序由主任务 + 定时器 API 完成） |

#### 5.3.3 三层状态（修订）

```
Layer 1: TaskLocal — 图像/XLD + 子任务 static 计数
Layer 2: processGroups — 仅文档/UI 分组（T9:A 不自动写状态）
Layer 3: ProjectGlobal — 子任务写检测结果；主任务读、对齐、汇总、写 IO（T10）
```

| 角色 | 职责 |
|------|------|
| 子任务 A/B/C | 检测 → 写 `global`（结果 + epoch/序号） |
| **主任务** | 按工艺对齐槽位 → 判定 → **唯一** 写气缸/IO（**T10:A**） |
| IO/Comm | CommService 写队列 |

#### 5.3.4 审计结论（T9）

**你的选择与现场约束一致，文档采纳 T9:A。** 若未来某条线逻辑稳定且要复用，可将 **主任务脚本片段** 抽成 `import` 模块，仍 **不是** 平台级 auto-aggregate。

### 5.4 跨任务图像（T8:A）

- 子任务间 **不共享** 大图/XLD；仅 **global 标量/小结构**。  
- 图像仅在 **TaskLocal VisionObjectStore** 内生命周期内有效。

### 5.5 IO 控制（T10:A）

- **气缸、输送带、分拣 IO** 等 **仅主任务** 调用 IO/Comm API。  
- 子任务 **禁止** 直接写气缸/关键 DO；静态检查可警告。  
- CommService 写队列不变（§6）。

### 5.6 GlobalVariableBroker

- 所有 **`global` 写** → 队列 → 单线程 apply。  
- **读** → 快照或版本号，避免读一半被写。  
- 可选 **`global_int_inc("name")`** 原子自增，供计数型汇总。  
- **命名（T18:B）**：推荐 `camA_ok`、`camB_score`；`ScriptAnalyzer` / Ops linter 对其它模式 **警告**（可配置严格度）。

### 5.7 主任务定时器（替代原 T16 平台清零）

**背景**：T9:A 下，周期清零、DO 脉冲、气缸延时等 **时序逻辑均在主任务**；子任务 **不提供** 定时器（避免与 T10 冲突）。

**需求（已确认）**：

| 能力 | 说明 |
|------|------|
| **数量** | **不限制** 定时器个数（由 Runtime 动态表管理，仅受内存约束） |
| **启动** | `timer_start(id, duration_ms)` 或创建时带时长 |
| **停止** | `timer_stop(id)` — 停止计时，保留已计时长 |
| **重启** | `timer_restart(id)` — **从 0 重新计时**（时长不变） |
| **查询** | `timer_elapsed_ms(id)` — 当前已计时时长；`timer_running(id)` / `timer_expired(id)` |
| **作用域** | **仅 MainTaskWorker** 可调用；子任务调用 → 静态错误 |

**实现归属**：`MainTaskTimerService`；内部 **`QElapsedTimer` 单调时钟**（**T23:B**），主任务循环 **tick**（与 `loopIntervalMs` 同线程）。

**定时器 id（T24:B）**：**字符串名**，同项目内唯一；重复 `timer_create` 同名 → 静态/运行错误。

**脚本 API 草案**（R2，Catalog）：

```ys
// DO 保持 2 秒后关断
timer_create("reject_pulse", 2000);
io_write_do("reject", 1);
timer_start("reject_pulse");

while (true) {
    if (timer_expired("reject_pulse")) {
        io_write_do("reject", 0);
        timer_stop("reject_pulse");
    }
}
```

| 函数（草案） | 行为 |
|--------------|------|
| `timer_create(name, ms)` | 注册命名定时器，默认时长 |
| `timer_start(name)` | 开始/继续 |
| `timer_stop(name)` | 停止，保留已计时长 |
| `timer_restart(name)` | 从 0 重新计时 |
| `timer_elapsed_ms(name)` | 已流逝 ms（单调时钟） |
| `timer_expired(name)` | 是否达到 duration |
| `timer_destroy(name)` | 注销（可选） |

**与清零关系**：若需「每 5 分钟矫正」，主任务用 `timer_create("session_reset", 300000)` + `reset_session()`；平台不配置专用清零通道。

### 5.8 Runtime 状态 UI（T25:C）

**R2 首期**（`CodePlanetRuntime.exe` 主窗口）：

| 区域 | 内容 |
|------|------|
| **日志面板** | 主/子任务、插件、Comm 最近 N 行；可导出到项目 `logs/` |
| **Global 表** | 当前 `ProjectGlobalStore` 快照（名、类型、值、最后写入任务） |
| **ProcessGroups 树（T32:B）** | 按 `processGroups` 分组；叶节点（相机/子任务）显示：关联 **global 当前值**、**最后硬触发时间**（单调时钟戳） |
| **暂不包含（后续）** | 实时缩略图、最后一次 OK 图路径（T32 否决 C） |

刷新：主线程 **QueuedConnection** 订阅 Broker；UI 节流 **100～200ms**（与主任务 `loopIntervalMs` 默认 **20ms**，T33:B，解耦）。

---

## 6. 通讯与 Modbus

CommService 独立线程、写 FIFO。  
**IO 输出策略**：与 §5.5 一致，**主任务集中下发**。

---

## 7. Python 模型（T4:B + Q5 + Q10）

### 7.1 统一 runner（T4:B）

```text
projects/{project_name}/models/
  runner.py              # 统一入口：load config.yaml → infer
  defect1/config.yaml    # 模型名、权重路径、输入尺寸、class map
  defect1/weights/…
```

- C++ `ModelPlugin` IPC：`(modelId, inputTensor/ref, params)` → runner 内读 yaml 路由。  
- Ops：校验 yaml 字段与平台 **request/response JSON Schema** 一致。

### 7.2 安全（Q10:C）

开发明文；量产加密权重 + 签名校验 runner 包。

---

## 8. 插件设计规范（R0）

（同 v0.1：IHardware / IComm / IModel / IImageAlgorithm / IConfigPage。）

---

## 9. 演进路线图

| 阶段 | 状态 | 重点 |
|------|------|------|
| **R0** | **已结案**（2026-05-21） | Schema、ProjectValidator、AppPaths、global 占位、demo、项目树、yslib Ctrl+B、Dock 布局；见 `R0-阶段交付报告.md` |
| **R1** | **已结案**（2026-05-23） | static/global breaking、import 静态分析、recent_projects、YslibStructureWidget、迁移扫描；见 `R1-阶段交付报告.md` |
| **R1.5** | **已结案**（2026-05-24） | Launcher v1、RSA 验签、父进程约束、F8、i18n、staging；见 `R1.5-阶段交付报告.md` |
| **R2** | **已结案**（2026-05-24；调试收敛 2026-05-26） | Runtime exe、Main/SubTaskWorker、import 运行时、YS408、include、MainTaskTimerService、状态 UI + i18n、父进程校验；**Ops F6 可视策略**（if/switch/for）、**结束态 RunSessionEnded**、**run_r2_regression 构建重试**；见 `R2-阶段交付报告.md` §15 |
| **R3** | 待启动 | 硬件/Comm、**更新 Apply（下载/解压/覆盖）**、**在线+U 盘 E2E 测试（Apply 后）**、更新站运维（T37）、mini dump；测试计划见 `AST审计执行报告/R3-更新Apply与E2E测试计划.md` |
| **R4** | 待启动 | Python runner |
| **R5** | 待启动 | OpenCV/HALCON 独立插件 |

**R0 已覆盖、R1 不再重复验收**：左侧项目树、`ProjectValidator`+Ctrl+B、demo 项目、`AppPaths::projectsRoot()`、路径/迁移文档、`global` 词法与高亮占位。

---

## 10. 与当前 Ops 差距（post-R1）

| 能力 | R1 | 缺口阶段 |
|------|-----|----------|
| yslib Schema + Validator + demo | ✅ | — |
| 项目树 + yslib Ctrl+B | ✅ | — |
| `static` 任务内 / `global` 跨任务 | ✅ | — |
| `import` 静态分析 | ✅ | 运行时链接 ✅（R2） |
| 最近 yslib 列表（T38） | ✅ | — |
| yslib 结构化编辑 | ✅ | — |
| 迁移 static→global 扫描 | ✅ | 手动触发（非自动弹窗） |
| 项目级 global 重复定义 Ctrl+B | ✅ | R2 YS408 |
| import 跨文件调用用户函数 | ✅ | R2 运行时 + demoV1.1 |
| Launcher / Runtime 独立 exe | ✅ / ✅ | R1.5 Launcher；R2 Runtime |
| 产线多任务 / 真机硬触发 | 骨架 ✅ | R3 真机 trigger |
| GlobalBroker（若单独抽象） | ❌ | R3+ |

---

## 10.1 R1.5 目标与边界（**已结案**，2026-05-24）

> 交付报告：[`docs/AST审计执行报告/R1.5-阶段交付报告.md`](./AST审计执行报告/R1.5-阶段交付报告.md)

### R1.5 必做（进入 Runtime 前的“守门”能力）

1. **`CodePlanetLauncher.exe`** 可独立启动，作为产线默认入口。  
2. 启动链：**5 秒倒计时**，倒计时期间 **F8 进入修复模式**（T19/T22）。  
3. 预检复用 `ProjectValidator`（T17），支持选择项目并拉起“运行进程目标”：  
   - 产线目标：`CodePlanetRuntime.exe`（R2 真正落地）；  
   - R1.5 过渡：允许配置回退到 `CodePlanet.exe` 做启动链联调（仅开发/联调环境）。  
4. `UpdateManifestVerifier` 从 **`resources/config/update.pub`** 读取公钥并完成 RSA 验签（T35/T29）。  
5. 更新策略执行 T31：**建议性更新**，失败仅提示 U 盘，不阻断旧版本运行。  
6. Runtime 启动约束（T27）+ 开发豁免（T28）：  
   - 产线需 Launcher 父进程/令牌；  
   - `CODEPLANET_DEV=1` 时允许开发直启。

### R1.5 不做（明确留给 R2/R3）

- `CodePlanetRuntime.exe` 完整产线能力（R2）  
- `import` 运行时模块链接与跨文件用户函数调用（R2）  
- 项目级 global 重复定义检查（R2）  
- MainTaskTimerService、Runtime 状态 UI（R2）  
- **更新包下载、解压、覆盖 Apply**（R3）  
- conbos 站点运维上架、硬件/Comm 插件（R3）

### R1.5 验收口径（摘要）— **已通过**

- Launcher 能在预检通过后启动 Runtime，并在 Runtime 快速退出时弹出错误与日志路径。  
- F8 修复模式可跳过插件预检启动（带风险确认），且不自动倒计时启动。  
- 验签失败时拒绝应用更新包，但允许继续运行本地旧版。  
- 插件/Runtime 版本低于 manifest：**Warning**，不阻断（T36）。  
- **在线/U 盘/Apply 完整 E2E**：统一在 **R3 Apply 实装后**验收（见 [`R3-更新Apply与E2E测试计划.md`](./AST审计执行报告/R3-更新Apply与E2E测试计划.md)）；R1.5 仅验签单测 + 断网不阻断。

---

## 10.2 R3 更新 Apply 与 E2E 测试（计划）

> 详细步骤：[R3-更新Apply与E2E测试计划.md](./AST审计执行报告/R3-更新Apply与E2E测试计划.md)

| 里程碑 | 内容 |
|--------|------|
| **R3 开发** | Launcher Apply：下载、SHA256、解压、保留 `logs/`、`ProjectValidator` |
| **R3 测试（U 盘）** | 验签失败、缺 zip、Apply 闭环、U 盘优先于在线 |
| **R3 测试（在线）** | conbos 静态托管、HTTPS 拉取、Apply 下载 |
| **不在 R1.5 测** | 上述 E2E 统一在 Apply 可用后一次性回归 |

---

## 10.4 R3 目标与边界（执行口径）

> 执行入口：[`docs/AST审计执行报告/R3-执行提示词.md`](./AST审计执行报告/R3-执行提示词.md)  
> 更新专项测试清单：[`R3-更新Apply与E2E测试计划.md`](./AST审计执行报告/R3-更新Apply与E2E测试计划.md)

### R3 必做（从“可提示更新”到“可安全应用更新”）

1. Launcher **Apply 更新实装**：下载（在线/本地）→ SHA256 校验 → 解压覆盖项目（保留 `logs/`）→ `ProjectValidator` 复核。  
2. **在线 + U 盘 E2E** 全量执行（T-UPD-1~11），并形成可追溯记录表。  
3. U 盘优先策略、断网不阻断、签名失败/缺包可读报错（维持 T31/T36 产品行为）。  
4. SubTaskWorker 对接 **真实触发入口**（至少抽象层接入，允许无真机 mock）。  
5. mini dump 落盘与路径提示（`%AppData%/CodePlanet/dumps/`），补齐 R1.5 占位。  

### R3 不做（留后续）

- Python runner 产线闭环（R4）  
- HALCON/OpenCV 产线插件化（R5）  
- 更高阶运行时诊断（性能剖析/分布式日志）

### R3 验收口径（摘要）

- Apply 成功后可启动并加载新项目版本；失败不破坏旧版本可运行性。  
- 在线/U 盘两通道均通过 E2E，且 U 盘优先策略可复现。  
- 子任务真实触发链路可验证（真机或规范化 mock），`simulateTrigger` 不再是唯一入口。  
- dump 文件可按错误路径定位。

---

## 10.3 R2 目标与边界（**已结案**，2026-05-24）

> 交付报告：[`docs/AST审计执行报告/R2-阶段交付报告.md`](./AST审计执行报告/R2-阶段交付报告.md)  
> 执行入口（归档）：[`docs/AST审计执行报告/R2-执行提示词.md`](./AST审计执行报告/R2-执行提示词.md)

### R2 必做（运行时落地）— **已完成**

1. **`CodePlanetRuntime.exe` 最小可运行壳**：可被 Launcher 拉起并进入主任务循环。  
2. **多任务执行骨架**：`MainTaskWorker` + `SubTaskWorker`（按 yslib `tasks`/`trigger` 建图）。  
3. **`import` 运行时链接**：导入模块函数可被当前脚本调用。  
4. **项目级 global 重复定义检查**：Ctrl+B 报错 YS408（跨脚本同名冲突）。  
5. **`#include` 路径解析修正**：相对「当前脚本目录」。  
6. **MainTaskTimerService**：`timer_create/start/stop/restart/elapsed/expired`（T23/T24）；表达式 `timer_expired` 返回 0/1。  
7. **Runtime 状态 UI 首期**：日志 + global 表 + processGroups 树（T25/T32）；**界面 i18n 随 Launcher `--locale=`**。  
8. **父进程约束接入 Runtime**：`--parent-pid + nonce`；`CODEPLANET_DEV=1` 开发豁免。
9. **Ops 调试一致性修复**：`global` 在无 `ProjectGlobalStore` 场景回退参数槽存取；跨文件 F10 返回采用调用方恢复点与 CRLF/LF 归一化，避免错误回跳与会话误重置。
10. **F2/F3 就地重置 + 项目树展开策略**：F2/F3 在当前文件首行重置（`RunDebugReset`），不回跳旧 IP，重置后可直接 F5/F6/F10；项目树启动/刷新后仅展开 active 项目。
11. **F6/F10 逐行箭头**：单步按物理行推进（含空白/注释）；函数声明扫描跳闭合行；顶层调用 F6 进入函数头行；F10 跨文件返回落在调用语句下一行（`executingStatementLineForFrame + 1`）。
12. **首轮一致性 + F5 结束位**：`sourceFilePath` 已绑定时首轮 F6/F10 与 F2 后语义一致（不再出现“第一遍不跳函数声明”）；F5 完成态箭头统一落在入口脚本末行（EOF）。

### R2 不做（明确留给 R3+）

- 更新 Apply（下载/解压/覆盖）与在线/U 盘 E2E（R3）  
- 硬件/Comm 插件真机联调、子任务 **相机硬触发**（R3；R2 为 `simulateTrigger`）  
- Python runner 产线链路（R4）  
- HALCON/OpenCV 插件产线化（R5）

### R2 验收口径（摘要）— **已通过**

- Launcher 正常拉起 Runtime（非 Ops 回退）。  
- demoV1.1：`import` 跨文件调用、`pulse_active` 定时器 2s、`camA_ok` 子任务写入。  
- 跨脚本重复 `global` Ctrl+B 报错 YS408。  
- 定时器 API 主任务可用、子任务 YS406。  
- Runtime UI 观察 processGroups 与 global；中/英界面与 Launcher 启动时语言一致。  
- 自动化：`run_all_checks.ps1`、`run_r2_regression.ps1`、父进程拦截测试 pass。

### R2 本机构建约定（Release 推荐）

| 步骤 | 说明 |
|------|------|
| Qt Creator **Release** 构建全部 | 覆盖 `bin/*.exe`（三端） |
| `scripts/deploy_bin.ps1 -Config Release` | **必须**（`windeployqt` + plugins/config/translations） |
| `scripts/run_launcher_dev.ps1 -Config Release` | 可选；本机 dev 启动 Launcher |

**注意**：Release exe 与 Debug Qt DLL（`Qt5Cored.dll`）不可混用；切换配置后须对应该 `-Config` 重新 `deploy_bin`。

---

## 11. 已确认项索引

- **Q1～Q10**：§2.1  
- **T1～T6**：§2.2  
- **T7～T12**：§2.3  
- **T13～T20**：§2.4、§1.5、§3、§5  
- **T21～T27**：§2.5、§3.5、§5.2、§5.7、§5.8、§1.5、§9  
- **T28～T34**：§2.6、§3.5、§5.8、§9  
- **T35～T38**：§2.7、§3.4.4、§3.5  

---

## 12. 文档完善度评估（v1.5，post-R2）

| 维度 | 完成度 | 说明 |
|------|--------|------|
| **战略与产品决策（Q+T）** | **100%** | Q1～Q10、T1～T38 已闭环 |
| **三端边界与职责** | **~99%** | Launcher + Runtime 产线最小闭环；R3 口径冻结 |
| **数据模型** | **~90%** | `docs/schemas/*` 与 demo 已存在（R0） |
| **运行时机制** | **~96%** | R2 产线 worker + timer + import 运行时；真机 trigger 待 R3 |
| **实施路线图** | **~99%** | R0～R2 结案，R3 目标/验收路径已冻结 |
| **与仓库同步（§10）** | **~99%** | post-R2 差距表已更新 |

**综合完善度：约 98%**

**阶段文档**：R0 → `R0-阶段交付报告.md`；R1 → `R1-阶段交付报告.md`；R1.5 → `R1.5-阶段交付报告.md`；**R2 → `R2-阶段交付报告.md`**。

---

## 13. 实施期可选项（非 T 编号，按需）

| 主题 | 说明 |
|------|------|
| **更新站运维 + E2E** | 部署规范见 `docs/维护文件/`；**Apply 与在线/U 盘闭环测试**见 `R3-更新Apply与E2E测试计划.md` |
| **R1 拆分** | 工期紧时：先 **static/global 迁移** → 再 **最近列表 + import 分析** |
| **Ops 更名** | `CodePlanetOps.exe` 可与 R1.5 Launcher 打包一并改，非 R1 必须 |

---

## 14. 文档维护

- 同步：`docs/架构说明.md`、`docs/维护文件/AST逻辑架构.md`、`.cursor/开发指南.md`（重大变更时）。  
- 阶段验收：`docs/AST审计执行报告/`（R0～R5）。

---

## 15. 变更记录

| 版本 | 日期 | 摘要 |
|------|------|------|
| v0.1 | 2026-05-21 | Q1～Q10、VisionObject、Broker、R0～R5 |
| v0.2 | 2026-05-21 | T1～T6：projects 目录、global、processGroups |
| v0.3 | 2026-05-21 | T7～T12：Launcher、T9 主任务汇总、import、assets |
| v0.4 | 2026-05-19 | T13～T20：项目包更新、mini dump、import、主任务定时器、F8 修复模式 |
| v0.5 | 2026-05-19 | T21～T27：conbos 在线+U盘、修复模式、定时器、Runtime UI、父进程校验 |
| v0.6 | 2026-05-19 | T28～T34：DEV 豁免、RSA manifest、建议性更新、UI 叶节点、R0 提示词；**Q+T 冻结** |
| v0.7 | 2026-05-21 | §3.4.5 Ops IDE：USER 配置、Dock CFF、布局持久化、R0 回归 |
| v0.8 | 2026-05-21 | T35～T38；R0 结案；§9/§10 刷新；R1 目标与提示词 |
| v0.9 | 2026-05-23 | R1 结案；§3.4.5 布局显式保存、`panels` 废弃；§10 post-R1 |
| v1.0 | 2026-05-23 | R1.5 目标/边界/验收口径冻结；完善度与路线图同步更新 |
| v1.1 | 2026-05-24 | **R1.5 结案**；§3.5 U 盘路径修正；更新站/U 盘部署规范；Launcher 交付补充 |
| v1.2 | 2026-05-24 | 在线/U 盘 E2E 测试统一并入 **R3 Apply 后**（`R3-更新Apply与E2E测试计划.md`） |
| v1.3 | 2026-05-24 | R2 目标/边界/验收口径冻结；新增 `R2-执行提示词.md` 入口 |
| v1.4 | 2026-05-24 | **R2 结案**；Runtime i18n（`--locale=`）；§10.3 验收通过；Release+deploy_bin 约定；§10 差距表刷新 |
| v1.5 | 2026-05-24 | R3 目标/边界/验收口径冻结；新增 `R3-执行提示词.md` 入口；完善度更新 |

---

*CodePlanet — 视觉检测平台架构终点（living document）*
