# Local G2 任务 8 前稳定化设计

**日期：** 2026-07-31
**状态：** 已经用户确认，待实施计划
**范围：** 修复进入任务 8 前的 P0/P1 阻断，不实现任务 8 的正式发布流水线

## 1. 背景

Local G2 五次 Hermite 模块已经具备曲率事件检测、局部窗口规划、候选构造、拼接和质量评价能力，但在接入正式流水线前存在三个阻断：

1. `RectangleDetour` 的 Hybrid A* 粗路径规划成功，平滑模块重建原始基线时却返回 `InvalidInput`。
2. `MaximumWindowLengthMeters = 0.80` 的语义应为左右窗口总长度，但当前事件合并阶段把它当成每侧都可扩展 `0.80 m`。
3. 拼接一个上游区域后会重算整个方向段的局部弧长，后续区域若仍使用原始弧长，可能命中错误位置。

当前源码已经恢复可构建。设计审查时的基线为：

- `dotnet build ClumsyPilot/ClumsyPilot.csproj --no-restore`：成功，0 个错误；
- 路径几何、Local G2 检测和 Local G2 候选专项检查：通过；
- `verify_path_smoothing_integration.ps1`：稳定失败于 `RectangleDetour` 原始基线。

## 2. 目标与非目标

### 2.1 目标

- 消除合法极限曲率圆弧被离散弦长误判为超限的问题，且不削弱候选安全门。
- 统一 `0.80 m` 为局部替换窗口的最大总长度。
- 保证一个合并区域实际能够生成至少一个覆盖全部事件的合法窗口。
- 固定同一方向段内从后向前的区域处理顺序，为任务 8 提供不会发生弧长错位的工作顺序。
- 用失败先行的自动回归锁定三项行为。

### 2.2 非目标

- 不实现 `LocalG2PreSmoothingPipeline`。
- 不把 `LocalG2Quintic` 接入 `PathSmoothingService`。
- 不新增 RectangleDetour 碰撞位置、最小净空或可视化诊断输出。
- 不调整车辆最大曲率、碰撞门限、净空门限或验证器容差来换取测试通过。
- 不修改三种旧平滑算法的选择、重试或排序策略。

现有完整车体和扫掠验证仍然保留。RectangleDetour 的原始基线只有在现有验证全部通过后才能返回 `Success`。

## 3. P0：曲率基线误判

### 3.1 已确认根因

粗路径运动基元携带真实车辆曲率和真实积分弧长。RectangleDetour 的最大车辆曲率为：

```text
0.833333333333333 1/m
```

该值等于车辆允许上限。`PathGeometryAnalyzer` 丢弃粗路径的逐点车辆曲率，以重采样点之间的欧氏弦长作为弧长，再用：

```text
Δheading / chord-length
```

恢复曲率。同一圆弧因此得到：

```text
0.833348403933077 1/m
```

误差大于验证器的 `1e-6` 数值容差，原始基线在进入碰撞循环前被拒绝。

### 3.2 首选修复：经过认证的共享离散曲率估计器

首选方案是在 `PathGeometryAnalyzer` 中使用带符号圆弧—弦长关系：

```text
kappa = 2 * sin(deltaHeading / 2) / chordLength
```

采样对定义如下：

- `deltaHeading` 使用沿路径连续展开后的带符号航向差，不直接对原始角度值相减；
- 首点：使用点 `0` 和点 `1` 的航向差与位置弦长；
- 末点：使用倒数第 `2` 点和末点的航向差与位置弦长；
- 内部点 `i`：使用点 `i-1` 和点 `i+1` 的航向差与位置弦长；
- 倒车段只在几何曲率生成后按现有方向符号转换为车辆曲率；
- 非有限弦长、退化弦长或无法唯一展开的转角继续返回失败。

该公式对恒定半径圆弧精确，能够消除本次由弦长短于圆弧长度引起的系统性高估。

### 3.3 安全认证门

共享估计器影响原始基线、旧平滑算法和 Local G2 候选，因此不得只凭 RectangleDetour 变绿就接受。实施必须先建立下列失败回归：

1. 最大允许曲率的前进与倒车圆弧，在首点、内部点和末点都不得超过真实曲率与数值容差之和。
2. 明确超出车辆曲率上限的圆弧仍必须被验证器拒绝。
3. 对带解析一、二阶导数的五次 Hermite 曲线进行稠密参考采样；新估计器对解析最大曲率的单侧低估量，不得大于旧估计器的单侧低估量加 `1e-6`。
4. S 弯、曲率峰值靠近端点、前进、倒车和非均匀末段采样都必须覆盖。
5. 所有现有几何、验证、旧算法和 Local G2 候选检查必须保持通过。

单侧低估量定义为：

```text
max(0, analyticMaximumCurvature - estimatedMaximumCurvature)
```

若共享估计器不满足上述认证门，则禁止全局替换。

### 3.4 双条件门控的限定回退

仅在以下任一条件成立时，才允许改用原始基线专用方案：

1. 首选共享估计器不能通过第 3.3 节的安全认证；或
2. 原始基线经共享分析器重建后，未改动的验证器明确因非有限或超限的**重建曲率**而拒绝，同时对应的可信粗路径 `VehicleCurvature` 是有限值且不超过车辆曲率上限。

- 原始基线保留 `CoarsePathPoint.VehicleCurvature` 和粗路径真实 `ArcLength`；
- 在每个方向段内直接由真实曲率序列计算 `dκ/ds`、总绝对曲率变化和变化代价；
- 使用原粗路径位姿执行现有完整车体和扫掠验证；
- 回退结果必须重新运行现有完整验证器；
- 候选路径继续使用共享几何分析器，不改变候选安全门。

该回退只允许用于原始粗路径，因为粗路径运动基元提供了可信的真实曲率；普通平滑候选没有同等来源的数据。它不放宽车辆曲率、碰撞、净空或验证器容差。

### 3.5 P0 验收

- 极限圆弧回归通过；
- 超限圆弧仍被拒绝；
- RectangleDetour 原始基线返回 `Success`；
- 不修改车辆最大曲率和验证器容差；
- `verify_path_smoothing_integration.ps1` 不再在 RectangleDetour 原始基线处失败。

## 4. P1：窗口总长度和合并语义

### 4.1 唯一长度语义

以下三个配置始终表示一个候选替换窗口的总长度：

| 配置 | 默认值 | 唯一语义 |
|---|---:|---|
| `MinimumWindowLengthMeters` | `0.20` | 左窗口加右窗口的最小总长度 |
| `PreferredWindowLengthMeters` | `0.50` | 左窗口加右窗口的首选总长度 |
| `MaximumWindowLengthMeters` | `0.80` | 左窗口加右窗口的最大总长度 |

对称候选的 `0.80 m` 表示左右约各 `0.40 m`，不表示左右各 `0.80 m`。靠近方向段边界时允许把缺失长度转移到另一侧，但总长度不能超过 `0.80 m`。

### 4.2 以候选可生成性决定合并

窗口规划器继续按方向段和事件弧长稳定排序。对同一方向段中的下一个事件，使用以下规则：

1. 将下一个事件加入临时事件组；
2. 用现有目标长度和左右比例为临时事件组构造窗口变体；
3. 只有临时事件组至少产生一个能够覆盖全部事件、总长度不超过最大值的窗口，才接受合并；
4. 如果没有合法窗口，结束当前区域，并从下一个事件建立新区域。

事件按弧长升序排列，因此一个更远事件不能加入当前组时，后续事件也不再尝试加入该组。

### 4.3 区域包络

`MaximumStartArcLengthMeters` 和 `MaximumEndArcLengthMeters` 当前没有运行时消费者，但任务 8 的区域报告可能使用它们。保留字段，并将语义改为：

- `MaximumStartArcLengthMeters`：该区域实际合法窗口中的最小起点；
- `MaximumEndArcLengthMeters`：该区域实际合法窗口中的最大终点。

不得继续保存 `event ± MaximumWindowLengthMeters` 的虚假包络。

### 4.4 窗口验收

- 相距 `1.0 m` 的两个事件在默认配置下形成两个独立区域；
- 能被同一 `0.80 m` 总窗口覆盖的相邻事件仍能合并；
- 三个事件只合并实际可被同一合法窗口覆盖的连续子组；
- 靠近方向段起点或终点的事件能够生成总长度受限的不对称窗口；
- 每个成功规划的区域至少包含一个合法窗口；
- 同一输入重复运行的区域分组、窗口顺序和候选编号一致。

## 5. P1：多区域弧长稳定性

### 5.1 处理顺序

任务 8 必须使用两个不同顺序：

- **工作顺序：** 方向段编号升序；同一方向段内按原始局部弧长降序；
- **报告顺序：** 保留检测器产生的原始方向段/弧长升序。

跨方向段的局部弧长彼此独立。对同一方向段，从后向前替换时，后方替换不会改变前方窗口之前的点或累计弧长，因此前方候选仍能使用原始坐标。

### 5.2 任务 8 前可完成的保障

在任务 8 前增加一个独立、确定性的区域工作顺序组件，并增加底层双窗口回归：

1. 在同一方向段创建两个互不重叠的区域 A、B，其中 B 位于 A 后方；
2. 先替换 B，并要求替换产生可观测的路径长度变化；
3. 验证 A 的原始起止弧长仍对应原始语义位置；
4. 再替换 A，验证两个替换都保留且路径拓扑完整；
5. 重复运行并比较工作顺序、点数和点坐标。

测试还必须证明相反顺序会使 B 的原始绝对弧长不再对应原始语义位置，从而锁定逆序规则存在的必要性。

### 5.3 任务 8 的硬性接入门

多区域问题在任务 8 前只能完成排序组件和底层证明，不能宣称端到端修复。任务 8 必须：

- 直接使用该区域工作顺序组件；
- 候选仍从不可变原始路径构造，评价和拼接作用于当前路径；
- 区域报告按原始顺序发布；
- 在两个区域都可能改善的真实流水线测试中验证第二个处理区域命中正确位置；
- 相同请求连续运行两次，状态、路径、候选编号和区域报告一致。

未满足这些条件时，`LocalG2Quintic` 不得接入正式服务。

## 6. 数据流

任务 8 前稳定化后的数据流为：

```text
CoarsePath
  -> PathSmoothingPreprocessor
  -> 原始基线曲率/安全复核
  -> CurvatureTransitionDetector
  -> LocalG2WindowPlanner（以合法候选决定合并）
  -> RegionWorkOrder（同段从后向前）
  -> 任务 8 接入门
```

本阶段不会调用不存在的正式流水线。

## 7. 错误处理

- 曲率估计产生非有限值、退化弦或模糊大转角：返回稳定失败，不发布路径。
- 单事件无法生成任何窗口：窗口规划失败并给出稳定原因，不静默丢弃事件。
- 临时联合事件组没有合法窗口：不视为全局失败，结束当前组并从下一个事件创建区域。
- 区域排序输入包含空区域、非法方向段或非有限弧长：拒绝排序。
- P0 首选估计器认证失败，或原始基线重建仅因非有限/超限曲率被验证器拒绝且可信粗路径曲率仍在车辆上限内：不放宽安全门，按第 3.4 节改用限定原始基线方案。

## 8. 实施边界与预期文件

实施计划可以修改或新增以下范围内的文件：

- `PathSmoothing/Processing/PathGeometryAnalyzer.cs`
- `PathSmoothing/Processing/RawPathBaselineBuilder.cs`（仅当启用限定回退）
- `PathSmoothing/LocalG2/LocalG2WindowPlanner.cs`
- `PathSmoothing/LocalG2/LocalG2SmoothingRegion.cs`
- 新的内部区域工作顺序组件
- `verify_path_smoothing_geometry.ps1`
- `verify_path_smoothing_integration.ps1`
- `verify_path_smoothing_local_g2_detection.ps1`
- `verify_path_smoothing_local_g2_candidates.ps1`

不得在本阶段创建 `LocalG2PreSmoothingPipeline.cs` 或修改服务分派。

## 9. 完成标准

本阶段只有同时满足以下条件才算完成：

1. 当前项目构建成功；
2. P0 曲率修复通过安全认证门，或明确采用并验证限定回退；
3. RectangleDetour 原始基线通过；
4. `0.80 m` 总窗口语义和 `1.0 m` 分组回归通过；
5. 双区域逆序处理底层回归通过；
6. 原有 PathSmoothing 几何、验证、服务、比较和 Local G2 专项检查不回归；
7. 任务 8 计划明确引用区域工作顺序组件和双区域端到端硬门。

本阶段完成只表示“具备进入任务 8 的条件”，不表示 Local G2 已经成为正式可用服务。
