775 lines
41 KiB
Markdown
775 lines
41 KiB
Markdown
# Windows Node Host 与 WPF 重构方案
|
||
|
||
> 状态:阶段 0–7 已落地,进入阶段 8 发布准备
|
||
> 日期:2026-08-31
|
||
> 适用范围:`windows-node/Zcbot.WindowsNode` 及其测试、打包与运行文档
|
||
|
||
## 1. 背景
|
||
|
||
当前 Windows Node 已完成托盘常驻、节点注册、WebSocket 连接、任务持久化与恢复、Adapter 发现与执行、Workspace 管理、专业软件配置、受管 runtime 安装、本机任务查看、数据目录迁移和 ANSYS 真机验收。它已经从一个简单的内网托盘 MVP 演进为专业软件任务的稳定宿主。
|
||
|
||
当前实现仍是单个 .NET 10 WinForms `WinExe`,后台协议与执行能力总体边界正确,但 UI 和 Host 内部职责开始集中:
|
||
|
||
- `ConfigurationForm.cs` 约 1300 行,布局、状态、软件管理、任务展示、数据迁移和 ANSYS 验收混在同一窗口类中。
|
||
- `TrayApplicationContext.cs` 同时管理托盘、窗口、注册、连接、重连、迁移和安全退出。
|
||
- `NodeConnectionLoop.cs` 同时承担 WebSocket 会话、心跳、消息解析、任务编排、恢复、取消与终态回报。
|
||
- `JobInboxStore.cs` 同时承担协议接单、磁盘持久化、状态流转、恢复扫描和 UI 展示读取。
|
||
- `SoftwareRuntimeManager.cs` 以大体量静态类同时承担软件定义、位置存储、探测、环境注入和 runtime 安装。
|
||
- 注册、下载和上传分别管理 HTTP 客户端,网络错误分类、重试和认证注入缺少统一边界。
|
||
- 现有 Windows Node 测试中有较多源码字符串断言,能够保护若干安全约束,但难以验证真实状态转换和异步生命周期。
|
||
|
||
本次重构同时处理两个问题:
|
||
|
||
1. 将 WinForms 主窗口迁移为 WPF,使用 XAML、数据绑定和 MVVM 组织界面。
|
||
2. 将 Node Host 重构为可测试、可组合、与 UI 无关的长期宿主架构。
|
||
|
||
本次不是服务端协议重写,也不是 Adapter 架构替换。
|
||
|
||
## 2. 目标
|
||
|
||
### 2.1 用户与运维目标
|
||
|
||
- 保持现有节点身份、数据目录、任务、Workspace 和 runtime 原位兼容。
|
||
- 保持解压发布包后直接运行的部署方式。
|
||
- 保持同一 EXE 的托盘、`enroll` 和 `run --headless` 三种入口。
|
||
- 提升 125%、150% 和 200% DPI 下的布局稳定性。
|
||
- 让节点状态、软件状态、任务状态和长时间操作在界面中保持一致。
|
||
- 让新增专业软件主要落在 Adapter 和软件定义,不再扩张单个巨型窗口。
|
||
- 在出现连接、传输、Worker 或恢复故障时提供可定位但不泄露 Token 的本机诊断。
|
||
|
||
### 2.2 工程目标
|
||
|
||
- 建立唯一 Composition Root,GUI 与 headless 共用同一套 Host 组装。
|
||
- 将 UI、应用编排、领域状态、协议传输和基础设施分层。
|
||
- 以明确的 Host 生命周期替代托盘类直接管理连接任务。
|
||
- 以明确的 Job 状态机约束接单、下载、执行、上传、取消和恢复。
|
||
- 统一 HTTP、WebSocket、认证、错误分类和传输重试边界。
|
||
- 统一 Adapter 目录发现、合同加载、软件 probe 和进程监督边界。
|
||
- 对纯逻辑和关键异步流程增加 .NET 行为测试,减少脆弱的源码字符串测试。
|
||
- 每个实施阶段都可构建、可打包、可验收和可回退。
|
||
|
||
## 3. 非目标
|
||
|
||
以下事项不随本轮重构进入实现:
|
||
|
||
- 不改服务端 HTTP/WebSocket URL、消息类型、字段语义或认证方式。
|
||
- 不改 `node.json`、`jobs/`、`workspaces/`、`runtimes/` 的对外文件布局。
|
||
- 不清理、重置或隐式迁移已有节点数据。
|
||
- 不改 Adapter 的 `adapter.json + contract + worker + job directory` 协议。
|
||
- 不引入 Python GUI、Electron、WebView 或 WinUI 3。
|
||
- 不安装 Windows Service,不拆 Service/DesktopRunner 双进程。
|
||
- 不增加自动更新平台、插件市场或在线 Adapter 覆盖。
|
||
- 不增加多 Job 并行或 per-capability slot;继续保持整机单执行槽。
|
||
- 不把 Adapter probe、软件语义或具体软件分支移入通用 Host。
|
||
- 不在框架迁移时同时进行大规模视觉重设计。
|
||
|
||
## 4. 必须保持的兼容契约
|
||
|
||
| 契约 | 重构后要求 |
|
||
|---|---|
|
||
| 可执行文件 | 仍为 `Zcbot.WindowsNode.exe` |
|
||
| GUI 启动 | 无参数启动托盘;未注册时显示主窗口,已注册时后台连接 |
|
||
| CLI | `enroll` 参数、输出标签和退出码不变 |
|
||
| Headless | `run --headless` 不初始化 WPF、窗口或托盘 |
|
||
| 单实例 | 继续使用 `Local\\Zcbot.WindowsNode` Mutex |
|
||
| 节点身份 | 继续读取现有 DPAPI `LocalMachine` 加密 Token |
|
||
| 注册表 | 数据根目录、软件位置和当前账号 Run 项键名不变 |
|
||
| 数据目录 | 默认值、环境变量优先级和旧 `%ProgramData%` 兼容不变 |
|
||
| Job | 已落盘任务可由新版继续恢复、取消、上传和回报终态 |
|
||
| Workspace | `current`、`rollback` 和 head Job 语义不变 |
|
||
| Adapter | 继续从 EXE 同级 `adapters/*/adapter.json` 发现 |
|
||
| 发布 | 完整包和独立 Adapter 包的目录结构不变 |
|
||
| 服务端 | 无 DB migration、无 API 变化、无部署联动要求 |
|
||
|
||
任何需要改变以上契约的实现发现都必须暂停,单独形成兼容设计,不得借重构直接修改。
|
||
|
||
## 5. 总体架构
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Entry["Program / Composition Root"]
|
||
Tray["TrayHost"]
|
||
Wpf["WPF Views"]
|
||
VM["ViewModels"]
|
||
App["Application Services"]
|
||
Host["NodeHost"]
|
||
Session["NodeSession"]
|
||
Jobs["JobCoordinator"]
|
||
Transfers["TransferClient"]
|
||
Adapters["AdapterCatalog / AdapterExecutor"]
|
||
Persistence["Config / Job / Workspace Repositories"]
|
||
Runtime["SoftwareRuntimeService"]
|
||
Server["zcbot HTTP / WebSocket"]
|
||
Workers["Python or EXE Workers"]
|
||
Disk["Existing data root"]
|
||
|
||
Entry --> Tray
|
||
Entry --> Host
|
||
Tray --> Wpf
|
||
Wpf --> VM
|
||
VM --> App
|
||
Tray --> App
|
||
App --> Host
|
||
Host --> Session
|
||
Host --> Jobs
|
||
Jobs --> Transfers
|
||
Jobs --> Adapters
|
||
Jobs --> Persistence
|
||
App --> Runtime
|
||
Session --> Server
|
||
Transfers --> Server
|
||
Adapters --> Workers
|
||
Persistence --> Disk
|
||
Runtime --> Disk
|
||
```
|
||
|
||
### 5.1 分层规则
|
||
|
||
#### Presentation
|
||
|
||
包含 WPF View、ViewModel、托盘和对话框适配器。
|
||
|
||
- 可以引用 Application。
|
||
- 不直接引用 `ClientWebSocket`、`HttpClient`、Registry、文件系统或进程。
|
||
- XAML code-behind 只处理纯 View 行为,例如 PasswordBox 取值、窗口拖动和焦点。
|
||
- 不在 `MainWindow.xaml.cs` 中编排节点业务。
|
||
|
||
#### Application
|
||
|
||
包含用户操作和宿主生命周期的用例编排。
|
||
|
||
- 注册、重连、清除身份、迁移数据目录、安全退出。
|
||
- 软件位置变更、runtime 安装和固定验收。
|
||
- 组合领域结果为不可变 UI Snapshot。
|
||
- 不依赖 WPF 或 WinForms 类型。
|
||
|
||
#### Host / Domain
|
||
|
||
包含节点会话、Job 状态机、单槽执行、恢复和 Adapter 抽象。
|
||
|
||
- 不感知托盘、窗口、按钮或对话框。
|
||
- 不通过任意字符串隐式改变 Job 状态。
|
||
- 关键状态转换经过统一校验和持久化。
|
||
|
||
#### Infrastructure
|
||
|
||
包含 HTTP、WebSocket、JSON、DPAPI、Registry、文件、进程和软件探测实现。
|
||
|
||
- 向上提供明确的小接口或服务,不把 Win32/IO 类型扩散到 ViewModel。
|
||
- 原子写、路径约束、日志脱敏和进程树终止在此集中实现。
|
||
|
||
## 6. 目标项目结构
|
||
|
||
第一轮保持单一 `Zcbot.WindowsNode.csproj`,先形成目录和命名空间边界,避免同时承担程序集拆分、`internal` 可见性和发布路径变化。完成后再依据依赖图决定是否拆出测试友好的 Core 项目。
|
||
|
||
```text
|
||
Zcbot.WindowsNode/
|
||
├── Program.cs
|
||
├── App.xaml
|
||
├── App.xaml.cs
|
||
│
|
||
├── Bootstrap/
|
||
│ ├── NodeCompositionRoot.cs
|
||
│ ├── NodeCommandLine.cs
|
||
│ └── SingleInstanceGuard.cs
|
||
│
|
||
├── Application/
|
||
│ ├── NodeApplicationController.cs
|
||
│ ├── NodeApplicationSnapshot.cs
|
||
│ ├── NodeShutdownDecision.cs
|
||
│ ├── DiagnosticService.cs
|
||
│ ├── JobMonitorService.cs
|
||
│ ├── SoftwareManagementService.cs
|
||
│ └── AnsysAcceptanceService.cs
|
||
│
|
||
├── Host/
|
||
│ ├── NodeHost.cs
|
||
│ ├── NodeHostSnapshot.cs
|
||
│ ├── NodeSession.cs
|
||
│ ├── NodeSessionState.cs
|
||
│ └── NodeEvent.cs
|
||
│
|
||
├── Protocol/
|
||
│ ├── NodeProtocolClient.cs
|
||
│ ├── NodeProtocolCodec.cs
|
||
│ ├── ServerMessage.cs
|
||
│ ├── NodeMessage.cs
|
||
│ └── NodeProtocolException.cs
|
||
│
|
||
├── Jobs/
|
||
│ ├── JobCoordinator.cs
|
||
│ ├── JobExecutionGate.cs
|
||
│ ├── JobStateMachine.cs
|
||
│ ├── JobRepository.cs
|
||
│ ├── JobRecoveryService.cs
|
||
│ └── JobSnapshot.cs
|
||
│
|
||
├── Transfers/
|
||
│ ├── NodeHttpClient.cs
|
||
│ ├── JobInputTransfer.cs
|
||
│ ├── JobOutputTransfer.cs
|
||
│ └── TransferRetryPolicy.cs
|
||
│
|
||
├── Adapters/
|
||
│ ├── AdapterCatalog.cs
|
||
│ ├── AdapterDescriptor.cs
|
||
│ ├── AdapterContractLoader.cs
|
||
│ ├── AdapterExecutionService.cs
|
||
│ └── ProcessSupervisor.cs
|
||
│
|
||
├── Workspaces/
|
||
│ ├── WorkspaceRepository.cs
|
||
│ └── WorkspacePromotionService.cs
|
||
│
|
||
├── Runtime/
|
||
│ ├── SoftwareCatalog.cs
|
||
│ ├── SoftwareLocationService.cs
|
||
│ ├── SoftwareProbeService.cs
|
||
│ └── ManagedRuntimeInstaller.cs
|
||
│
|
||
├── Persistence/
|
||
│ ├── NodeConfigStore.cs
|
||
│ ├── NodeDataRootService.cs
|
||
│ ├── AtomicFile.cs
|
||
│ ├── PathGuard.cs
|
||
│ └── RotatingNodeLog.cs
|
||
│
|
||
├── Presentation/
|
||
│ ├── Tray/
|
||
│ ├── ViewModels/
|
||
│ ├── Views/
|
||
│ ├── Commands/
|
||
│ ├── Converters/
|
||
│ └── Themes/
|
||
│
|
||
└── Compatibility/
|
||
└── persisted model readers retained only where required
|
||
```
|
||
|
||
目录是目标职责图,不要求通过一次机械移动完成;重构期间优先保证逻辑边界,最后再统一物理目录。
|
||
|
||
## 7. Host 核心设计
|
||
|
||
### 7.1 Composition Root
|
||
|
||
`NodeCompositionRoot` 是唯一对象组装入口:
|
||
|
||
- 解析一次数据根目录并生成 `NodePaths`。
|
||
- 创建唯一 `NodeConfigStore`、`JobRepository`、`WorkspaceRepository` 和 `AdapterCatalog`。
|
||
- 按当前节点配置创建共享 `NodeHttpClient` 和 `NodeProtocolClient`。
|
||
- 创建 `JobCoordinator`、`NodeSession` 和 `NodeHost`。
|
||
- GUI 与 headless 只决定 Presentation 和生命周期宿主,不各自复制 Host 构造逻辑。
|
||
|
||
不引入通用依赖注入容器;当前规模使用显式构造函数组装更便于审计、打包和故障定位。
|
||
|
||
### 7.2 NodeHost 生命周期
|
||
|
||
`NodeHost` 对外只暴露少量稳定操作:
|
||
|
||
```csharp
|
||
Task RunAsync(CancellationToken cancellationToken);
|
||
Task ReconnectAsync(CancellationToken cancellationToken);
|
||
Task<NodeShutdownResult> StopAsync(NodeShutdownMode mode, CancellationToken cancellationToken);
|
||
NodeHostSnapshot Current { get; }
|
||
event EventHandler<NodeHostSnapshot>? SnapshotChanged;
|
||
```
|
||
|
||
生命周期约束:
|
||
|
||
- `RunAsync` 是结构化并发根,拥有会话、恢复、Job 和传输子任务。
|
||
- 所有子任务都可追溯到 Host CancellationToken,不允许 fire-and-forget Worker 管线。
|
||
- 重连先停止接收 offer,再等待本地任务和上传到达安全点,之后替换会话。
|
||
- 正常退出与取消任务退出使用同一 `StopAsync`,GUI 和 headless 不复制收尾逻辑。
|
||
- `StopAsync` 幂等;重复点击退出或系统注销不会启动第二条取消链。
|
||
- Snapshot 是不可变值,UI 只消费 Snapshot,不读取 Host 内部集合。
|
||
|
||
### 7.3 WebSocket 会话拆分
|
||
|
||
从 `NodeConnectionLoop` 提取:
|
||
|
||
- `NodeSession`:连接、hello、心跳、接收循环和退避重连。
|
||
- `NodeProtocolCodec`:JSON 消息的严格解析、类型分发和序列化。
|
||
- `NodeProtocolClient`:并发安全发送和 WebSocket 关闭语义。
|
||
- `JobCoordinator`:处理 offer、cancel 和导出等业务消息。
|
||
|
||
要求:
|
||
|
||
- 一个会话只拥有一个接收循环。
|
||
- 所有发送通过同一发送锁,避免并发 `SendAsync`。
|
||
- 认证拒绝、握手 HTTP 错误、网络中断和协议错误继续保持不同状态。
|
||
- 未知消息按现有兼容策略处理,不得把解析异常误报为身份失效。
|
||
- 心跳携带的能力、health、slot 和合同摘要来自同一个原子 Snapshot。
|
||
|
||
### 7.4 Job 状态机
|
||
|
||
新增 `JobStateMachine` 作为内部唯一状态转换入口,覆盖:
|
||
|
||
```text
|
||
offered
|
||
-> accepted
|
||
-> downloading
|
||
-> ready
|
||
-> software_running
|
||
-> promoting_workspace
|
||
-> uploading_preview / uploading_output
|
||
-> succeeded
|
||
|
||
任意可取消阶段 -> cancelling -> cancelled
|
||
任意执行阶段 -> failed
|
||
进程重启 -> recovered according to persisted markers
|
||
```
|
||
|
||
具体落盘字符串和 JSON 字段保持现状;状态机首先包裹现有格式,不强制迁移历史文件。
|
||
|
||
要求:
|
||
|
||
- offer 仍然先持久化并 flush/原子替换,再回复 accept。
|
||
- Job ID、lease ID 和 request digest 一致性校验保持不变。
|
||
- 终态不可逆;重复终态消息必须幂等。
|
||
- 单执行槽由本机 `JobExecutionGate` 再次强制,不只依赖云端 slot。
|
||
- Workspace promotion、预览上传和显式导出分别建模,不能因上传重试重复执行专业软件。
|
||
- 进程重启恢复只依赖已落盘事实,不依赖 UI 内存状态。
|
||
|
||
### 7.5 Job 持久化拆分
|
||
|
||
将 `JobInboxStore` 拆为三个职责:
|
||
|
||
- `JobRepository`:原子读写 Job、marker 和 terminal。
|
||
- `JobRecoveryService`:启动扫描和恢复决策。
|
||
- `JobMonitorService`:面向 UI 生成只读展示 Snapshot。
|
||
|
||
统一 `AtomicFile`:
|
||
|
||
- 同目录临时文件。
|
||
- 写入、flush、关闭后原子替换。
|
||
- 原文件存在时保持当前替换语义。
|
||
- 不用跨卷 rename。
|
||
- 临时文件命名不与 Worker 协议文件冲突。
|
||
|
||
统一 `PathGuard`:
|
||
|
||
- 所有 Job、Workspace、Adapter 和 runtime 派生路径必须归一化后验证仍位于预期根目录。
|
||
- 不把请求内文件名直接拼入本机路径。
|
||
- 保持合同内输出 ID 与实际文件 manifest 的现有校验。
|
||
|
||
### 7.6 传输层
|
||
|
||
创建每个已加载节点配置唯一的 `NodeHttpClient`:
|
||
|
||
- 统一 BaseAddress、Bearer Token、User-Agent、默认超时和错误摘要。
|
||
- 输入下载和输出上传复用连接池。
|
||
- 大文件继续流式传输,不整体读入内存。
|
||
- 重试只覆盖可安全重放的阶段,上传继续依赖服务端幂等校验。
|
||
- 认证失败不进入普通网络重试。
|
||
- 日志不记录 Authorization Header、Node Token、注册码或签名 URL 查询串。
|
||
|
||
`JobInputTransfer` 与 `JobOutputTransfer` 只负责传输;是否重试、何时回报终态由 `JobCoordinator` 决定。
|
||
|
||
### 7.7 Adapter 与进程监督
|
||
|
||
将当前 Adapter 发现和执行拆为:
|
||
|
||
- `AdapterCatalog`:启动时一次发现、合同加载和描述符缓存。
|
||
- `AdapterContractLoader`:manifest、合同路径、Schema 和 SHA-256 校验。
|
||
- `AdapterExecutionService`:准备 Job 目录并调用固定 Adapter。
|
||
- `ProcessSupervisor`:启动、标准流采集、超时、取消、完整进程树终止和退出确认。
|
||
|
||
安全边界保持:
|
||
|
||
- Worker 入口必须来自已安装 manifest,不来自任务请求。
|
||
- 入口归一化后必须位于对应 Adapter 目录。
|
||
- Python 解释器必须来自固定受管 runtime 解析。
|
||
- 请求不能注入命令行、环境变量、工作目录或本机路径。
|
||
- 进程退出后才读取 terminal;取消后必须等待完整进程树退出。
|
||
- Host 不解析 Origin、ANSYS、Blender 业务语义。
|
||
|
||
### 7.8 Workspace
|
||
|
||
`WorkspaceRepository` 负责现有 metadata 和目录读取,`WorkspacePromotionService` 负责:
|
||
|
||
- 校验 source head。
|
||
- 在临时目录准备下一版。
|
||
- 成功后更新 `rollback` 和 `current`。
|
||
- 失败时保持旧 `current` 可继续使用。
|
||
- 只保留一份 rollback。
|
||
|
||
重构不得增加按 Job 永久保存工程副本,也不得在 Node 间搬迁 Workspace。
|
||
|
||
### 7.9 软件与 runtime 管理
|
||
|
||
将 `SoftwareRuntimeManager` 拆为:
|
||
|
||
- `SoftwareCatalog`:固定的软件和 runtime 定义。
|
||
- `SoftwareLocationService`:注册表配置、自动检测和版本来源。
|
||
- `SoftwareProbeService`:通过 Adapter probe 汇总最终 health。
|
||
- `ManagedRuntimeInstaller`:固定 requirements、临时目录安装、验证和原子替换。
|
||
|
||
要求:
|
||
|
||
- 软件卡继续按 `runtime_id` 归并多个 capability。
|
||
- 环境变量优先级和现有兼容名称不变。
|
||
- runtime 有活动任务时继续拒绝替换。
|
||
- 安装命令、镜像地址和 requirements 不接受任务请求控制。
|
||
- Origin 软件位置识别与 COM 健康继续分离。
|
||
- ANSYS 执行门和固定验收继续由 Adapter/验收脚本给出事实结果。
|
||
|
||
## 8. WPF Presentation 设计
|
||
|
||
### 8.1 框架选择
|
||
|
||
- 继续使用 C# 和 .NET 10。
|
||
- 项目启用 WPF。
|
||
- 暂时保留 WinForms 引用,仅复用成熟的 `NotifyIcon`。
|
||
- 不引入第三方 MVVM 或主题框架;先使用小型 `ObservableObject`、`RelayCommand`、`AsyncCommand` 和资源字典。
|
||
- 首版使用浅色主题,颜色、字体、间距和控件状态全部抽为资源。
|
||
|
||
### 8.2 View 与 ViewModel
|
||
|
||
```text
|
||
MainWindow
|
||
├── OverviewView / OverviewViewModel
|
||
├── SoftwareView / SoftwareViewModel
|
||
│ ├── SoftwareCardViewModel[]
|
||
│ └── AnsysAcceptanceViewModel
|
||
├── JobsView / JobsViewModel
|
||
└── SettingsView / SettingsViewModel
|
||
```
|
||
|
||
ViewModel 只接收 Application Service 和不可变 Snapshot;不直接 new Adapter Registry、Job Store 或路径对象。
|
||
|
||
### 8.3 状态绑定
|
||
|
||
以下状态由 Snapshot 或专用 ViewModel 字段统一驱动:
|
||
|
||
- 节点连接状态、颜色、说明和操作可用性。
|
||
- 注册卡是否显示。
|
||
- 软件位置、runtime、probe 和 capability 状态。
|
||
- runtime 安装、验收和数据迁移进度。
|
||
- Job 列表、选中项、详情和刷新状态。
|
||
- 退出期间全局操作禁用。
|
||
|
||
不允许同一状态同时由多个页面各自推断。
|
||
|
||
### 8.4 托盘与窗口生命周期
|
||
|
||
`TrayHost` 只处理:
|
||
|
||
- 创建和释放 NotifyIcon。
|
||
- 将 Host Snapshot 映射为图标、悬浮文本和菜单摘要。
|
||
- 打开、隐藏和激活 WPF 主窗口。
|
||
- 收集退出选择并调用 `NodeApplicationController.StopAsync`。
|
||
|
||
活动任务退出的三种选择、二次确认和等待提示保持现有语义。业务取消与进程收尾不在 TrayHost 内实现。
|
||
|
||
### 8.5 可访问性与 DPI
|
||
|
||
- 使用设备无关布局,不写依赖当前字体像素测量的固定页面宽度。
|
||
- 关键页面在 760×560 最小窗口和 100%–200% DPI 下可访问。
|
||
- 长路径、长错误和任务标题允许换行、截断并提供完整详情。
|
||
- 设置合理的 Tab 顺序、AccessKey、默认按钮和取消行为。
|
||
- 不仅使用颜色表达在线、警告和失败状态。
|
||
- 长时间操作必须有文本状态、进度反馈和可用时的取消入口。
|
||
|
||
## 9. 诊断与可观测性
|
||
|
||
在不引入远程日志平台的前提下,增加受控本机 Host 日志:
|
||
|
||
- 路径位于现有 data root 的 `logs/`。
|
||
- 使用 ASCII 级别标签:`[INFO]`、`[WARN]`、`[ERR]`。
|
||
- 单文件有明确大小上限并只保留有限轮转文件。
|
||
- 记录会话阶段、Job ID、capability、Adapter 版本、Worker PID、传输阶段和 HRESULT/异常类型。
|
||
- 不记录 Node Token、注册码、Authorization Header、完整签名 URL 或用户输入文件内容。
|
||
- “复制诊断信息”继续输出可粘贴摘要,不默认复制完整日志。
|
||
|
||
`NodeHostSnapshot` 至少包含:
|
||
|
||
- 当前节点状态和状态变化时间。
|
||
- 当前会话 ID 或本地连接代次,不包含凭据。
|
||
- 活动 Job、当前阶段和开始时间。
|
||
- 待恢复/待上传数量。
|
||
- Adapter 数量、能力摘要和最近 probe 时间。
|
||
- data root 和版本信息。
|
||
|
||
## 10. 测试策略
|
||
|
||
### 10.1 Characterization 测试
|
||
|
||
重构前固定当前行为:
|
||
|
||
- CLI 参数、stdout/stderr 标签和退出码。
|
||
- 未注册、在线、身份失效和普通断线状态差异。
|
||
- offer 先落盘后 accept。
|
||
- 重复 Job digest 校验。
|
||
- 终态与上传重试幂等。
|
||
- Workspace promotion 与 rollback。
|
||
- 活动任务退出的等待和取消路径。
|
||
- 数据目录迁移的停止、复制、校验和切换顺序。
|
||
|
||
### 10.2 .NET 单元测试
|
||
|
||
新增 `Zcbot.WindowsNode.Tests`,优先测试:
|
||
|
||
- `JobStateMachine` 合法和非法转换。
|
||
- `NodeHost` 启停、重复停止和重连屏障。
|
||
- `NodeProtocolCodec` 消息分类及错误处理。
|
||
- `JobRecoveryService` 对各持久化阶段的恢复决策。
|
||
- `TransferRetryPolicy` 对认证、网络、服务端和取消错误的分类。
|
||
- `AdapterContractLoader` 的路径、manifest、版本与合同校验。
|
||
- ViewModel Snapshot 映射、Command 可用性和异步失败恢复。
|
||
|
||
测试使用临时目录和可控的 HTTP handler/协议替身;不连接 `.env` 中的数据库或生产服务。
|
||
|
||
### 10.3 集成测试
|
||
|
||
- 本地假 WebSocket 服务完成 hello、心跳、offer、cancel 和重连。
|
||
- 固定测试 Worker 验证启动、超时、取消和进程树回收。
|
||
- 临时 data root 验证重启恢复、原子写和 Workspace promotion。
|
||
- framework-dependent 与 self-contained 两种发布包完成启动烟测。
|
||
- 发布包验证 Adapter、合同、验收资产和 requirements 完整。
|
||
|
||
### 10.4 UI 验收
|
||
|
||
- 未注册首次启动。
|
||
- 已注册后台启动和托盘显示。
|
||
- 托盘双击、窗口隐藏和恢复。
|
||
- 注册、重连、清身份和复制诊断。
|
||
- 软件自动检测、手选、清除和 runtime 安装。
|
||
- ANSYS 固定验收、取消、通过报告和执行门。
|
||
- 本机任务刷新、选中详情和重启后恢复。
|
||
- 活动任务等待退出、取消退出和返回。
|
||
- 100%、125%、150%、200% DPI。
|
||
|
||
### 10.5 现有 Python 源码测试调整
|
||
|
||
保留适合静态审计的测试:
|
||
|
||
- 项目目标框架和发布参数。
|
||
- 不暴露任意执行原语。
|
||
- Adapter 与合同是否完整打包。
|
||
- Token 不以明文模型字段或日志字段出现。
|
||
- 独立 Adapter 包不依赖重建 Node。
|
||
|
||
将控件名称、WinForms 布局字符串、按钮宽度等断言替换为 .NET 行为测试或 WPF 结构测试,避免测试阻止内部文件拆分。
|
||
|
||
## 11. 实施阶段
|
||
|
||
### 阶段 0:基线与保护网
|
||
|
||
- 固化功能、协议、持久化和发布包基线。
|
||
- 增加关键生命周期 Characterization 测试。
|
||
- 记录真机 DPI 与托盘行为。
|
||
- 不改变生产行为。
|
||
|
||
完成门槛:现有 build、专项测试、打包和启动烟测全部通过。
|
||
|
||
### 阶段 1:Composition Root 与应用控制器
|
||
|
||
- 引入唯一 `NodeCompositionRoot`。
|
||
- 从托盘类提取注册、连接、重连、迁移和退出编排。
|
||
- GUI 与 headless 共用 Host 构造路径。
|
||
- WinForms 界面保持不变。
|
||
|
||
完成门槛:现有界面和 CLI 行为完全等价。
|
||
|
||
### 阶段 2:Job 持久化与状态机
|
||
|
||
- 提取 `JobRepository`、`JobStateMachine` 和 `JobRecoveryService`。
|
||
- 集中原子文件和路径约束。
|
||
- 保持现有落盘格式,验证新版能恢复旧 Job。
|
||
- 增加状态机和恢复测试。
|
||
|
||
完成门槛:旧 Job 样本可恢复,终态与 Workspace 不回退。
|
||
|
||
### 阶段 3:会话、协议与传输
|
||
|
||
- 拆分 `NodeSession`、`NodeProtocolCodec` 和 `NodeProtocolClient`。
|
||
- 引入共享 `NodeHttpClient`。
|
||
- 统一错误分类、认证注入和安全重试。
|
||
- 由 `JobCoordinator` 接管消息业务编排。
|
||
|
||
完成门槛:假服务端重连、offer、cancel、上传重试和身份拒绝测试通过。
|
||
|
||
### 阶段 4:Adapter、进程与 runtime
|
||
|
||
- 提取 `AdapterCatalog`、`AdapterExecutionService` 和 `ProcessSupervisor`。
|
||
- 拆分软件位置、probe 和 runtime 安装。
|
||
- 统一活动任务执行门和取消收尾。
|
||
- 不改 Adapter 文件或合同。
|
||
|
||
完成门槛:Origin、ANSYS、Blender 现有 probe、执行、取消和打包测试通过。
|
||
|
||
### 阶段 5:WPF Shell 与托盘
|
||
|
||
- 启用 WPF,建立 App、MainWindow、资源字典和 ViewModel 基础设施。
|
||
- 保留 WinForms NotifyIcon。
|
||
- 完成无参数 GUI、CLI 和 headless 启动分流。
|
||
- 先建立空页面与完整生命周期,不删除旧窗口。
|
||
|
||
完成门槛:单实例、后台启动、显示/隐藏和安全退出通过。
|
||
|
||
### 阶段 6:逐页迁移
|
||
|
||
按以下顺序迁移:
|
||
|
||
1. 节点概览与首次注册。
|
||
2. 运行设置与数据目录迁移。
|
||
3. 专业软件卡和 runtime 管理。
|
||
4. ANSYS 固定验收。
|
||
5. 本机任务列表和详情。
|
||
|
||
完成门槛:每一页迁移后均完成行为等价检查,不等待最后一次性验收。
|
||
|
||
### 阶段 7:移除 WinForms 主窗口与加固
|
||
|
||
- 删除 `ConfigurationForm` 和旧 `TrayApplicationContext`。
|
||
- 保留 NotifyIcon 所需的最小 WinForms 依赖。
|
||
- 清理重复状态、静态 Service Locator 和临时兼容代码。
|
||
- 完成本机结构化日志与诊断摘要。
|
||
- 完成全量专项测试和发布包真机烟测。
|
||
|
||
完成门槛:源码中没有第二套可达 UI 或重复 Host 生命周期。
|
||
|
||
### 阶段 8:文档与发布准备
|
||
|
||
- 架构落地后把稳定决策同步到根 `DESIGN.md`。
|
||
- 如运行方式、诊断路径或部署步骤有变化,同步 `RUN.md` 和 `windows-node/README.md`。
|
||
- 阶段性成果更新 `PROGRESS.md`。
|
||
- WPF 稳定前不提升版本号,不创建已发布 Changelog 版本。
|
||
- 准备上线时再通过独立 release commit 更新版本和用户版 Changelog。
|
||
|
||
## 12. 建议提交拆分
|
||
|
||
每个提交只包含一个可验证的逻辑变化:
|
||
|
||
1. `test(windows-node): characterize host lifecycle`
|
||
2. `refactor(windows-node): add shared composition root`
|
||
3. `refactor(windows-node): extract job state and persistence`
|
||
4. `refactor(windows-node): separate session and protocol handling`
|
||
5. `refactor(windows-node): unify job transfers`
|
||
6. `refactor(windows-node): extract adapter process supervision`
|
||
7. `refactor(windows-node): split software runtime services`
|
||
8. `feat(windows-node): add wpf shell and tray host`
|
||
9. `feat(windows-node): migrate overview and settings views`
|
||
10. `feat(windows-node): migrate software and acceptance views`
|
||
11. `feat(windows-node): migrate local job monitor`
|
||
12. `refactor(windows-node): remove legacy winforms window`
|
||
13. `test(windows-node): cover wpf and host integration`
|
||
14. `docs(windows-node): document host and wpf architecture`
|
||
|
||
实施中可根据实际依赖合并相邻提交,但不得将 Host 重构、UI 视觉调整和发布版本提升混入同一提交。
|
||
|
||
## 13. 风险与控制
|
||
|
||
| 风险 | 控制措施 |
|
||
|---|---|
|
||
| 重连时重复启动任务 | Host 统一拥有会话代次和单槽执行门 |
|
||
| 退出后残留 Worker | 所有进程归 `ProcessSupervisor`,停止时等待完整树退出 |
|
||
| 上传重试导致重复执行 | 执行终态与传输状态分离,传输只重放幂等上传 |
|
||
| 后台线程更新 WPF 集合 | Snapshot 在 Dispatcher 上映射到 ObservableCollection |
|
||
| 新版无法恢复旧 Job | 不改落盘字段,使用历史样本做恢复测试 |
|
||
| 数据迁移期间重新接单 | Controller 先停调度并等待安全屏障,再执行迁移 |
|
||
| runtime 安装覆盖活动环境 | 本机执行门检查活动 Job,临时安装验证后原子替换 |
|
||
| Token 泄露到日志或 UI | 集中认证客户端、脱敏器和诊断字段 allowlist |
|
||
| WPF 与 WinForms 类型冲突 | WinForms 仅限 Tray 命名空间并使用完整类型名 |
|
||
| 重构范围失控 | 非目标列表和阶段完成门槛作为 review gate |
|
||
|
||
## 14. 回退策略
|
||
|
||
- 整个改动在独立功能分支完成,WPF 稳定前不让线上用户接触。
|
||
- 每个阶段保持可构建,Host 抽取阶段继续由旧 WinForms UI 驱动。
|
||
- WPF 迁移期间旧窗口可作为开发对照,但最终合并前必须只有一套可达 UI。
|
||
- 发布前保留上一版完整 Node 程序包;回退只替换程序目录,不修改 data root。
|
||
- 因持久化格式保持兼容,回退旧 EXE 后仍能读取原有身份、Job 和 Workspace。
|
||
- 若实施中确需新增持久化字段,必须做到旧版本忽略、新版本可缺省,且在本方案中补充独立兼容说明。
|
||
|
||
## 15. 完成定义
|
||
|
||
满足以下条件才视为重构完成:
|
||
|
||
- WinForms `ConfigurationForm` 已移除,主界面全部使用 WPF。
|
||
- WinForms 仅用于 NotifyIcon 或已明确记录的必要互操作。
|
||
- GUI 和 headless 从同一个 Composition Root 获得 Node Host。
|
||
- `NodeConnectionLoop` 的会话、协议和 Job 编排职责已拆分。
|
||
- `JobInboxStore` 的持久化、恢复、状态机和 UI 展示职责已拆分。
|
||
- `SoftwareRuntimeManager` 的定义、位置、probe 和安装职责已拆分。
|
||
- 关键 Host 生命周期和 Job 状态转换有真实 .NET 行为测试。
|
||
- 旧节点身份、历史 Job 和 Workspace 在新版测试样本中可继续使用。
|
||
- Origin、ANSYS、Blender Adapter 无需修改即可运行。
|
||
- framework-dependent 与 self-contained 发布包均通过构建和启动烟测。
|
||
- 真机托盘、DPI、runtime 安装、任务执行、取消、上传和安全退出验收通过。
|
||
- `DESIGN.md`、`RUN.md`、`PROGRESS.md` 和 Windows Node README 已按实际落地范围同步。
|
||
|
||
## 16. 首个实施切片
|
||
|
||
建议第一个开发切片只做以下内容:
|
||
|
||
1. 增加 Host 生命周期 Characterization 测试。
|
||
2. 引入 `NodeCompositionRoot`,消除 GUI 与 headless 的重复构造路径。
|
||
3. 提取 `NodeApplicationController`,从托盘类移出注册、重连、迁移和退出编排。
|
||
4. 让现有 WinForms UI 继续驱动新的 Controller。
|
||
5. 完成 build、专项测试、打包和启动烟测。
|
||
|
||
该切片不启用 WPF、不移动 Job 格式、不改 Adapter,也不改变用户可见界面。它先建立后续 Host 重构和 WPF 迁移共同依赖的稳定边界,风险最低、验证价值最高。
|
||
|
||
### 16.1 实施记录(2026-08-31)
|
||
|
||
首个切片已完成:新增 `Zcbot.WindowsNode.Tests` 与 Host 生命周期行为测试;引入唯一 `NodeCompositionRoot` 和 UI 无关的 `NodeApplicationController`;GUI 与 `run --headless` 已共用组装入口;注册、重连、清除身份、迁移和安全退出编排已从托盘类移入 Controller。现有 WinForms 主窗口、协议、Job/Workspace 落盘格式、Adapter 和发布目录均保持不变。
|
||
|
||
验证已覆盖未注册启动、重连收尾屏障、幂等停止、取消退出、迁移失败重启和清身份收尾;.NET 测试、既有 Windows Node 源码专项测试、solution build、framework-dependent 打包及 GUI/headless 启动烟测通过。下一切片进入阶段 2,提取 Job 持久化、状态机与恢复决策。
|
||
|
||
### 16.2 阶段 2 实施记录(2026-08-31)
|
||
|
||
Job 持久化、状态和恢复边界已提取:`JobRepository` 直接负责既有 request/state/terminal/marker 目录的读取与原子写,`JobStateMachine` 约束正常单向转换并以显式 `Recovery` 模式兼容重启后的输入复验和历史成功任务续传,`JobRecoveryService` 将落盘事实分类为续执行、续上传、重放终态和无需动作。`AtomicFile` 与 `PathGuard` 集中保持同目录临时文件、flush 后替换和 Job 派生路径不越界;`JobInboxStore` 暂时保留 offer 校验、旧调用薄入口和 UI 展示读取,后续由协议与 `JobMonitorService` 切片继续收窄。
|
||
|
||
新增测试覆盖完整状态图、非法回退、终态不可重开、恢复例外、旧 request/state 样本无迁移读取、终态幂等、offer 先持久化及 digest/lease 重放、Workspace promotion/rollback、原子替换和路径穿越拒绝。40 项 .NET 行为测试、25 项既有源码专项、格式检查、Release 发布包及 headless 启动烟测通过;下一切片进入阶段 3,会话、协议与传输拆分。
|
||
|
||
### 16.3 阶段 3 实施记录(2026-08-31)
|
||
|
||
会话、协议和 Job 编排已从原连接循环分离:`NodeSession` 负责连接、hello、心跳、单接收循环与退避重连,`NodeProtocolCodec` 保持既有消息信封并允许未知消息按原策略忽略,`NodeProtocolClient` 集中处理文本分片、1 MiB 上限、身份关闭语义和发送锁;`JobCoordinator` 接管 offer、cancel、export、恢复回报及本地执行流水线,新的 `NodeConnectionLoop` 只组合并收尾两者。
|
||
|
||
输入下载和输出上传现共用每份已加载配置唯一的 `NodeHttpClient`,统一 BaseAddress、Bearer、Node ID 与 User-Agent;lease/digest 保持逐请求 Header,避免共享 Header 竞争。`TransferRetryPolicy` 将认证、瞬时、永久和取消错误分开,只有无请求体的 GET 下载执行有界自动重试,输出上传继续依赖既有服务端幂等确认与落盘恢复,不会因传输重试重新执行专业软件。新增假 WebSocket/HTTP handler 测试覆盖信封兼容、未知消息、分片接收、并发发送、4003 身份拒绝、断线重连、认证不重试和瞬时下载重试;57 项 .NET 行为测试、25 项源码专项、格式与 diff 检查、Release 发布包及隔离数据目录 headless 烟测通过。下一切片进入阶段 4,拆分 Adapter、进程监督与 runtime。
|
||
|
||
### 16.4 阶段 4 实施记录(2026-08-31)
|
||
|
||
Adapter 发现、合同、执行和进程边界已拆分:`AdapterCatalog` 以线程安全 Lazy 在启动期一次发现并缓存已安装描述符,`AdapterContractLoader` 负责 manifest 白名单、版本/runtime、相对路径边界、合同 capability、Workspace 输出、JSON Schema、入口扩展名和 SHA-256;`AdapterExecutionService` 保留既有 Job 目录协议、终态读取、Workspace promotion/restore 和错误码,所有 capability 共享 `JobExecutionGate`,不再只依赖云端 slot。`ProcessSupervisor` 统一固定进程启动、受限标准流采集、取消、完整进程树终止和 30 秒退出确认;对不存在 Job 的取消不再创建遗留 CTS。
|
||
|
||
软件与 runtime 已拆为 `SoftwareCatalog`、`SoftwareLocationService`、`SoftwareProbeService` 和 `ManagedRuntimeInstaller`。Origin/ANSYS/Blender 固定定义、兼容环境变量、注册表与标准目录检测顺序保持不变,probe 保持 30 秒缓存并可在 runtime 更新后显式失效;安装器仍只接受内置 requirements 和固定 Python 3.12 发现方式,在临时目录验证后原子替换并保留失败 rollback,同时在入口机械拒绝活动执行。新增行为测试覆盖已打包 Adapter 合同加载、跨 capability 单槽、等待取消、软件目录定义和 probe 缓存失效;62 项 .NET 行为测试、122 项 Origin/ANSYS/Blender/合同/Node 专项、格式与 diff 检查、Release 发布包及隔离数据目录 headless 烟测通过。下一切片进入阶段 5,建立 WPF Shell、ViewModel 基础设施及 NotifyIcon 互操作。
|
||
|
||
### 16.5 阶段 5 实施记录(2026-08-31)
|
||
|
||
GUI 入口已切换为 WPF `Application` 消息循环,新增 `MainWindow`、Light 资源字典、`ObservableObject`、同步/异步 Command 和 `MainWindowViewModel`。主窗口提供节点状态总览、隐藏到托盘、安全退出及经典配置入口;关闭窗口只隐藏,不终止后台节点。新的 `TrayHost` 通过显式 WinForms 类型别名管理 `NotifyIcon`,把 Controller 状态切回 WPF Dispatcher,延续托盘双击、重连、三选一活动任务退出和取消二次确认。尚未迁移的注册、专业软件、验收、本机任务和数据目录功能仍由按需创建的 `ConfigurationForm` 承担,阶段 8 完成前保持可达。
|
||
|
||
CLI 参数分支仍在创建任何 WPF 对象前执行,`run --headless`、单实例互斥体、Composition Root 和 Controller 生命周期保持原语义。新增 ViewModel 状态映射、命令转发、异步命令防重入与异常报告测试;66 项 .NET 行为测试、188 项 Origin/ANSYS/Blender/合同/Node 专项、格式与 diff 检查、framework-dependent Release 包、隔离 GUI 消息循环及 headless 返回码烟测通过。下一切片进入阶段 6,迁移节点概览、注册与运行设置页面。
|
||
|
||
### 16.6 阶段 6 第一切片实施记录(2026-08-31)
|
||
|
||
节点概览、首次注册和运行设置基础能力已迁入 WPF。`MainWindowViewModel` 现在持有页面导航、身份摘要、注册字段、操作反馈及 Command 可用状态,通过事件边界复用 Controller 的注册、重连和清身份流程;一次性注册码由 `PasswordBox` 同步到 ViewModel,注册成功或身份状态刷新后立即清空。清身份继续二次确认,注册继续使用 `EnrollOptions` 的 URL、名称和注册码校验。登录自启动经 `IStartupRegistration` 接口调用当前账号 `Run` 项,权限或 IO 失败会保留原开关状态并展示错误。运行设置展示实际 data root,迁移按钮暂时进入经典配置,以继续使用已有活动任务检查、固定磁盘校验、复制摘要和重启流程。
|
||
|
||
专业软件、runtime、ANSYS 验收、本机任务和数据目录迁移尚未迁入 WPF,因此本记录不把阶段 6 标为整体完成。新增测试覆盖 WPF 页面导航、身份映射、注册参数转发、自启动成功与失败回滚,源码契约确认 WPF 不直接依赖 Controller;69 项 .NET 行为测试、189 项 Origin/ANSYS/Blender/合同/Node 专项、格式与 diff 检查、framework-dependent Release 包及隔离 GUI/headless 烟测通过。下一切片迁移专业软件卡与 runtime 管理。
|
||
|
||
### 16.7 阶段 6 第二切片实施记录(2026-08-31)
|
||
|
||
专业软件卡和 runtime 管理已迁入 WPF。新的 `SoftwareManagementService` 组合 `SoftwareCatalog`、`SoftwareLocationService`、Adapter probe 和 `ManagedRuntimeInstaller`,向 Presentation 只暴露不可变快照与受控操作;`SoftwarePageViewModel` 在用户进入页面后异步刷新 Origin、ANSYS、Blender 卡片,支持选择严格匹配的 EXE/安装根目录、清除账号级配置后恢复自动检测、安装或更新隔离 runtime,以及显式取消安装。文件和目录对话框、安装确认仍封装在 Tray WinForms 互操作层,WPF ViewModel 不读取注册表、不创建进程,也不接触任意命令。
|
||
|
||
软件快照直接读取 `AdapterCatalog.HasActiveExecution`,全机任一 Job 执行时均禁用 runtime 安装;即使 UI 快照过期,安装器入口仍会二次拒绝活动执行。安装继续固定 Python 3.12、内置 requirements 和镜像配置,在临时目录验证后原子切换,取消时终止完整安装进程树,失败保持原 runtime。新增测试覆盖软件卡刷新、位置保存与清除、安装确认/结果、活动任务禁用和取消收尾;73 项 .NET 行为测试、190 项 Origin/ANSYS/Blender/合同/Node 专项、格式与 diff 检查、framework-dependent Release 包及隔离 GUI/headless 烟测通过,未执行真实安装或启动专业软件。下一切片迁移 ANSYS 固定验收。
|
||
|
||
### 16.8 WPF UI 打磨记录(2026-08-31)
|
||
|
||
在不改变页面命令和 Host 生命周期的前提下,Light 主题补齐集中颜色、表面、边框、状态和间距 token,并用 WPF ControlTemplate 统一按钮与侧栏导航的圆角、悬停、按下、禁用和键盘焦点状态。侧栏使用单选视觉的 ToggleButton 显示当前页,页头增加实时节点状态徽标,概览卡增加同源状态色带,软件卡增加位置可用性徽标和安装忙碌进度;操作区改用 WrapPanel,在 760 px 最小窗口下可自动换行。操作结果改为独立提示条,仅在有消息时占位,减少与底部常驻说明的竞争。
|
||
|
||
新增 UI 结构契约覆盖导航选中绑定、状态 tone、响应式操作区、忙碌反馈和主题资源,既有 ViewModel 测试补充状态色与提示可见性;73 项 .NET 行为测试、191 项 Origin/ANSYS/Blender/合同/Node/UI 专项、格式与 diff 检查、framework-dependent Release 包及隔离 GUI/headless 烟测通过。纯视觉改动未改变 CLI、托盘、注册、runtime 安装或持久化契约。
|
||
|
||
### 16.9 阶段 6 第三切片实施记录(2026-08-31)
|
||
|
||
按主导航可用性优先,将本机任务迁移提前到 ANSYS 固定验收之前。`JobMonitorService` 从 `JobInboxStore` 接管面向 UI 的只读快照生成,继续合并 request、state、terminal、cloud-terminal 和 upload-complete 落盘事实,不改变既有 Job 目录或恢复协议。新的 `JobPageViewModel` 负责状态中文映射、执行时长、摘要、选中详情与按 Job ID 保持选择;WPF 页面以只读表格展示最近 50 条记录,进入页面立即刷新,并在窗口可见且任务页激活时每秒刷新。侧栏“本机任务”不再打开经典配置。
|
||
|
||
新增测试覆盖快照刷新、状态格式、读取失败、刷新后选择保持,以及真实 WPF 资源加载后的四页互斥可见性和标题绑定;94 项 .NET 行为测试、28 项 Windows Node 源码专项、格式与 diff 检查通过。阶段 6 尚余 ANSYS 固定验收和数据目录完整迁移,完成后再删除经典任务页及其 WinForms 定时器,避免迁移期间影响现有回退入口。
|
||
|
||
### 16.10 阶段 6 完成记录(2026-08-31)
|
||
|
||
ANSYS 固定验收和数据目录完整迁移已进入 WPF。`AnsysAcceptanceService` 固定绑定已打包的 `ansys.mechanical.static_structural@v2` 验收入口,ViewModel 提供报告目录选择、长时进度、显式停止、通过报告校验和机器级执行门;执行门仍要求本次报告 `passed=true`、用户确认许可证已释放,并在权限不足时保持关闭。`DataRootPageViewModel` 通过 `DataRootManagementService` 检查环境变量托管与未完成任务,目标规范化和二次确认后只调用 Controller 的迁移编排,继续保持停连、复制、逐文件 SHA-256 校验、成功后保存新根目录与失败重连回滚。
|
||
|
||
### 16.11 阶段 7 完成记录(2026-08-31)
|
||
|
||
诊断摘要提取为 `DiagnosticService` 并由 WPF 概览页复制,内容继续排除 Node Token。删除 `ConfigurationForm` 和旧 `TrayApplicationContext`,托盘菜单不再暴露经典配置入口;WinForms 仅保留 `NotifyIcon`、固定文件/目录选择、确认框和剪贴板互操作。Presentation 不直接持有 Controller,不解析 Job JSON,不访问注册表,也不创建 Worker;117 项 .NET 行为测试、28 项 Windows Node 源码专项、格式与 diff 检查通过。下一步进入阶段 8 发布准备与目标机 DPI/GUI 烟测。
|