chore: 停止跟踪日报和开发规格文档
This commit is contained in:
-22
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"captured_at": "2026-08-03T12:00:19+08:00",
|
||||
"date": "2026-08-03",
|
||||
"module": "daily-summary-job",
|
||||
"summary": "daily-summary-job 个人技能已完成设计、安装和自动化验证,当前进入真实项目试用阶段。",
|
||||
"achievements": [
|
||||
"完成个人技能安装,并支持记录进展、生成日报和更新日报三类按需触发。",
|
||||
"建立模块自动识别、目录自动初始化、日期命名和 Markdown/HTML 成对归档规则。",
|
||||
"实现持久化精简检查点,支持从多 Agent 工作证据中逐步汇总而不依赖完整对话上下文。",
|
||||
"实现自包含交互式 HTML,可筛选问题、切换现状/目标、查看原因链、解决步骤、验证门和路线图。",
|
||||
"完成技能结构校验、31 项自动测试、JavaScript 语法检查和临时项目端到端验证。"
|
||||
],
|
||||
"issues": [
|
||||
"Windows 默认 Python/PowerShell 输出编码可能导致中文路径和标签在控制台显示乱码;使用 python -X utf8 后恢复正常。",
|
||||
"浏览器控制运行时当前无法启动,因此交互页面尚缺少真实浏览器截图和视觉回归确认。"
|
||||
],
|
||||
"next_steps": [
|
||||
"让脚本在 Windows 默认以 UTF-8 输出,减少调用方对 python -X utf8 的依赖。",
|
||||
"在可用浏览器中完成桌面端、移动端和键盘操作的视觉验收。",
|
||||
"在后续真实开发日持续使用该技能,并根据实际日报反馈调整证据抽取与交互呈现。"
|
||||
]
|
||||
}
|
||||
-238
@@ -1,238 +0,0 @@
|
||||
{
|
||||
"date": "2026-08-03",
|
||||
"title": "Daily Summary Job 技能今日进展总结",
|
||||
"summary": "当前功能定位:daily-summary-job 是一个按需触发的个人开发日报技能,负责记录精简检查点、提取当天及多 Agent 工作证据、整理问题与改善、自动分类归档,并生成或更新成对的 Markdown 和自包含交互式 HTML。技能已经完成设计、安装与核心验证;结构校验、31 项自动测试、JavaScript 语法检查及独立临时项目端到端流程均已通过。当前仍需处理 Windows 控制台默认编码体验,并在可用的真实浏览器中补做视觉与交互验收。",
|
||||
"modules": [
|
||||
"daily-summary-job"
|
||||
],
|
||||
"achievements": [
|
||||
{
|
||||
"title": "当前技能功能介绍(截至 2026-08-03)",
|
||||
"detail": "daily-summary-job 当前提供八类能力:①按需识别自然语言或显式技能调用;②记录精简开发检查点;③汇总当天证据并生成日报;④按稳定问题 ID 合并新证据、更新原报告;⑤提取多 Agent 的完成项、问题、原因、验证和下一步,并保留冲突结论;⑥自动识别模块、初始化报告目录、按日期和序号命名;⑦用交互式 HTML 展现问题、原因链、改善步骤、验证门和路线图;⑧校验 Markdown/HTML 配对、证据一致性和离线自包含性。技能不在后台持续运行,也不要求固定口令。",
|
||||
"evidence": [
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md",
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py",
|
||||
"docs/superpowers/specs/2026-08-03-daily-summary-job-skill-design.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "建立自动分类、初始化和日期归档机制",
|
||||
"detail": "技能会优先使用显式模块,其次匹配已有 *_rep 目录;跨模块归入 cross-module_rep,无法判定或项目没有代码目录时归入 general_rep,并自动创建 dailywork_report 下所需目录。最终报告使用 YYYY-MM-DD 日期目录和顺序编号命名。",
|
||||
"evidence": [
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py",
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "实现面向多 Agent 工作的持久化检查点",
|
||||
"detail": "通过每日检查点把完成项、问题和下一步压缩为结构化 JSON,最终日报优先汇总这些持久证据,从而避免为了生成日报长期保留所有 Agent 的完整对话。检查点预算限制为 5 个完成项、5 个问题和 3 个下一步。",
|
||||
"evidence": [
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md",
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "实现交互式问题与解决思路可视化",
|
||||
"detail": "HTML 报告为无外部依赖的自包含页面,提供问题选择、证据等级筛选、现状/目标对比、原因链、解决步骤、改进前后切换、验证门、路线图、键盘导航、响应式布局和减少动画偏好支持。",
|
||||
"evidence": [
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html",
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "完成命令行流程与自动化验证",
|
||||
"detail": "实现 inspect、checkpoint、render/update 和 validate 四类命令;此前的新鲜验证结果为技能结构有效、31 项测试全部通过、模板 JavaScript 语法通过,且独立临时项目中的记录、生成、更新复用同一文件对和最终校验均成功。",
|
||||
"evidence": [
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py",
|
||||
"C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py",
|
||||
"docs/superpowers/plans/2026-08-03-daily-summary-job-skill.md"
|
||||
]
|
||||
}
|
||||
],
|
||||
"issues": [
|
||||
{
|
||||
"id": "issue-windows-console-encoding",
|
||||
"title": "Windows 默认控制台编码导致中文输出乱码",
|
||||
"module": "daily-summary-job",
|
||||
"evidence_level": "已验证",
|
||||
"discovery": "本次执行 inspect 和读取中文字段时,普通 python/PowerShell 命令的控制台输出出现乱码;随后对源文件进行 UTF-8 解码和字符码点检查,确认文件没有损坏。",
|
||||
"actual": "脚本生成的文件内容是正确 UTF-8,但默认命令行输出中的中文项目路径、模块名和证据标签可能不可读。",
|
||||
"expected": "在 Windows 默认调用方式下,命令行 JSON 和诊断信息也应稳定显示为可读 UTF-8 中文。",
|
||||
"cause": "Windows 当前 Python/PowerShell 控制台输出编码与脚本的 UTF-8 内容不一致;使用 python -X utf8 重跑相同命令后中文显示正常,说明问题位于进程输出编码层。",
|
||||
"impact": "不会破坏已经写入的报告文件,但会降低命令行可读性,并可能影响依赖控制台文本进行人工核对或下游解析的流程。",
|
||||
"improvements": [
|
||||
{
|
||||
"action": "本次所有后续脚本命令改用 python -X utf8 执行。",
|
||||
"result": "inspect 输出中的中文项目路径恢复正常,报告输入可以安全校验。",
|
||||
"status": "已应用临时规避"
|
||||
},
|
||||
{
|
||||
"action": "对 SKILL.md、report-schema.md 和脚本证据等级常量执行 UTF-8 解码及字符检查。",
|
||||
"result": "确认磁盘文件内容有效,乱码不是文件损坏造成。",
|
||||
"status": "已验证"
|
||||
}
|
||||
],
|
||||
"validation": [
|
||||
{
|
||||
"name": "UTF-8 文件解码",
|
||||
"status": "通过",
|
||||
"detail": "技能说明、报告模式和脚本均可按 UTF-8 正常读取,中文证据等级字符存在且码点正确。"
|
||||
},
|
||||
{
|
||||
"name": "UTF-8 模式重跑 inspect",
|
||||
"status": "通过",
|
||||
"detail": "python -X utf8 下相同 inspect 命令正确显示包含中文的项目路径。"
|
||||
}
|
||||
],
|
||||
"next_steps": [
|
||||
"在脚本入口显式配置 stdout/stderr 为 UTF-8,或在技能命令模板中统一启用 UTF-8 模式。",
|
||||
"增加 Windows 默认控制台调用的回归测试,覆盖中文路径和中文 JSON 字段。"
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"label": "脚本入口",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py",
|
||||
"result": "普通模式出现乱码,python -X utf8 模式显示正常。"
|
||||
},
|
||||
{
|
||||
"label": "UTF-8 内容检查",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md",
|
||||
"result": "文件能够严格按 UTF-8 解码,证据等级文本正确。"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "issue-browser-visual-qa-unavailable",
|
||||
"title": "交互页面尚未完成真实浏览器视觉验收",
|
||||
"module": "daily-summary-job",
|
||||
"evidence_level": "待验证风险",
|
||||
"discovery": "尝试使用应用内浏览器预览交互页面时,浏览器控制运行时因 Node 启动错误而不可用。",
|
||||
"actual": "HTML 模板已经通过源码断言、JavaScript 语法检查和端到端生成校验,但没有在真实浏览器中完成截图、点击和响应式布局检查。",
|
||||
"expected": "应在可工作的浏览器中打开生成报告,操作筛选器和切换器,并分别检查桌面端、移动端、键盘导航与减少动画模式。",
|
||||
"cause": "当前应用内浏览器控制环境无法启动其 Node 运行时,属于本次技能代码之外的预览工具可用性问题。",
|
||||
"impact": "交互结构和脚本语法已有自动化保障,但仍可能存在只有真实渲染后才能发现的间距、溢出、颜色对比或浏览器兼容问题。",
|
||||
"improvements": [
|
||||
{
|
||||
"action": "运行模板源码交互断言和 JavaScript 语法检查。",
|
||||
"result": "核心控件、事件逻辑和脚本语法均通过检查。",
|
||||
"status": "已完成"
|
||||
},
|
||||
{
|
||||
"action": "在独立临时项目中执行生成、更新和 validate 端到端流程。",
|
||||
"result": "生成的 HTML 为自包含文件,更新复用原有文件对,最终校验有效。",
|
||||
"status": "已完成"
|
||||
}
|
||||
],
|
||||
"validation": [
|
||||
{
|
||||
"name": "自动化测试",
|
||||
"status": "通过",
|
||||
"detail": "31 项自动测试全部通过,覆盖模板关键结构和报告工作流。"
|
||||
},
|
||||
{
|
||||
"name": "JavaScript 语法",
|
||||
"status": "通过",
|
||||
"detail": "模板内联脚本通过 Node 语法检查。"
|
||||
},
|
||||
{
|
||||
"name": "真实浏览器视觉检查",
|
||||
"status": "待验证",
|
||||
"detail": "浏览器控制运行时无法启动,尚无真实渲染截图证据。"
|
||||
}
|
||||
],
|
||||
"next_steps": [
|
||||
"在可用浏览器中打开本次生成的可视化报告并逐项操作所有控件。",
|
||||
"至少检查常见桌面宽度和窄屏移动端宽度,并记录截图或视觉问题。"
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"label": "交互模板",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html",
|
||||
"result": "模板包含筛选、切换、原因链、解决步骤、验证门和路线图。"
|
||||
},
|
||||
{
|
||||
"label": "浏览器运行时错误",
|
||||
"reference": "本次技能开发会话的浏览器预览尝试",
|
||||
"result": "failed to start Node runtime,os error 3;无法形成视觉截图证据。"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"validations": [
|
||||
{
|
||||
"name": "技能结构校验",
|
||||
"status": "通过",
|
||||
"detail": "quick_validate.py 返回 Skill is valid!。"
|
||||
},
|
||||
{
|
||||
"name": "自动化测试",
|
||||
"status": "通过",
|
||||
"detail": "test_prepare_report.py 共 31 项测试通过,0 失败。"
|
||||
},
|
||||
{
|
||||
"name": "模板脚本语法",
|
||||
"status": "通过",
|
||||
"detail": "抽取模板内联 JavaScript 后执行 node --check 通过。"
|
||||
},
|
||||
{
|
||||
"name": "独立临时项目端到端流程",
|
||||
"status": "通过",
|
||||
"detail": "记录、生成、更新和校验链路成功;更新复用了同一 Markdown/HTML 文件对,validation_valid 为 true。"
|
||||
},
|
||||
{
|
||||
"name": "真实浏览器视觉验收",
|
||||
"status": "待验证",
|
||||
"detail": "受应用内浏览器运行时故障影响,尚未完成真实渲染和交互截图检查。"
|
||||
}
|
||||
],
|
||||
"next_steps": [
|
||||
{
|
||||
"priority": "P0",
|
||||
"module": "daily-summary-job",
|
||||
"action": "统一 Windows 命令行 UTF-8 输出行为,并补充中文路径回归测试。",
|
||||
"done_when": "不附加 python -X utf8 时,inspect、checkpoint、render 和 validate 的中文 JSON 输出仍清晰可读。"
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"module": "daily-summary-job",
|
||||
"action": "在真实浏览器中完成交互与响应式视觉验收。",
|
||||
"done_when": "桌面端和移动端均完成控件操作、键盘导航和布局检查,并留下截图或可复核记录。"
|
||||
},
|
||||
{
|
||||
"priority": "P2",
|
||||
"module": "daily-summary-job",
|
||||
"action": "在后续真实开发日持续记录检查点并更新日报,根据实际使用反馈调整抽取规则。",
|
||||
"done_when": "至少完成一个包含多 Agent 证据的完整工作日闭环,并确认报告没有遗漏关键问题或产生事实混淆。"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"label": "技能说明",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md"
|
||||
},
|
||||
{
|
||||
"label": "报告数据模式",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md"
|
||||
},
|
||||
{
|
||||
"label": "报告生成脚本",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py"
|
||||
},
|
||||
{
|
||||
"label": "自动测试",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py"
|
||||
},
|
||||
{
|
||||
"label": "交互页面模板",
|
||||
"reference": "C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html"
|
||||
},
|
||||
{
|
||||
"label": "设计文档",
|
||||
"reference": "docs/superpowers/specs/2026-08-03-daily-summary-job-skill-design.md"
|
||||
},
|
||||
{
|
||||
"label": "实施计划",
|
||||
"reference": "docs/superpowers/plans/2026-08-03-daily-summary-job-skill.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
{
|
||||
"date": "2026-08-04",
|
||||
"title": "EMPlanner 架构梳理与 LS 优化启动日报",
|
||||
"summary": "已依据 EMPlanner 当前说明和代码目录明确轨迹规划的分层架构与模块边界;LS 横向优化为当前开展方向,尚未在本日报中宣称完成或通过专项回归。",
|
||||
"modules": [
|
||||
"emplanner"
|
||||
],
|
||||
"achievements": [
|
||||
{
|
||||
"title": "确定 EMPlanner 轨迹规划分层架构",
|
||||
"detail": "明确从请求快照、方向段/Frenet 投影和静态走廊,到 LS、ST、轨迹装配、世界空间复核及上层滚动执行的职责划分。",
|
||||
"evidence": [
|
||||
"ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "明确规划器与执行侧边界",
|
||||
"detail": "EMPlanner 仅产出经校验的时间轨迹;调度、轨迹交接、换向执行和控制命令由 TrajectoryExecution 承担。",
|
||||
"evidence": [
|
||||
"ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md",
|
||||
"ClumsyPilot/ParkrobTrajplanner/TrajectoryExecution/README.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "梳理 LS 优化的接口边界",
|
||||
"detail": "LS 使用 l、dl、ddl、dddl 变量,在静态走廊与车辆几何约束下求解;求解器通过 IQpSolver/QuadraticProgram 抽象接入。",
|
||||
"evidence": [
|
||||
"ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md",
|
||||
"ClumsyPilot/ParkrobTrajplanner/EMPlanner/Lateral/"
|
||||
]
|
||||
}
|
||||
],
|
||||
"issues": [
|
||||
{
|
||||
"id": "ls-optimization-in-progress",
|
||||
"title": "LS 横向优化处于开展阶段",
|
||||
"module": "emplanner",
|
||||
"evidence_level": "对话发现",
|
||||
"discovery": "用户说明当前正在开展 LS 优化工作。",
|
||||
"actual": "当前已明确 LS 位于静态走廊之后、ST 之前,并承担横向路径优化与独立几何复核;本日报未取得本轮专项优化结果或回归输出。",
|
||||
"expected": "在不破坏静态走廊、导数、Frenet 分母和车辆曲率硬约束的前提下,形成可独立复核的横向候选轨迹。",
|
||||
"cause": "优化参数、目标权重、收敛策略及专项场景的本轮验证证据尚待补充。",
|
||||
"impact": "LS 结果直接决定后续 ST 使用的实际 PathS 与轨迹可发布性,需先完成可行性和稳定性验证。",
|
||||
"improvements": [],
|
||||
"validation": [
|
||||
{
|
||||
"name": "架构与接口静态核对",
|
||||
"status": "通过",
|
||||
"detail": "README 与 Lateral 目录表明 LS 的数据流、变量及求解器边界已定义;未执行 LS 专项运行测试。"
|
||||
}
|
||||
],
|
||||
"next_steps": [
|
||||
"确定 LS 优化目标、权重和约束调参方案。",
|
||||
"针对典型前进、倒车及走廊边界场景执行专项回归。"
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"label": "LS 架构说明",
|
||||
"reference": "ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md",
|
||||
"result": "文档定义 LS SQP、独立横向几何复核及其与 ST 的数据边界。"
|
||||
},
|
||||
{
|
||||
"label": "当前工作说明",
|
||||
"reference": "用户需求(2026-08-04)",
|
||||
"result": "当前开展 LS 优化工作。"
|
||||
}
|
||||
],
|
||||
"conceptual_visual": true
|
||||
}
|
||||
],
|
||||
"validations": [
|
||||
{
|
||||
"name": "EMPlanner 架构静态核对",
|
||||
"status": "通过",
|
||||
"detail": "核对 README、Lateral 目录和当日 EMPlanner 提交记录;本次未运行构建或自动化测试。"
|
||||
}
|
||||
],
|
||||
"next_steps": [
|
||||
{
|
||||
"priority": "P0",
|
||||
"module": "emplanner",
|
||||
"action": "细化并实现 LS 优化策略",
|
||||
"done_when": "横向优化目标、约束和候选筛选策略形成可审查实现。"
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"module": "emplanner",
|
||||
"action": "执行 LS 专项回归",
|
||||
"done_when": "典型前进、倒车和窄走廊场景均有可复核的运行结果。"
|
||||
},
|
||||
{
|
||||
"priority": "P1",
|
||||
"module": "emplanner",
|
||||
"action": "联调 LS 到 ST 的 PathS 输入",
|
||||
"done_when": "ST 仅消费 LS 已复核且严格递增的实际 PathS,并保留验证记录。"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"label": "EMPlanner 架构说明",
|
||||
"reference": "ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md"
|
||||
},
|
||||
{
|
||||
"label": "当日 EMPlanner 提交记录",
|
||||
"reference": "git log --since='2026-08-04 00:00' -- ClumsyPilot/ParkrobTrajplanner/EMPlanner"
|
||||
},
|
||||
{
|
||||
"label": "LS/ST 观测计划",
|
||||
"reference": "docs/superpowers/plans/2026-08-04-em-observation-movementtest.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
-92
@@ -1,92 +0,0 @@
|
||||
# Daily Summary Job 技能今日进展总结
|
||||
|
||||
> 日期:2026-08-03
|
||||
> 模块:daily-summary-job
|
||||
> 证据原则:已验证事实、静态分析、对话发现和待验证风险必须分开表达。
|
||||
|
||||
## 1. 今日结论摘要
|
||||
|
||||
当前功能定位:daily-summary-job 是一个按需触发的个人开发日报技能,负责记录精简检查点、提取当天及多 Agent 工作证据、整理问题与改善、自动分类归档,并生成或更新成对的 Markdown 和自包含交互式 HTML。技能已经完成设计、安装与核心验证;结构校验、31 项自动测试、JavaScript 语法检查及独立临时项目端到端流程均已通过。当前仍需处理 Windows 控制台默认编码体验,并在可用的真实浏览器中补做视觉与交互验收。
|
||||
|
||||
## 2. 今日完成的工作
|
||||
|
||||
- **当前技能功能介绍(截至 2026-08-03)**:daily-summary-job 当前提供八类能力:①按需识别自然语言或显式技能调用;②记录精简开发检查点;③汇总当天证据并生成日报;④按稳定问题 ID 合并新证据、更新原报告;⑤提取多 Agent 的完成项、问题、原因、验证和下一步,并保留冲突结论;⑥自动识别模块、初始化报告目录、按日期和序号命名;⑦用交互式 HTML 展现问题、原因链、改善步骤、验证门和路线图;⑧校验 Markdown/HTML 配对、证据一致性和离线自包含性。技能不在后台持续运行,也不要求固定口令。(证据:C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md、C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py、docs/superpowers/specs/2026-08-03-daily-summary-job-skill-design.md)
|
||||
- **建立自动分类、初始化和日期归档机制**:技能会优先使用显式模块,其次匹配已有 *_rep 目录;跨模块归入 cross-module_rep,无法判定或项目没有代码目录时归入 general_rep,并自动创建 dailywork_report 下所需目录。最终报告使用 YYYY-MM-DD 日期目录和顺序编号命名。(证据:C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py、C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md)
|
||||
- **实现面向多 Agent 工作的持久化检查点**:通过每日检查点把完成项、问题和下一步压缩为结构化 JSON,最终日报优先汇总这些持久证据,从而避免为了生成日报长期保留所有 Agent 的完整对话。检查点预算限制为 5 个完成项、5 个问题和 3 个下一步。(证据:C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md、C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py)
|
||||
- **实现交互式问题与解决思路可视化**:HTML 报告为无外部依赖的自包含页面,提供问题选择、证据等级筛选、现状/目标对比、原因链、解决步骤、改进前后切换、验证门、路线图、键盘导航、响应式布局和减少动画偏好支持。(证据:C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html、C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py)
|
||||
- **完成命令行流程与自动化验证**:实现 inspect、checkpoint、render/update 和 validate 四类命令;此前的新鲜验证结果为技能结构有效、31 项测试全部通过、模板 JavaScript 语法通过,且独立临时项目中的记录、生成、更新复用同一文件对和最终校验均成功。(证据:C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py、C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py、docs/superpowers/plans/2026-08-03-daily-summary-job-skill.md)
|
||||
|
||||
## 3. 今日发现的问题
|
||||
|
||||
### 3.1 Windows 默认控制台编码导致中文输出乱码 `issue-windows-console-encoding`
|
||||
|
||||
- **证据等级**:已验证
|
||||
- **实际现象**:脚本生成的文件内容是正确 UTF-8,但默认命令行输出中的中文项目路径、模块名和证据标签可能不可读。
|
||||
- **正确预期**:在 Windows 默认调用方式下,命令行 JSON 和诊断信息也应稳定显示为可读 UTF-8 中文。
|
||||
- **原因或当前假设**:Windows 当前 Python/PowerShell 控制台输出编码与脚本的 UTF-8 内容不一致;使用 python -X utf8 重跑相同命令后中文显示正常,说明问题位于进程输出编码层。
|
||||
- **影响**:不会破坏已经写入的报告文件,但会降低命令行可读性,并可能影响依赖控制台文本进行人工核对或下游解析的流程。
|
||||
|
||||
### 3.2 交互页面尚未完成真实浏览器视觉验收 `issue-browser-visual-qa-unavailable`
|
||||
|
||||
- **证据等级**:待验证风险
|
||||
- **实际现象**:HTML 模板已经通过源码断言、JavaScript 语法检查和端到端生成校验,但没有在真实浏览器中完成截图、点击和响应式布局检查。
|
||||
- **正确预期**:应在可工作的浏览器中打开生成报告,操作筛选器和切换器,并分别检查桌面端、移动端、键盘导航与减少动画模式。
|
||||
- **原因或当前假设**:当前应用内浏览器控制环境无法启动其 Node 运行时,属于本次技能代码之外的预览工具可用性问题。
|
||||
- **影响**:交互结构和脚本语法已有自动化保障,但仍可能存在只有真实渲染后才能发现的间距、溢出、颜色对比或浏览器兼容问题。
|
||||
|
||||
## 4. 问题如何被发现及证据
|
||||
|
||||
### issue-windows-console-encoding · Windows 默认控制台编码导致中文输出乱码
|
||||
|
||||
本次执行 inspect 和读取中文字段时,普通 python/PowerShell 命令的控制台输出出现乱码;随后对源文件进行 UTF-8 解码和字符码点检查,确认文件没有损坏。
|
||||
|
||||
| 证据 | 引用 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| 脚本入口 | C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py | 普通模式出现乱码,python -X utf8 模式显示正常。 |
|
||||
| UTF-8 内容检查 | C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md | 文件能够严格按 UTF-8 解码,证据等级文本正确。 |
|
||||
|
||||
### issue-browser-visual-qa-unavailable · 交互页面尚未完成真实浏览器视觉验收
|
||||
|
||||
尝试使用应用内浏览器预览交互页面时,浏览器控制运行时因 Node 启动错误而不可用。
|
||||
|
||||
| 证据 | 引用 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| 交互模板 | C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html | 模板包含筛选、切换、原因链、解决步骤、验证门和路线图。 |
|
||||
| 浏览器运行时错误 | 本次技能开发会话的浏览器预览尝试 | failed to start Node runtime,os error 3;无法形成视觉截图证据。 |
|
||||
|
||||
## 5. 已采取的改善和验证结果
|
||||
|
||||
- **issue-windows-console-encoding / 已应用临时规避**:本次所有后续脚本命令改用 python -X utf8 执行。;结果:inspect 输出中的中文项目路径恢复正常,报告输入可以安全校验。
|
||||
- **issue-windows-console-encoding / 已验证**:对 SKILL.md、report-schema.md 和脚本证据等级常量执行 UTF-8 解码及字符检查。;结果:确认磁盘文件内容有效,乱码不是文件损坏造成。
|
||||
- **issue-windows-console-encoding / UTF-8 文件解码 / 通过**:技能说明、报告模式和脚本均可按 UTF-8 正常读取,中文证据等级字符存在且码点正确。
|
||||
- **issue-windows-console-encoding / UTF-8 模式重跑 inspect / 通过**:python -X utf8 下相同 inspect 命令正确显示包含中文的项目路径。
|
||||
- **issue-browser-visual-qa-unavailable / 已完成**:运行模板源码交互断言和 JavaScript 语法检查。;结果:核心控件、事件逻辑和脚本语法均通过检查。
|
||||
- **issue-browser-visual-qa-unavailable / 已完成**:在独立临时项目中执行生成、更新和 validate 端到端流程。;结果:生成的 HTML 为自包含文件,更新复用原有文件对,最终校验有效。
|
||||
- **issue-browser-visual-qa-unavailable / 自动化测试 / 通过**:31 项自动测试全部通过,覆盖模板关键结构和报告工作流。
|
||||
- **issue-browser-visual-qa-unavailable / JavaScript 语法 / 通过**:模板内联脚本通过 Node 语法检查。
|
||||
- **issue-browser-visual-qa-unavailable / 真实浏览器视觉检查 / 待验证**:浏览器控制运行时无法启动,尚无真实渲染截图证据。
|
||||
- **技能结构校验 / 通过**:quick_validate.py 返回 Skill is valid!。
|
||||
- **自动化测试 / 通过**:test_prepare_report.py 共 31 项测试通过,0 失败。
|
||||
- **模板脚本语法 / 通过**:抽取模板内联 JavaScript 后执行 node --check 通过。
|
||||
- **独立临时项目端到端流程 / 通过**:记录、生成、更新和校验链路成功;更新复用了同一 Markdown/HTML 文件对,validation_valid 为 true。
|
||||
- **真实浏览器视觉验收 / 待验证**:受应用内浏览器运行时故障影响,尚未完成真实渲染和交互截图检查。
|
||||
|
||||
## 6. 尚未解决的风险与下一步
|
||||
|
||||
- **issue-windows-console-encoding**:在脚本入口显式配置 stdout/stderr 为 UTF-8,或在技能命令模板中统一启用 UTF-8 模式。
|
||||
- **issue-windows-console-encoding**:增加 Windows 默认控制台调用的回归测试,覆盖中文路径和中文 JSON 字段。
|
||||
- **issue-browser-visual-qa-unavailable**:在可用浏览器中打开本次生成的可视化报告并逐项操作所有控件。
|
||||
- **issue-browser-visual-qa-unavailable**:至少检查常见桌面宽度和窄屏移动端宽度,并记录截图或视觉问题。
|
||||
- **P0 / daily-summary-job**:统一 Windows 命令行 UTF-8 输出行为,并补充中文路径回归测试。;完成标志:不附加 python -X utf8 时,inspect、checkpoint、render 和 validate 的中文 JSON 输出仍清晰可读。
|
||||
- **P1 / daily-summary-job**:在真实浏览器中完成交互与响应式视觉验收。;完成标志:桌面端和移动端均完成控件操作、键盘导航和布局检查,并留下截图或可复核记录。
|
||||
- **P2 / daily-summary-job**:在后续真实开发日持续记录检查点并更新日报,根据实际使用反馈调整抽取规则。;完成标志:至少完成一个包含多 Agent 证据的完整工作日闭环,并确认报告没有遗漏关键问题或产生事实混淆。
|
||||
|
||||
## 7. 证据索引
|
||||
|
||||
- **技能说明**:C:/Users/admin/.codex/skills/daily-summary-job/SKILL.md
|
||||
- **报告数据模式**:C:/Users/admin/.codex/skills/daily-summary-job/references/report-schema.md
|
||||
- **报告生成脚本**:C:/Users/admin/.codex/skills/daily-summary-job/scripts/prepare_report.py
|
||||
- **自动测试**:C:/Users/admin/.codex/skills/daily-summary-job/scripts/test_prepare_report.py
|
||||
- **交互页面模板**:C:/Users/admin/.codex/skills/daily-summary-job/assets/interactive-report-template.html
|
||||
- **设计文档**:docs/superpowers/specs/2026-08-03-daily-summary-job-skill-design.md
|
||||
- **实施计划**:docs/superpowers/plans/2026-08-03-daily-summary-job-skill.md
|
||||
-397
File diff suppressed because one or more lines are too long
-55
@@ -1,55 +0,0 @@
|
||||
# EMPlanner 架构梳理与 LS 优化启动日报
|
||||
|
||||
> 日期:2026-08-04
|
||||
> 模块:emplanner
|
||||
> 证据原则:已验证事实、静态分析、对话发现和待验证风险必须分开表达。
|
||||
|
||||
## 1. 今日结论摘要
|
||||
|
||||
已依据 EMPlanner 当前说明和代码目录明确轨迹规划的分层架构与模块边界;LS 横向优化为当前开展方向,尚未在本日报中宣称完成或通过专项回归。
|
||||
|
||||
## 2. 今日完成的工作
|
||||
|
||||
- **确定 EMPlanner 轨迹规划分层架构**:明确从请求快照、方向段/Frenet 投影和静态走廊,到 LS、ST、轨迹装配、世界空间复核及上层滚动执行的职责划分。(证据:ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md)
|
||||
- **明确规划器与执行侧边界**:EMPlanner 仅产出经校验的时间轨迹;调度、轨迹交接、换向执行和控制命令由 TrajectoryExecution 承担。(证据:ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md、ClumsyPilot/ParkrobTrajplanner/TrajectoryExecution/README.md)
|
||||
- **梳理 LS 优化的接口边界**:LS 使用 l、dl、ddl、dddl 变量,在静态走廊与车辆几何约束下求解;求解器通过 IQpSolver/QuadraticProgram 抽象接入。(证据:ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md、ClumsyPilot/ParkrobTrajplanner/EMPlanner/Lateral/)
|
||||
|
||||
## 3. 今日发现的问题
|
||||
|
||||
### 3.1 LS 横向优化处于开展阶段 `ls-optimization-in-progress`
|
||||
|
||||
- **证据等级**:对话发现
|
||||
- **实际现象**:当前已明确 LS 位于静态走廊之后、ST 之前,并承担横向路径优化与独立几何复核;本日报未取得本轮专项优化结果或回归输出。
|
||||
- **正确预期**:在不破坏静态走廊、导数、Frenet 分母和车辆曲率硬约束的前提下,形成可独立复核的横向候选轨迹。
|
||||
- **原因或当前假设**:优化参数、目标权重、收敛策略及专项场景的本轮验证证据尚待补充。
|
||||
- **影响**:LS 结果直接决定后续 ST 使用的实际 PathS 与轨迹可发布性,需先完成可行性和稳定性验证。
|
||||
|
||||
## 4. 问题如何被发现及证据
|
||||
|
||||
### ls-optimization-in-progress · LS 横向优化处于开展阶段
|
||||
|
||||
用户说明当前正在开展 LS 优化工作。
|
||||
|
||||
| 证据 | 引用 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| LS 架构说明 | ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md | 文档定义 LS SQP、独立横向几何复核及其与 ST 的数据边界。 |
|
||||
| 当前工作说明 | 用户需求(2026-08-04) | 当前开展 LS 优化工作。 |
|
||||
|
||||
## 5. 已采取的改善和验证结果
|
||||
|
||||
- **ls-optimization-in-progress / 架构与接口静态核对 / 通过**:README 与 Lateral 目录表明 LS 的数据流、变量及求解器边界已定义;未执行 LS 专项运行测试。
|
||||
- **EMPlanner 架构静态核对 / 通过**:核对 README、Lateral 目录和当日 EMPlanner 提交记录;本次未运行构建或自动化测试。
|
||||
|
||||
## 6. 尚未解决的风险与下一步
|
||||
|
||||
- **ls-optimization-in-progress**:确定 LS 优化目标、权重和约束调参方案。
|
||||
- **ls-optimization-in-progress**:针对典型前进、倒车及走廊边界场景执行专项回归。
|
||||
- **P0 / emplanner**:细化并实现 LS 优化策略;完成标志:横向优化目标、约束和候选筛选策略形成可审查实现。
|
||||
- **P1 / emplanner**:执行 LS 专项回归;完成标志:典型前进、倒车和窄走廊场景均有可复核的运行结果。
|
||||
- **P1 / emplanner**:联调 LS 到 ST 的 PathS 输入;完成标志:ST 仅消费 LS 已复核且严格递增的实际 PathS,并保留验证记录。
|
||||
|
||||
## 7. 证据索引
|
||||
|
||||
- **EMPlanner 架构说明**:ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md
|
||||
- **当日 EMPlanner 提交记录**:git log --since='2026-08-04 00:00' -- ClumsyPilot/ParkrobTrajplanner/EMPlanner
|
||||
- **LS/ST 观测计划**:docs/superpowers/plans/2026-08-04-em-observation-movementtest.md
|
||||
-419
@@ -1,419 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>开发工作日报|交互式问题与改善说明</title>
|
||||
<style> :root {
|
||||
color-scheme: light;
|
||||
--ink: #142532;
|
||||
--muted: #60717c;
|
||||
--paper: #f3f6f5;
|
||||
--panel: #ffffff;
|
||||
--line: #ccd7d7;
|
||||
--teal: #0f6b70;
|
||||
--teal-soft: #dff1ef;
|
||||
--green: #24784c;
|
||||
--green-soft: #e6f4ea;
|
||||
--amber: #955d12;
|
||||
--amber-soft: #fff0d7;
|
||||
--red: #ad3541;
|
||||
--red-soft: #fbe8ea;
|
||||
--blue: #285f91;
|
||||
--blue-soft: #e3eff9;
|
||||
--shadow: 0 16px 44px rgba(27, 52, 60, .08);
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; background: var(--paper); color: var(--ink); font: 16px/1.65 system-ui, -apple-system, "Segoe UI", sans-serif; }
|
||||
button { font: inherit; }
|
||||
button:focus-visible { outline: 3px solid #e7a628; outline-offset: 3px; }
|
||||
#daily-summary-app { width: min(1180px, 100%); margin: 0 auto; padding: clamp(18px, 4vw, 44px); }
|
||||
.hero { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 20px; align-items: end; border-bottom: 2px solid var(--ink); padding-bottom: 22px; }
|
||||
.eyebrow { margin: 0 0 5px; color: var(--teal); font-weight: 800; letter-spacing: .06em; }
|
||||
h1, h2, h3, p { margin-top: 0; }
|
||||
h1 { margin-bottom: 8px; font-size: clamp(1.8rem, 4vw, 2.65rem); line-height: 1.18; }
|
||||
h2 { font-size: clamp(1.25rem, 2.8vw, 1.65rem); line-height: 1.3; }
|
||||
h3 { font-size: 1.04rem; }
|
||||
.subtitle { max-width: 790px; margin-bottom: 0; color: var(--muted); }
|
||||
.date-chip { border: 1px solid var(--line); border-radius: 7px; padding: 7px 10px; background: var(--panel); font-weight: 800; white-space: nowrap; }
|
||||
.overview { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin: 22px 0; }
|
||||
.stat { border-top: 4px solid var(--teal); padding: 12px 4px 8px; }
|
||||
.stat:nth-child(2) { border-color: var(--red); }
|
||||
.stat:nth-child(3) { border-color: var(--green); }
|
||||
.stat:nth-child(4) { border-color: var(--amber); }
|
||||
.stat strong { display: block; font-size: 1.8rem; line-height: 1.1; }
|
||||
.stat span { color: var(--muted); }
|
||||
.workbench { display: grid; grid-template-columns: minmax(220px, 290px) minmax(0, 1fr); gap: 18px; align-items: start; }
|
||||
.navigator, .problem-lab { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); }
|
||||
.navigator { padding: 16px; }
|
||||
.navigator h2 { margin-bottom: 10px; }
|
||||
.evidence-filter-list, .issue-list, .solution-steps { display: grid; gap: 8px; }
|
||||
.evidence-filter-list { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 16px; }
|
||||
.evidence-filter, .issue-button, .solution-step, .before-after-toggle, .step-control { min-height: 42px; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; color: var(--ink); background: var(--panel); cursor: pointer; text-align: left; }
|
||||
.evidence-filter[aria-pressed="true"], .issue-button[aria-pressed="true"], .solution-step[aria-pressed="true"], .before-after-toggle[aria-pressed="true"] { border-color: var(--teal); color: #fff; background: var(--teal); }
|
||||
.issue-button small { display: block; margin-top: 2px; opacity: .76; }
|
||||
.problem-lab { overflow: hidden; }
|
||||
.problem-heading { padding: 20px clamp(16px, 3vw, 28px) 12px; border-bottom: 1px solid var(--line); }
|
||||
.badge { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 7px; border: 1px solid currentColor; border-radius: 999px; padding: 3px 9px; font-size: .84rem; font-weight: 800; }
|
||||
.badge::before { content: "◆"; font-size: .72em; }
|
||||
.badge[data-level="已验证"] { color: var(--green); background: var(--green-soft); }
|
||||
.badge[data-level="静态分析"] { color: var(--amber); background: var(--amber-soft); }
|
||||
.badge[data-level="对话发现"] { color: var(--blue); background: var(--blue-soft); }
|
||||
.badge[data-level="待验证风险"], .badge[data-level="结论冲突"] { color: var(--red); background: var(--red-soft); }
|
||||
.problem-body { padding: 18px clamp(16px, 3vw, 28px) 26px; }
|
||||
.comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.compare-panel { border-left: 4px solid var(--red); padding: 4px 0 4px 13px; }
|
||||
.compare-panel.expected { border-color: var(--green); }
|
||||
.compare-panel p { margin-bottom: 0; color: var(--muted); }
|
||||
.before-after-toggle { margin: 14px 0; text-align: center; }
|
||||
.cause-flow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; margin: 24px 0; }
|
||||
.cause-node { position: relative; min-height: 126px; border-top: 4px solid var(--blue); padding: 12px 4px 4px; }
|
||||
.cause-node:not(:last-child)::after { position: absolute; top: 45px; right: -14px; content: "→"; color: var(--muted); font-weight: 800; }
|
||||
.cause-node p { margin-bottom: 0; color: var(--muted); }
|
||||
.concept-note { border-left: 4px solid var(--amber); padding: 9px 12px; color: #6e4813; background: var(--amber-soft); }
|
||||
.solution-layout { display: grid; grid-template-columns: minmax(180px, .7fr) minmax(0, 1.3fr); gap: 16px; margin-top: 24px; }
|
||||
.solution-detail { min-height: 150px; border-left: 1px solid var(--line); padding-left: 18px; }
|
||||
.solution-detail p { color: var(--muted); }
|
||||
.step-controls { display: flex; gap: 8px; margin-top: 12px; }
|
||||
.step-control { text-align: center; }
|
||||
.validation-section, .roadmap-section { padding: 30px 0; border-bottom: 1px solid var(--line); }
|
||||
.validation-gates { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
|
||||
.validation-gate { border-top: 4px solid var(--line); padding: 12px 4px 4px; }
|
||||
.validation-gate[data-status="通过"], .validation-gate[data-status="完成"] { border-color: var(--green); }
|
||||
.validation-gate[data-status="失败"], .validation-gate[data-status="阻断"] { border-color: var(--red); }
|
||||
.validation-gate[data-status="待验证"] { border-color: var(--amber); }
|
||||
.validation-gate p { margin-bottom: 0; color: var(--muted); }
|
||||
.roadmap { display: grid; gap: 10px; }
|
||||
.roadmap-item { display: grid; grid-template-columns: 70px minmax(0, 1fr); gap: 12px; border-bottom: 1px solid var(--line); padding: 10px 0; }
|
||||
.roadmap-item strong:first-child { color: var(--teal); }
|
||||
.roadmap-item p { margin-bottom: 0; color: var(--muted); }
|
||||
.empty { color: var(--muted); font-style: italic; }
|
||||
footer { padding-top: 22px; color: var(--muted); font-size: .9rem; }
|
||||
@media (max-width: 820px) {
|
||||
.hero, .workbench, .solution-layout { grid-template-columns: 1fr; }
|
||||
.date-chip { justify-self: start; }
|
||||
.overview { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.navigator { box-shadow: none; }
|
||||
.issue-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.solution-detail { border-top: 1px solid var(--line); border-left: 0; padding-top: 16px; padding-left: 0; }
|
||||
}
|
||||
@media (max-width: 560px) {
|
||||
.overview, .comparison, .cause-flow, .validation-gates, .issue-list { grid-template-columns: 1fr; }
|
||||
.cause-node:not(:last-child)::after { top: auto; right: auto; bottom: -17px; left: 50%; content: "↓"; }
|
||||
.roadmap-item { grid-template-columns: 52px minmax(0, 1fr); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after { scroll-behavior: auto !important; transition: none !important; animation: none !important; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main id="daily-summary-app" data-selected-issue="">
|
||||
<header class="hero">
|
||||
<div>
|
||||
<p class="eyebrow">开发日报 · 问题与改善交互说明</p>
|
||||
<h1 id="report-title">今日工作总结</h1>
|
||||
<p id="report-summary" class="subtitle"></p>
|
||||
</div>
|
||||
<span id="report-date" class="date-chip"></span>
|
||||
</header>
|
||||
|
||||
<section class="overview" aria-label="今日工作总览">
|
||||
<div class="stat"><strong id="achievement-count">0</strong><span>完成事项</span></div>
|
||||
<div class="stat"><strong id="issue-count">0</strong><span>发现问题</span></div>
|
||||
<div class="stat"><strong id="validation-count">0</strong><span>验证记录</span></div>
|
||||
<div class="stat"><strong id="next-count">0</strong><span>下一步</span></div>
|
||||
</section>
|
||||
|
||||
<div class="workbench">
|
||||
<aside class="navigator">
|
||||
<h2>选择问题</h2>
|
||||
<div id="evidence-filters" class="evidence-filter-list" aria-label="按证据等级筛选">
|
||||
<button type="button" class="evidence-filter" data-level="全部" aria-pressed="true">全部</button>
|
||||
</div>
|
||||
<div id="issue-list" class="issue-list"></div>
|
||||
</aside>
|
||||
|
||||
<section class="problem-lab" aria-live="polite">
|
||||
<div class="problem-heading">
|
||||
<span id="issue-evidence" class="badge" data-level="对话发现">对话发现</span>
|
||||
<h2 id="issue-title">暂无问题</h2>
|
||||
<p id="issue-meta" class="subtitle"></p>
|
||||
</div>
|
||||
<div class="problem-body">
|
||||
<button id="before-after-toggle" type="button" class="before-after-toggle" aria-pressed="false">切换为改善后视图</button>
|
||||
<div class="comparison">
|
||||
<article class="compare-panel">
|
||||
<h3 id="actual-label">实际发生</h3>
|
||||
<p id="issue-actual"></p>
|
||||
</article>
|
||||
<article class="compare-panel expected">
|
||||
<h3>正确预期</h3>
|
||||
<p id="issue-expected"></p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div id="cause-flow" class="cause-flow" aria-label="问题发现与原因链">
|
||||
<article class="cause-node"><h3>问题发现</h3><p id="issue-discovery"></p></article>
|
||||
<article class="cause-node"><h3>实际现象</h3><p id="issue-symptom"></p></article>
|
||||
<article class="cause-node"><h3>原因或假设</h3><p id="issue-cause"></p></article>
|
||||
<article class="cause-node"><h3>影响范围</h3><p id="issue-impact"></p></article>
|
||||
</div>
|
||||
<p id="concept-note" class="concept-note">概念示意:没有数值证据时不绘制虚构比例。</p>
|
||||
|
||||
<div class="solution-layout">
|
||||
<div>
|
||||
<h3>改善步骤</h3>
|
||||
<div id="solution-steps" class="solution-steps"></div>
|
||||
</div>
|
||||
<article class="solution-detail">
|
||||
<h3 id="solution-title">尚未记录改善</h3>
|
||||
<p id="solution-result">当前只保留问题和下一步,不把候选方案写成已完成。</p>
|
||||
<div class="step-controls">
|
||||
<button id="previous-solution" type="button" class="step-control">上一步</button>
|
||||
<button id="next-solution" type="button" class="step-control">下一步</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="validation-section">
|
||||
<h2>验证门</h2>
|
||||
<div id="validation-gates" class="validation-gates"></div>
|
||||
</section>
|
||||
|
||||
<section class="roadmap-section">
|
||||
<h2>下一步路线图</h2>
|
||||
<div id="roadmap" class="roadmap"></div>
|
||||
</section>
|
||||
|
||||
<footer>本页与 Markdown 主报告来自同一结构化事实源。键盘左右方向键可切换问题。</footer>
|
||||
|
||||
<template id="issue-button-template"><button type="button" class="issue-button" aria-pressed="false"><span></span><small></small></button></template>
|
||||
<template id="evidence-filter-template"><button type="button" class="evidence-filter" aria-pressed="false"></button></template>
|
||||
<template id="solution-step-template"><button type="button" class="solution-step" aria-pressed="false"></button></template>
|
||||
<template id="validation-gate-template"><article class="validation-gate"><h3></h3><strong></strong><p></p></article></template>
|
||||
<template id="roadmap-item-template"><article class="roadmap-item"><strong></strong><div><h3></h3><p></p></div></article></template>
|
||||
</main>
|
||||
|
||||
<script id="report-data" type="application/json">{"date":"2026-08-04","title":"EMPlanner 架构梳理与 LS 优化启动日报","summary":"已依据 EMPlanner 当前说明和代码目录明确轨迹规划的分层架构与模块边界;LS 横向优化为当前开展方向,尚未在本日报中宣称完成或通过专项回归。","modules":["emplanner"],"achievements":[{"title":"确定 EMPlanner 轨迹规划分层架构","detail":"明确从请求快照、方向段/Frenet 投影和静态走廊,到 LS、ST、轨迹装配、世界空间复核及上层滚动执行的职责划分。","evidence":["ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md"]},{"title":"明确规划器与执行侧边界","detail":"EMPlanner 仅产出经校验的时间轨迹;调度、轨迹交接、换向执行和控制命令由 TrajectoryExecution 承担。","evidence":["ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md","ClumsyPilot/ParkrobTrajplanner/TrajectoryExecution/README.md"]},{"title":"梳理 LS 优化的接口边界","detail":"LS 使用 l、dl、ddl、dddl 变量,在静态走廊与车辆几何约束下求解;求解器通过 IQpSolver/QuadraticProgram 抽象接入。","evidence":["ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md","ClumsyPilot/ParkrobTrajplanner/EMPlanner/Lateral/"]}],"issues":[{"id":"ls-optimization-in-progress","title":"LS 横向优化处于开展阶段","module":"emplanner","evidence_level":"对话发现","discovery":"用户说明当前正在开展 LS 优化工作。","actual":"当前已明确 LS 位于静态走廊之后、ST 之前,并承担横向路径优化与独立几何复核;本日报未取得本轮专项优化结果或回归输出。","expected":"在不破坏静态走廊、导数、Frenet 分母和车辆曲率硬约束的前提下,形成可独立复核的横向候选轨迹。","cause":"优化参数、目标权重、收敛策略及专项场景的本轮验证证据尚待补充。","impact":"LS 结果直接决定后续 ST 使用的实际 PathS 与轨迹可发布性,需先完成可行性和稳定性验证。","improvements":[],"validation":[{"name":"架构与接口静态核对","status":"通过","detail":"README 与 Lateral 目录表明 LS 的数据流、变量及求解器边界已定义;未执行 LS 专项运行测试。"}],"next_steps":["确定 LS 优化目标、权重和约束调参方案。","针对典型前进、倒车及走廊边界场景执行专项回归。"],"evidence":[{"label":"LS 架构说明","reference":"ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md","result":"文档定义 LS SQP、独立横向几何复核及其与 ST 的数据边界。"},{"label":"当前工作说明","reference":"用户需求(2026-08-04)","result":"当前开展 LS 优化工作。"}],"conceptual_visual":true}],"validations":[{"name":"EMPlanner 架构静态核对","status":"通过","detail":"核对 README、Lateral 目录和当日 EMPlanner 提交记录;本次未运行构建或自动化测试。"}],"next_steps":[{"priority":"P0","module":"emplanner","action":"细化并实现 LS 优化策略","done_when":"横向优化目标、约束和候选筛选策略形成可审查实现。"},{"priority":"P1","module":"emplanner","action":"执行 LS 专项回归","done_when":"典型前进、倒车和窄走廊场景均有可复核的运行结果。"},{"priority":"P1","module":"emplanner","action":"联调 LS 到 ST 的 PathS 输入","done_when":"ST 仅消费 LS 已复核且严格递增的实际 PathS,并保留验证记录。"}],"sources":[{"label":"EMPlanner 架构说明","reference":"ClumsyPilot/ParkrobTrajplanner/EMPlanner/README.md"},{"label":"当日 EMPlanner 提交记录","reference":"git log --since='2026-08-04 00:00' -- ClumsyPilot/ParkrobTrajplanner/EMPlanner"},{"label":"LS/ST 观测计划","reference":"docs/superpowers/plans/2026-08-04-em-observation-movementtest.md"}]}</script>
|
||||
<script>'use strict';
|
||||
globalThis.DailySummaryVisuals = (() => {
|
||||
const registry = new Map();
|
||||
|
||||
function register(name, renderer) {
|
||||
if (!/^[a-z0-9][a-z0-9-]+$/.test(name) || typeof renderer !== 'function') {
|
||||
throw new TypeError('invalid visualization adapter');
|
||||
}
|
||||
registry.set(name, renderer);
|
||||
}
|
||||
|
||||
function select(name) {
|
||||
return registry.get(name) || registry.get('composite-scene');
|
||||
}
|
||||
|
||||
function render(view, root, context) {
|
||||
const renderer = select(view.adapter);
|
||||
if (!renderer) throw new Error('composite-scene adapter is not registered');
|
||||
return renderer(view, root, context);
|
||||
}
|
||||
|
||||
return { register, select, render };
|
||||
})();
|
||||
</script>
|
||||
<script> 'use strict';
|
||||
const data = JSON.parse(document.getElementById('report-data').textContent);
|
||||
const app = document.getElementById('daily-summary-app');
|
||||
const issues = Array.isArray(data.issues) ? data.issues : [];
|
||||
let filteredIssues = issues.slice();
|
||||
let selectedIssueId = filteredIssues[0]?.id || '';
|
||||
let selectedSolutionIndex = 0;
|
||||
let showingAfter = false;
|
||||
|
||||
function setText(id, value) {
|
||||
document.getElementById(id).textContent = value == null || value === '' ? '无已记录项' : String(value);
|
||||
}
|
||||
|
||||
function countIssueValidations() {
|
||||
return issues.reduce((total, issue) => total + (issue.validation?.length || 0), 0);
|
||||
}
|
||||
|
||||
function renderHeader() {
|
||||
setText('report-title', data.title);
|
||||
setText('report-summary', data.summary);
|
||||
setText('report-date', data.date);
|
||||
setText('achievement-count', data.achievements?.length || 0);
|
||||
setText('issue-count', issues.length);
|
||||
setText('validation-count', (data.validations?.length || 0) + countIssueValidations());
|
||||
setText('next-count', data.next_steps?.length || 0);
|
||||
}
|
||||
|
||||
function renderFilters() {
|
||||
const root = document.getElementById('evidence-filters');
|
||||
const levels = ['全部', ...new Set(issues.map((issue) => issue.evidence_level))];
|
||||
root.replaceChildren();
|
||||
levels.forEach((level, index) => {
|
||||
const button = document.getElementById('evidence-filter-template').content.firstElementChild.cloneNode(true);
|
||||
button.textContent = level;
|
||||
button.dataset.level = level;
|
||||
button.setAttribute('aria-pressed', String(index === 0));
|
||||
button.addEventListener('click', () => applyFilter(level, button));
|
||||
root.appendChild(button);
|
||||
});
|
||||
}
|
||||
|
||||
function applyFilter(level, activeButton) {
|
||||
document.querySelectorAll('.evidence-filter').forEach((button) => button.setAttribute('aria-pressed', String(button === activeButton)));
|
||||
filteredIssues = level === '全部' ? issues.slice() : issues.filter((issue) => issue.evidence_level === level);
|
||||
selectedIssueId = filteredIssues.some((issue) => issue.id === selectedIssueId) ? selectedIssueId : (filteredIssues[0]?.id || '');
|
||||
renderIssueList();
|
||||
renderSelectedIssue();
|
||||
}
|
||||
|
||||
function renderIssueList() {
|
||||
const root = document.getElementById('issue-list');
|
||||
root.replaceChildren();
|
||||
filteredIssues.forEach((issue) => {
|
||||
const button = document.getElementById('issue-button-template').content.firstElementChild.cloneNode(true);
|
||||
button.dataset.issueId = issue.id;
|
||||
button.querySelector('span').textContent = issue.title;
|
||||
button.querySelector('small').textContent = `${issue.evidence_level} · ${issue.module}`;
|
||||
button.setAttribute('aria-pressed', String(issue.id === selectedIssueId));
|
||||
button.addEventListener('click', () => selectIssue(issue.id));
|
||||
root.appendChild(button);
|
||||
});
|
||||
if (!filteredIssues.length) {
|
||||
const empty = document.createElement('p');
|
||||
empty.className = 'empty';
|
||||
empty.textContent = '该证据等级下没有问题。';
|
||||
root.appendChild(empty);
|
||||
}
|
||||
}
|
||||
|
||||
function selectIssue(issueId) {
|
||||
selectedIssueId = issueId;
|
||||
selectedSolutionIndex = 0;
|
||||
showingAfter = false;
|
||||
renderIssueList();
|
||||
renderSelectedIssue();
|
||||
}
|
||||
|
||||
function currentIssue() {
|
||||
return issues.find((issue) => issue.id === selectedIssueId);
|
||||
}
|
||||
|
||||
function renderSelectedIssue() {
|
||||
const issue = currentIssue();
|
||||
app.dataset.selectedIssue = issue?.id || '';
|
||||
if (!issue) {
|
||||
setText('issue-title', '暂无问题');
|
||||
setText('issue-meta', '当前筛选条件没有可展示的问题。');
|
||||
return;
|
||||
}
|
||||
const badge = document.getElementById('issue-evidence');
|
||||
badge.textContent = issue.evidence_level;
|
||||
badge.dataset.level = issue.evidence_level;
|
||||
setText('issue-title', issue.title);
|
||||
setText('issue-meta', `${issue.id} · ${issue.module}`);
|
||||
setText('issue-discovery', issue.discovery);
|
||||
setText('issue-symptom', issue.actual);
|
||||
setText('issue-cause', issue.cause);
|
||||
setText('issue-impact', issue.impact);
|
||||
setText('issue-actual', showingAfter ? improvementSummary(issue) : issue.actual);
|
||||
setText('actual-label', showingAfter ? '改善后状态' : '实际发生');
|
||||
setText('issue-expected', issue.expected);
|
||||
const toggle = document.getElementById('before-after-toggle');
|
||||
toggle.setAttribute('aria-pressed', String(showingAfter));
|
||||
toggle.textContent = showingAfter ? '返回改善前视图' : '切换为改善后视图';
|
||||
document.getElementById('concept-note').hidden = issue.conceptual_visual === false;
|
||||
renderSolutions(issue);
|
||||
renderValidations(issue);
|
||||
renderRoadmap(issue);
|
||||
}
|
||||
|
||||
function improvementSummary(issue) {
|
||||
if (!issue.improvements?.length) return '尚未记录已完成改善;保持原问题状态。';
|
||||
return issue.improvements.map((item) => `${item.status}:${item.action};${item.result}`).join(';');
|
||||
}
|
||||
|
||||
function renderSolutions(issue) {
|
||||
const steps = issue.improvements?.length ? issue.improvements : issue.next_steps.map((step) => ({ action: step, result: '待执行与验证', status: '下一步' }));
|
||||
const root = document.getElementById('solution-steps');
|
||||
root.replaceChildren();
|
||||
steps.forEach((step, index) => {
|
||||
const button = document.getElementById('solution-step-template').content.firstElementChild.cloneNode(true);
|
||||
button.textContent = `${index + 1}. ${step.action}`;
|
||||
button.setAttribute('aria-pressed', String(index === selectedSolutionIndex));
|
||||
button.addEventListener('click', () => { selectedSolutionIndex = index; renderSolutions(issue); });
|
||||
root.appendChild(button);
|
||||
});
|
||||
const selected = steps[selectedSolutionIndex];
|
||||
setText('solution-title', selected?.action || '尚未记录改善');
|
||||
setText('solution-result', selected ? `${selected.status} · ${selected.result}` : '当前只保留问题,不虚构解决结果。');
|
||||
document.getElementById('previous-solution').disabled = !selected || selectedSolutionIndex === 0;
|
||||
document.getElementById('next-solution').disabled = !selected || selectedSolutionIndex === steps.length - 1;
|
||||
}
|
||||
|
||||
function renderValidations(issue) {
|
||||
const values = [...(issue.validation || []), ...(data.validations || [])];
|
||||
const root = document.getElementById('validation-gates');
|
||||
root.replaceChildren();
|
||||
values.forEach((item) => {
|
||||
const gate = document.getElementById('validation-gate-template').content.firstElementChild.cloneNode(true);
|
||||
gate.dataset.status = item.status;
|
||||
gate.querySelector('h3').textContent = item.name;
|
||||
gate.querySelector('strong').textContent = item.status;
|
||||
gate.querySelector('p').textContent = item.detail;
|
||||
root.appendChild(gate);
|
||||
});
|
||||
if (!values.length) root.appendChild(emptyNode('尚未记录验证结果。'));
|
||||
}
|
||||
|
||||
function renderRoadmap(issue) {
|
||||
const root = document.getElementById('roadmap');
|
||||
root.replaceChildren();
|
||||
const issueSteps = (issue.next_steps || []).map((action) => ({ priority: '问题', module: issue.module, action, done_when: '完成专门验证后关闭。' }));
|
||||
[...issueSteps, ...(data.next_steps || [])].forEach((item) => {
|
||||
const row = document.getElementById('roadmap-item-template').content.firstElementChild.cloneNode(true);
|
||||
row.querySelector('strong').textContent = item.priority;
|
||||
row.querySelector('h3').textContent = `${item.module} · ${item.action}`;
|
||||
row.querySelector('p').textContent = `完成标志:${item.done_when}`;
|
||||
root.appendChild(row);
|
||||
});
|
||||
if (!root.children.length) root.appendChild(emptyNode('尚未记录下一步。'));
|
||||
}
|
||||
|
||||
function emptyNode(message) {
|
||||
const paragraph = document.createElement('p');
|
||||
paragraph.className = 'empty';
|
||||
paragraph.textContent = message;
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
function moveIssue(offset) {
|
||||
if (!filteredIssues.length) return;
|
||||
const index = Math.max(0, filteredIssues.findIndex((issue) => issue.id === selectedIssueId));
|
||||
const next = (index + offset + filteredIssues.length) % filteredIssues.length;
|
||||
selectIssue(filteredIssues[next].id);
|
||||
}
|
||||
|
||||
document.getElementById('before-after-toggle').addEventListener('click', () => { showingAfter = !showingAfter; renderSelectedIssue(); });
|
||||
document.getElementById('previous-solution').addEventListener('click', () => { if (selectedSolutionIndex > 0) { selectedSolutionIndex -= 1; renderSelectedIssue(); } });
|
||||
document.getElementById('next-solution').addEventListener('click', () => { const issue = currentIssue(); const count = issue?.improvements?.length || issue?.next_steps?.length || 0; if (selectedSolutionIndex < count - 1) { selectedSolutionIndex += 1; renderSelectedIssue(); } });
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.target.matches('button, input, select, textarea, [contenteditable="true"]')) return;
|
||||
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
||||
event.preventDefault();
|
||||
moveIssue(event.key === 'ArrowLeft' ? -1 : 1);
|
||||
}
|
||||
});
|
||||
|
||||
renderHeader();
|
||||
renderFilters();
|
||||
renderIssueList();
|
||||
renderSelectedIssue();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,183 +0,0 @@
|
||||
# Local G2 五次 Hermite 路径平滑算法说明
|
||||
|
||||
> 文档定位:说明当前 Local G2 五次 Hermite 路径平滑任务的算法结构、输入、输出和实现边界。
|
||||
> 证据范围:截至 2026-07-31 的实现计划、代码结构和已运行专项检查。
|
||||
|
||||
## 1. 目标、位置与非目标
|
||||
|
||||
### 1.1 它要解决什么问题
|
||||
|
||||
Hybrid A* 粗路径由离散运动基元连接而成。它能提供可行的车辆空间路径,但相邻基元交界处可能出现车辆曲率的突变。曲率突变会使后续连续优化或控制模块得到不够平滑的初值。
|
||||
|
||||
Local G2 五次 Hermite 预平滑的目标,是只在这些局部曲率突变附近,用一小段五次 Hermite 曲线替换原有几何,使连接处的位置、切向趋势和曲率更连续,并且不牺牲车辆碰撞安全、净空和方向切换拓扑。
|
||||
|
||||
### 1.2 它在系统中的位置
|
||||
|
||||
成功的 Hybrid A* 粗路径
|
||||
↓
|
||||
Local G2 五次 Hermite 预平滑
|
||||
↓
|
||||
后续 SQP 或时间参数化模块的空间初始路径
|
||||
|
||||
这里的 Local 表示只修改必要的局部窗口;G2 表示曲线连接处不仅位置相连、切向连续,还要让曲率连续;五次 Hermite 表示每一小段曲线由两端的位置、一阶导数和二阶导数确定。
|
||||
|
||||
### 1.3 本算法不做什么
|
||||
|
||||
- 不重新搜索 Hybrid A*,不改变其代价、地图模型或运动基元生成策略。
|
||||
- 不跨越前进/倒车换向点做曲率计算或曲线拼接。
|
||||
- 不做 SQP 求解、速度规划、加速度规划、轮速分解或动态障碍物预测。
|
||||
- 不承诺当前代码已经把 Local G2 结果正式发布给下游。当前完成的是候选构造和评价层;专用发布流水线仍待接入。
|
||||
|
||||
## 2. 输入:进入算法前必须具备什么
|
||||
|
||||
Local G2 的业务入口设计基于一个路径平滑请求。它需要的输入如下。
|
||||
|
||||
| 输入 | 作用 | 关键要求 |
|
||||
|---|---|---|
|
||||
| 成功的 Hybrid A* 粗路径 | 给出原始空间轨迹与每个点的车辆曲率 | 路径点数值有限,弧长非递减 |
|
||||
| 路径方向段 | 将前进段、倒车段隔离 | 段索引连续,段内方向一致,换向点不被跨越 |
|
||||
| 地图 | 用于完整车体碰撞和净空复核 | 地图查询可用 |
|
||||
| 车辆参数 | 提供车体外形、曲率上限和安全边界 | 曲率约束有效 |
|
||||
| LocalG2QuinticOptions | 控制窗口、偏移、质量门和候选上限 | 所有参数通过有限值与范围校验 |
|
||||
| 公共平滑配置 | 控制输出采样、碰撞步长、净空余量 | 输出采样和碰撞步长必须为正 |
|
||||
| 取消令牌 | 允许耗时计算被安全取消 | 每个候选和区域循环均应检查 |
|
||||
|
||||
### 2.1 坐标和单位
|
||||
|
||||
- 位置、路径长度、窗口长度、偏移和净空:米 m。
|
||||
- 航向:弧度 rad。
|
||||
- 车辆曲率 κ:1/m。
|
||||
- 曲率导数 dκ/ds:1/m²,表示沿路径走一米时曲率变化得有多快。
|
||||
|
||||
### 2.2 Local G2 的默认安全参数
|
||||
|
||||
| 参数 | 默认值 | 含义 |
|
||||
|---|---:|---|
|
||||
| 最小 / 偏好 / 最大窗口长度 | 0.20 / 0.50 / 0.80 m | 单个局部替换允许的长度范围 |
|
||||
| 最大局部偏移 | 0.10 m | 候选曲线不得偏离原始窗口过远 |
|
||||
| 曲率跳变阈值 | max(0.001,0.05 × 最大车辆曲率) | 过滤数值噪声,只处理足够明显的跳变 |
|
||||
| 峰值 dκ/ds 最低改善 | 20% | 候选必须明显降低曲率变化尖峰 |
|
||||
| 曲率变化代价容差 | 2% | 不允许用新的高频摆动换取表面平滑 |
|
||||
| 每区域候选上限 | 12 | 保证计算量与结果可重复 |
|
||||
| 输出采样 / 碰撞检查步长 | 0.025 / 0.025 m | 统一几何分析与连续车体复核的精度 |
|
||||
| 最小净空余量 | 0.02 m | 候选与障碍物必须保留的安全距离 |
|
||||
|
||||
## 3. 模块架构:每个模块负责什么
|
||||
|
||||
| 模块 | 职责 | 当前状态 |
|
||||
|---|---|---|
|
||||
| PathSmoothingPreprocessor | 校验粗路径,将其拆成不跨换向点的方向段,并保留真实起始车辆曲率 | 已实现 |
|
||||
| PathGeometryAnalyzer | 统一重采样,恢复航向,计算 κ、dκ/ds、曲率变化代价等指标 | 已实现 |
|
||||
| CurvatureTransitionDetector | 在同一方向段内检测相邻粗路径点的曲率跳变 | 已实现 |
|
||||
| LocalG2WindowPlanner | 为跳变规划受限局部窗口,并合并可能相互影响的事件 | 已实现 |
|
||||
| QuinticHermiteCurve2D | 由两端的位置、切向导数、二阶导数构造二维五次 Hermite 曲线 | 已实现 |
|
||||
| LocalG2CandidateBuilder | 生成有限数量的候选曲线,处理前进/倒车曲率符号 | 已实现 |
|
||||
| LocalG2PathSplicer | 将一个局部候选替换进完整方向段,同时保持换向拓扑 | 已实现 |
|
||||
| LocalG2CandidateEvaluator | 执行偏移、曲率、碰撞、净空、改善度和确定性排序检查 | 已实现 |
|
||||
| SmoothedPathValidator | 以完整车体模型复核候选路径和相邻点扫掠安全 | 已实现 |
|
||||
| LocalG2PreSmoothingPipeline | 顺序处理全部区域、局部回退、全局回滚并发布最终结果 | 尚未实现 |
|
||||
| PathSmoothingService 的 Local G2 分派 | 将 LocalG2Quintic 请求送入专用流水线 | 尚未接入 |
|
||||
|
||||
## 4. 数据流:从粗路径到候选安全路径
|
||||
|
||||
### 步骤 1:预处理与方向隔离
|
||||
|
||||
粗路径先按前进和倒车拆成方向段。换向点两侧允许同一车辆位姿重复出现,但绝不被当作同一条连续曲线的一部分。这样可以避免把停车换向误判为需要平滑的几何折点。
|
||||
|
||||
### 步骤 2:检测曲率跳变
|
||||
|
||||
检测器只比较同一方向段内相邻粗路径点的车辆曲率。当差值达到阈值时,记录曲率事件:它所在的段、左右点、局部弧长、车辆航向,以及跳变前后的曲率。
|
||||
|
||||
### 步骤 3:规划局部窗口
|
||||
|
||||
窗口规划器围绕每个事件产生不同长度和左右分配的窗口方案。相邻事件若可能相互影响,会被归入同一个区域;每个区域最多输出 12 个确定性窗口/尺度组合,避免随机结果。
|
||||
|
||||
### 步骤 4:构造五次 Hermite 候选
|
||||
|
||||
对一个窗口,候选构造器在窗口两端以及必要的内部曲率事件处建立边界节点。每个节点包含位置、车辆航向、车辆曲率和导数尺度。对每对相邻节点构造一段五次 Hermite 曲线并按 0.025 m 左右的空间间距采样。
|
||||
|
||||
直观理解:原始路径像由短直线和圆弧拼出的折线化轨迹;五次 Hermite 曲线像在局部用一条可控的柔性曲线接住两边,使方向和转弯程度逐步过渡。
|
||||
|
||||
### 步骤 5:拼接候选
|
||||
|
||||
拼接器保留窗口之前和之后的原始点,用精确插值得到窗口端点,再插入候选点。随后重新计算该方向段的局部弧长,保持段首、段尾和换向标志不变。
|
||||
|
||||
### 步骤 6:统一几何分析和完整车体验证
|
||||
|
||||
候选路径与原始窗口都通过同一个几何分析器计算指标,再由完整车体碰撞检查器验证每个姿态和相邻姿态之间的扫掠。这样“看起来更圆滑”的曲线不会绕过实际车体安全检查。
|
||||
|
||||
### 步骤 7:质量门与选优
|
||||
|
||||
一个候选只有同时通过以下检查,才可被接受:
|
||||
|
||||
1. 不超过车辆曲率上限,也不超出原始局部曲率范围。
|
||||
2. 到原始窗口折线的最大偏移不超过 0.10 m。
|
||||
3. 完整路径碰撞检查通过,最小净空不少于 0.02 m。
|
||||
4. 峰值 dκ/ds 至少降低 20%。
|
||||
5. 曲率变化代价不比原始窗口增加超过 2%。
|
||||
|
||||
若多个候选合格,按最大偏移、峰值 dκ/ds、曲率变化代价、路径长度变化和候选索引依次排序,确保结果可重复。
|
||||
|
||||
## 5. 输出:路径、段、指标、区域报告与状态
|
||||
|
||||
### 5.1 候选层已经能够产生的结果
|
||||
|
||||
候选评价层可以得到一条经过完整车体复核的候选安全路径,以及对应的方向段和局部指标。每个输出路径点包含:
|
||||
|
||||
- 位置、航向、展开航向和全局弧长;
|
||||
- 前进或倒车方向;
|
||||
- 几何曲率、车辆曲率、车辆曲率导数 dκ/ds;
|
||||
- 重新计算的车体净空;
|
||||
- 是否为换向点,以及该点来自原始锚点、插值点或 Local G2 过渡点。
|
||||
|
||||
每个方向段则记录其段号、方向、路径点的起止索引,以及换向拓扑标志。
|
||||
|
||||
### 5.2 计划中的正式发布结果
|
||||
|
||||
公共契约已为 Local G2 预留以下最终状态:
|
||||
|
||||
| 状态 | 计划含义 |
|
||||
|---|---|
|
||||
| NotNeeded | 未检测到需要处理的曲率跳变,发布已验证的原始路径 |
|
||||
| Complete | 所有区域都得到有效改善 |
|
||||
| PartialImprovement | 只有部分区域得到有效改善,其余区域保留原样 |
|
||||
| Unchanged | 检测到事件,但没有候选能安全通过质量门 |
|
||||
|
||||
正式结果还应包含每个区域的报告:窗口范围、候选数、被选候选、原始/结果峰值 dκ/ds、曲率变化代价、最大偏移、最小净空和保留原路径的原因。
|
||||
|
||||
### 5.3 当前输出边界
|
||||
|
||||
上述最终状态和区域报告的契约已经存在,但负责顺序处理多个区域、必要时全局回滚、并由服务发布结果的 LocalG2PreSmoothingPipeline 尚未实现。因此,当前代码的准确描述是“可生成和评价局部 G2 候选”,而不是“已经对外发布完整 Local G2 平滑路径”。
|
||||
|
||||
## 6. 安全与质量门
|
||||
|
||||
Local G2 的核心原则不是尽可能把曲线画圆,而是在严格约束下只接受确实更好的局部替换。
|
||||
|
||||
- **方向安全**:不跨换向点,前进/倒车的曲率符号转换只做一次。
|
||||
- **几何安全**:候选端点必须与原始窗口精确对应,避免拼接留下缝隙或重复点。
|
||||
- **车辆安全**:逐点与逐段扫掠检查完整车体,而不是只检查轨迹中心线。
|
||||
- **净空安全**:以本次检查的净空为准,不信任候选输入自带的净空值。
|
||||
- **平滑质量**:以 dκ/ds 的峰值和曲率变化代价衡量改善,避免引入新的摆动。
|
||||
- **确定性**:固定窗口、固定导数尺度顺序和固定排序规则,便于复现与诊断。
|
||||
|
||||
## 7. 当前实现进度与边界
|
||||
|
||||
实施计划共 9 个任务。任务 1 至任务 7 已完成公共契约、真实起始曲率保留、统一 dκ/ds 分析、事件检测、窗口规划、五次 Hermite 几何、候选拼接和质量评价。
|
||||
|
||||
已重新执行并通过的专项检查包括:
|
||||
|
||||
- 路径平滑契约检查;
|
||||
- 粗路径集成与搜索检查;
|
||||
- 路径平滑几何、验证器、服务和比较检查;
|
||||
- Local G2 跳变检测、五次曲线和候选质量检查。
|
||||
|
||||
任务 8 的专用流水线、服务分派和 Local G2 端到端夹具检查尚未实现;任务 9 的完整回归与主路线文档也尚未完成。另有一个共享原始基线回归会在第二份报告中单独说明:RectangleDetour 场景在进入 G2 前的基线复验失败。
|
||||
|
||||
## 8. 证据索引
|
||||
|
||||
- Local G2 实施计划:docs/superpowers/plans/2026-07-30-local-g2-path-presmoothing.md
|
||||
- Local G2 设计说明:docs/superpowers/specs/2026-07-30-local-g2-path-presmoothing-design.md
|
||||
- Local G2 实现目录:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/
|
||||
- 统一几何分析:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Processing/PathGeometryAnalyzer.cs
|
||||
- 完整车体验证:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Validation/SmoothedPathValidator.cs
|
||||
- 专项检查:ClumsyPilot/tests/verify_path_smoothing_local_g2_detection.ps1、verify_path_smoothing_local_g2_curve.ps1、verify_path_smoothing_local_g2_candidates.ps1
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Local G2 五次 Hermite 局部平滑|算法演示</title>
|
||||
<style>
|
||||
:root { color-scheme: light; --ink:#15243a; --muted:#617086; --paper:#f6f8fc; --line:#9aa6b5; --blue:#1976d2; --blue-pale:#dbeeff; --green:#1d8a5b; --amber:#bd7900; --red:#c33b3b; }
|
||||
* { box-sizing:border-box; }
|
||||
body { margin:0; background:linear-gradient(135deg,#eef4fb,#fafbfd); color:var(--ink); font:16px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif; }
|
||||
main { width:min(1160px,100%); margin:auto; padding:clamp(18px,4vw,48px); }
|
||||
header { display:grid; gap:8px; margin-bottom:14px; }
|
||||
h1 { font-size:clamp(1.7rem,4vw,2.75rem); line-height:1.15; margin:0; }
|
||||
h1 + p, .evidence-note { margin:0; color:var(--muted); }
|
||||
.boundary { color:#805700; font-weight:700; }
|
||||
.evidence-note { border-left:4px solid var(--amber); padding-left:10px; }
|
||||
.stepper { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:8px; margin:22px 0 14px; }
|
||||
button { min-height:44px; border:1px solid #b9c7d8; border-radius:10px; padding:8px 10px; color:var(--ink); background:white; font:inherit; cursor:pointer; }
|
||||
button:hover { border-color:var(--blue); } button:focus-visible { outline:3px solid #ffbd3c; outline-offset:2px; } button[aria-pressed="true"] { color:white; background:var(--blue); border-color:var(--blue); font-weight:700; } button:disabled { opacity:.45; cursor:not-allowed; }
|
||||
.diagram-shell { background:white; border:1px solid #d7e0ec; border-radius:18px; overflow:hidden; box-shadow:0 14px 34px #233c6012; }
|
||||
.step-copy { padding:clamp(16px,3vw,28px) clamp(16px,4vw,40px) 4px; } #step-status { color:var(--blue); font-weight:800; letter-spacing:.08em; } h2 { margin:4px 0; font-size:clamp(1.35rem,3vw,2rem); } #step-description { margin:0; color:var(--muted); }
|
||||
svg { width:100%; height:auto; display:block; }
|
||||
.scene-layer { opacity:0; transition:opacity .32s ease; } [data-step="0"] .scene-0, [data-step="1"] .scene-1, [data-step="2"] .scene-2, [data-step="3"] .scene-3, [data-step="4"] .scene-4, [data-step="5"] .scene-5 { opacity:1; }
|
||||
[data-step="1"] .coarse-path-outside { opacity:.26; }
|
||||
.step-controls { display:flex; justify-content:space-between; gap:12px; margin-top:16px; } .step-controls button { width:110px; }
|
||||
@media (max-width:700px) { .stepper { grid-template-columns:repeat(2,minmax(0,1fr)); } }
|
||||
@media (prefers-reduced-motion:reduce) { .scene-layer { transition:none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main id="local-g2-algorithm-demo" data-step="0">
|
||||
<header>
|
||||
<h1>Local G2:五次 Hermite 局部路径平滑</h1>
|
||||
<p>候选层已实现;<span class="boundary">正式发布流水线尚未接入</span>。本页说明候选构造和质量门,不表示正式发布结果。</p>
|
||||
<p class="evidence-note">典型示例:用于解释机制,不代表某次测试的精确坐标。</p>
|
||||
</header>
|
||||
<nav class="stepper" aria-label="Local G2 平滑步骤">
|
||||
<button type="button" class="step-button" data-step="0" aria-pressed="true">0 粗路径</button><button type="button" class="step-button" data-step="1" aria-pressed="false">1 局部窗口</button><button type="button" class="step-button" data-step="2" aria-pressed="false">2 Hermite 约束</button><button type="button" class="step-button" data-step="3" aria-pressed="false">3 局部替换</button><button type="button" class="step-button" data-step="4" aria-pressed="false">4 连续性效果</button><button type="button" class="step-button" data-step="5" aria-pressed="false">5 安全质量门</button>
|
||||
</nav>
|
||||
<section class="diagram-shell" aria-live="polite">
|
||||
<div class="step-copy"><span id="step-status"></span><h2 id="step-title"></h2><p id="step-description"></p></div>
|
||||
<svg id="algorithm-diagram" viewBox="0 0 1200 720" role="img" aria-labelledby="algorithm-svg-title algorithm-svg-desc">
|
||||
<title id="algorithm-svg-title">Local G2 五次 Hermite 局部路径平滑步骤</title><desc id="algorithm-svg-desc">典型粗路径在局部曲率跳变处被五次 Hermite 曲线安全替换的六步示意。</desc>
|
||||
<defs>
|
||||
<marker id="arrow-blue" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0,0 L10,5 L0,10z" fill="#1976d2"/></marker>
|
||||
<marker id="arrow-green" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0,0 L10,5 L0,10z" fill="#1d8a5b"/></marker>
|
||||
<marker id="arrow-red" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0,0 L10,5 L0,10z" fill="#c33b3b"/></marker>
|
||||
</defs>
|
||||
<rect x="0" y="0" width="1200" height="720" fill="#fbfcff"/>
|
||||
<g fill="none" stroke="#dce4ee" stroke-width="1"><path d="M80 100H1120M80 220H1120M80 340H1120M80 460H1120M80 580H1120"/><path d="M120 70V610M300 70V610M480 70V610M660 70V610M840 70V610M1020 70V610"/></g>
|
||||
<g aria-label="始终可见的典型原始路径"><path class="coarse-path-outside" d="M120 462 L290 462" fill="none" stroke="#9aa6b5" stroke-width="12" stroke-linejoin="round"/><path class="coarse-path-window" d="M290 462 L420 462 L520 350 L690 258" fill="none" stroke="#9aa6b5" stroke-width="12" stroke-linejoin="round"/><path class="coarse-path-outside" d="M690 258 L885 133 L1080 95" fill="none" stroke="#9aa6b5" stroke-width="12" stroke-linejoin="round"/><path class="coarse-path-outside" d="M120 462 L290 462" fill="none" stroke="#fff" stroke-width="3" stroke-dasharray="4 11"/><path class="coarse-path-window" d="M290 462 L420 462 L520 350 L690 258" fill="none" stroke="#fff" stroke-width="3" stroke-dasharray="4 11"/><path class="coarse-path-outside" d="M690 258 L885 133 L1080 95" fill="none" stroke="#fff" stroke-width="3" stroke-dasharray="4 11"/>
|
||||
<g fill="#617086"><circle cx="120" cy="462" r="8"/><circle cx="290" cy="462" r="8"/><circle cx="420" cy="462" r="8"/><circle cx="520" cy="350" r="8"/><circle cx="690" cy="258" r="8"/><circle cx="885" cy="133" r="8"/><circle cx="1080" cy="95" r="8"/></g>
|
||||
<text x="92" y="502" fill="#15243a" font-weight="700">起点</text><text x="1050" y="73" fill="#15243a" font-weight="700">终点</text><path d="M145 462 h70" stroke="#1976d2" stroke-width="4" marker-end="url(#arrow-blue)"/><text x="148" y="447" fill="#1976d2">行驶方向</text></g>
|
||||
<g class="scene-layer scene-0"><circle cx="420" cy="462" r="22" fill="none" stroke="#c33b3b" stroke-width="4"/><path d="M398 431 L439 485 M441 431 L400 485" stroke="#c33b3b" stroke-width="4"/><text x="446" y="454" fill="#c33b3b" font-weight="700">κ 跳变</text><text x="84" y="90" fill="#617086" font-size="18">离散点 + 原始折线:局部接口存在方向/曲率突变</text></g>
|
||||
<g class="scene-layer scene-1"><rect x="290" y="184" width="400" height="340" rx="18" fill="#dbeeff" opacity=".7"/><line x1="290" y1="180" x2="290" y2="535" stroke="#1976d2" stroke-width="4" stroke-dasharray="10 8"/><line x1="690" y1="180" x2="690" y2="535" stroke="#1976d2" stroke-width="4" stroke-dasharray="10 8"/><text x="300" y="210" fill="#1976d2" font-weight="700">局部窗口:只处理跳变附近</text><text x="252" y="555" fill="#1976d2">窗口边界</text><text x="650" y="555" fill="#1976d2">窗口边界</text></g>
|
||||
<g class="scene-layer scene-2"><path d="M290 462 h180 M690 258 l156 -100" stroke="#1976d2" stroke-width="4" marker-end="url(#arrow-blue)"/><path d="M310 432 Q350 400 388 438 M660 290 Q700 315 730 270" fill="none" stroke="#1976d2" stroke-width="3" stroke-dasharray="8 7"/><text x="334" y="401" fill="#1976d2">二阶趋势</text><text x="737" y="253" fill="#1976d2">端点切向</text><path id="quintic-candidate" fill="none" stroke="#1976d2" stroke-width="7" stroke-dasharray="13 8"/><text x="430" y="300" fill="#1976d2" font-weight="700">五次 Hermite 候选(位置 + 切向 + 二阶趋势)</text></g>
|
||||
<g class="scene-layer scene-3"><path id="replacement-candidate" fill="none" stroke="#1d8a5b" stroke-width="10"/><circle cx="290" cy="462" r="13" fill="white" stroke="#1d8a5b" stroke-width="5"/><circle cx="690" cy="258" r="13" fill="white" stroke="#1d8a5b" stroke-width="5"/><text x="245" y="430" fill="#1d8a5b" font-weight="700">替换开始</text><text x="650" y="235" fill="#1d8a5b" font-weight="700">替换结束</text><text x="410" y="520" fill="#1d8a5b" font-weight="700">绿色候选覆盖灰色原折线</text></g>
|
||||
<g class="scene-layer scene-4"><rect x="70" y="70" width="1060" height="420" rx="16" fill="#f0faf5" stroke="#b8dfca"/><path id="continuity-candidate" fill="none" stroke="#1d8a5b" stroke-width="9"/><text x="90" y="105" fill="#1d8a5b" font-weight="700">替换后路径:窗口外不变,接口趋势连续</text><g transform="translate(110 530)"><path d="M0 0V150M0 150H850" stroke="#617086" stroke-width="3"/><text x="-20" y="5" fill="#617086">κ</text><text x="855" y="160" fill="#617086">s</text><path d="M60 118 L290 118 L300 38 L520 38" stroke="#c33b3b" stroke-width="6" fill="none"/><path d="M60 118 C230 118 280 106 355 84 S465 46 520 38" stroke="#1d8a5b" stroke-width="6" fill="none"/><text x="535" y="43" fill="#c33b3b">原始跳变</text><text x="535" y="73" fill="#1d8a5b">候选连续过渡</text><text x="520" y="130" fill="#617086">趋势示意,非实测数据</text></g></g>
|
||||
<g class="scene-layer scene-5"><path id="safety-candidate" fill="none" stroke="#1d8a5b" stroke-width="36" opacity=".18"/><path id="accepted-candidate" fill="none" stroke="#1d8a5b" stroke-width="8"/><g fill="#fff" stroke="#1d8a5b" stroke-width="4"><circle cx="300" cy="462" r="13"/><circle cx="500" cy="382" r="13"/><circle cx="680" cy="266" r="13"/></g><g fill="#1d8a5b" font-weight="700"><text x="720" y="370">✓ 碰撞(完整车体安全)</text><text x="720" y="402">✓ 净空</text><text x="720" y="434">✓ 曲率</text><text x="720" y="466">✓ 偏移</text></g><g transform="translate(320 435) rotate(0)"><rect x="-28" y="-15" width="56" height="30" rx="6" fill="#fff" stroke="#1d8a5b" stroke-width="4"/><circle cx="-17" cy="18" r="5"/><circle cx="17" cy="18" r="5"/></g><g transform="translate(500 348) rotate(-30)"><rect x="-28" y="-15" width="56" height="30" rx="6" fill="#fff" stroke="#1d8a5b" stroke-width="4"/><circle cx="-17" cy="18" r="5"/><circle cx="17" cy="18" r="5"/></g><g transform="translate(660 278) rotate(-28)"><rect x="-28" y="-15" width="56" height="30" rx="6" fill="#fff" stroke="#1d8a5b" stroke-width="4"/><circle cx="-17" cy="18" r="5"/><circle cx="17" cy="18" r="5"/></g><text x="90" y="90" fill="#1d8a5b" font-size="18">通过质量门后才接受候选;任一门阻断则回退原路径</text><text x="90" y="120" fill="#617086" font-size="16">车辆轮廓为机制示意,非实测数据</text><path d="M1020 478V500" fill="none" stroke="#c33b3b" stroke-width="3" stroke-dasharray="7 6" marker-end="url(#arrow-red)"/><rect x="720" y="515" width="390" height="72" rx="10" fill="#fff0f1" stroke="#c33b3b" stroke-width="3"/><text x="742" y="543" fill="#c33b3b" font-weight="700">条件分支:任一门失败</text><text x="742" y="570" fill="#c33b3b" font-weight="700">拒绝候选 → 回退灰色原路径</text></g>
|
||||
<g transform="translate(80 700)"><rect width="22" height="12" fill="#9aa6b5"/><text x="30" y="12" fill="#617086">原始粗路径</text><rect x="185" width="22" height="12" fill="#1976d2"/><text x="215" y="12" fill="#617086">窗口/约束</text><rect x="340" width="22" height="12" fill="#1d8a5b"/><text x="370" y="12" fill="#617086">已接受候选</text><rect x="535" width="22" height="12" fill="#bd7900"/><text x="565" y="12" fill="#617086">发布边界</text><rect x="705" width="22" height="12" fill="#c33b3b"/><text x="735" y="12" fill="#617086">拒绝/阻断</text></g>
|
||||
</svg>
|
||||
</section>
|
||||
<p class="boundary">事实边界:正式发布流水线尚未接入;图中的绿色仅代表通过本演示中的典型质量门。</p>
|
||||
<div class="step-controls"><button id="prev-step" type="button">上一步</button><button id="next-step" type="button">下一步</button></div>
|
||||
</main>
|
||||
<script>
|
||||
const hermite = {
|
||||
p0: { x: 290, y: 462 }, p1: { x: 690, y: 258 },
|
||||
d0: { x: 180, y: 0 }, d1: { x: 195, y: -125 },
|
||||
a0: { x: 0, y: 0 }, a1: { x: 0, y: 0 }
|
||||
};
|
||||
function quinticBasis(t) {
|
||||
const t2 = t * t, t3 = t2 * t, t4 = t3 * t, t5 = t4 * t;
|
||||
return [
|
||||
1 - 10 * t3 + 15 * t4 - 6 * t5,
|
||||
t - 6 * t3 + 8 * t4 - 3 * t5,
|
||||
0.5 * (t2 - 3 * t3 + 3 * t4 - t5),
|
||||
10 * t3 - 15 * t4 + 6 * t5,
|
||||
-4 * t3 + 7 * t4 - 3 * t5,
|
||||
0.5 * (t3 - 2 * t4 + t5)
|
||||
];
|
||||
}
|
||||
function buildQuinticPath() {
|
||||
const points = [];
|
||||
for (let i = 0; i <= 48; i += 1) {
|
||||
const [h00, h10, h20, h01, h11, h21] = quinticBasis(i / 48);
|
||||
points.push({
|
||||
x: h00 * hermite.p0.x + h10 * hermite.d0.x + h20 * hermite.a0.x + h01 * hermite.p1.x + h11 * hermite.d1.x + h21 * hermite.a1.x,
|
||||
y: h00 * hermite.p0.y + h10 * hermite.d0.y + h20 * hermite.a0.y + h01 * hermite.p1.y + h11 * hermite.d1.y + h21 * hermite.a1.y
|
||||
});
|
||||
}
|
||||
return points.map((point, index) => `${index === 0 ? 'M' : 'L'} ${point.x.toFixed(1)} ${point.y.toFixed(1)}`).join(' ');
|
||||
}
|
||||
const pathData=buildQuinticPath(); ['quintic-candidate','replacement-candidate','continuity-candidate','safety-candidate','accepted-candidate'].forEach((id)=>document.getElementById(id).setAttribute('d',pathData));
|
||||
const steps=[['0 / 5','原始 Hybrid A* 粗路径','可行离散路径在局部接口处仍可能有曲率跳变。'],['1 / 5','检测并框定局部窗口','只处理跳变附近,不重新搜索整条路径。'],['2 / 5','由端点约束构造五次 Hermite 候选','位置、切向和曲率趋势共同确定局部曲线。'],['3 / 5','替换窗口内部的原始几何','窗口外路径保持不变,接缝需要连续。'],['4 / 5','观察曲率—弧长连续性','目标是消除接口处的趋势跳变,而不是只让外形更圆。'],['5 / 5','经安全与质量门决定接受或回退','候选必须同时满足车体安全、净空、曲率和偏移约束。']];
|
||||
const stepButtons=[...document.querySelectorAll('.step-button')];
|
||||
function setStep(index) { const next=Math.max(0,Math.min(steps.length-1,index)); const [status,title,description]=steps[next]; document.getElementById('local-g2-algorithm-demo').dataset.step=String(next); document.getElementById('step-status').textContent=`步骤 ${status}`; document.getElementById('step-title').textContent=title; document.getElementById('step-description').textContent=description; stepButtons.forEach((button)=>button.setAttribute('aria-pressed',String(Number(button.dataset.step)===next))); document.getElementById('prev-step').disabled=next===0; document.getElementById('next-step').disabled=next===steps.length-1; }
|
||||
stepButtons.forEach((button)=>button.addEventListener('click',()=>setStep(Number(button.dataset.step)))); document.getElementById('prev-step').addEventListener('click',()=>setStep(Number(document.getElementById('local-g2-algorithm-demo').dataset.step)-1)); document.getElementById('next-step').addEventListener('click',()=>setStep(Number(document.getElementById('local-g2-algorithm-demo').dataset.step)+1));
|
||||
document.addEventListener('keydown',(event)=>{ const target=event.target; if(event.altKey||event.ctrlKey||event.metaKey||event.shiftKey||target.matches('input, textarea, select, button, [contenteditable="true"]')) return; if(event.key==='ArrowLeft'||event.key==='ArrowRight') { event.preventDefault(); setStep(Number(document.getElementById('local-g2-algorithm-demo').dataset.step)+(event.key==='ArrowLeft'?-1:1)); } }); setStep(0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,185 +0,0 @@
|
||||
# Local G2 路径平滑问题分析与后续措施
|
||||
|
||||
> 文档定位:记录当前 Local G2 五次 Hermite 任务在进入正式服务接入前发现的问题、证据边界和下一步行动。
|
||||
> 核心原则:专项测试通过,说明某个局部能力有效;它不自动等同于真实场景下的端到端功能已经完成。
|
||||
|
||||
## 1. 阅读本报告前:证据等级说明
|
||||
|
||||
本报告使用三种证据等级,避免把不同确定性的结论混在一起。
|
||||
|
||||
| 证据等级 | 含义 | 本报告中的问题 |
|
||||
|---|---|---|
|
||||
| 已复现故障 | 已通过实际构建和测试命令稳定观察到失败 | 问题一 |
|
||||
| 静态分析确认的逻辑缺口 | 从当前代码的输入、约束和控制流可以直接推导出不一致 | 问题二 |
|
||||
| 待验证集成风险 | 当前代码结构在未来接入流程中可能导致错误,但尚无完整流水线可实际复现 | 问题三 |
|
||||
|
||||
已经通过的专项检查包括:Local G2 契约、曲率导数、跳变检测、五次曲线、候选构造、候选质量门,以及共享的粗路径与平滑基础检查。本报告不否定这些检查的价值,而是说明它们尚未覆盖的组合场景。
|
||||
|
||||
## 2. 问题一:RectangleDetour 原始基线复验失败
|
||||
|
||||
### 2.1 现象
|
||||
|
||||
这是一个 **已复现故障**。
|
||||
|
||||
在端到端检查中,RectangleDetour 场景的 Hybrid A* 粗路径规划成功;但平滑模块建立“原始粗路径基线”时失败,结果从预期的 Success 变成 InvalidInput。实际测试输出为:
|
||||
|
||||
Raw baseline RectangleDetour must remain a feasible, verified copy of the coarse path.
|
||||
Expected=Success Actual=InvalidInput
|
||||
|
||||
失败发生在 Local G2 候选生成之前。因此当前不能说“G2 平滑失败了”;更准确的说法是:这条真实粗路径还没有通过进入任何平滑算法前的统一基线复验。
|
||||
|
||||
### 2.2 生动例子
|
||||
|
||||
把路径平滑想成给一条已经规划出的山路做局部铺装。
|
||||
|
||||
RectangleDetour 这条山路的导航系统已经证明车辆能走到终点,相当于 Hybrid A* 已经找到了路。但在铺装前,工程人员用更严格的尺子重新测量道路的弯曲程度和车身扫过的范围。测量门禁认为这段路有不满足要求的地方,于是道路在进入铺装工序前被拦下。
|
||||
|
||||
此时不应强行开始铺装,也不应为了让它通过而降低安全门禁;先要查清是哪一个测量点、哪一种曲率或几何计算触发了拒绝。
|
||||
|
||||
### 2.3 为什么会出现这个现象
|
||||
|
||||
任务 3 将原始粗路径也接入与候选曲线相同的几何分析器和完整车体验证器,这是为了实现公平比较。当前链路为:
|
||||
|
||||
粗路径 → 预处理与方向分段 → 统一重采样和曲率分析
|
||||
→ 完整车体/扫掠复验 → 原始基线
|
||||
|
||||
当前配置把输出采样间距设为 0.025 m;基线会在该间距下重新计算曲率和曲率导数,再进行车辆曲率、姿态和扫掠检查。已取得的诊断只说明“平滑路径包含非法数值或超限车辆曲率”,还没有定位到具体样本、具体方向段或根本原因。
|
||||
|
||||
因此可以确认的是“基线复验失败”;尚不能确认是原始粗路径本身超限、重采样的端点处理问题,还是某个几何分析/验证边界条件的问题。
|
||||
|
||||
### 2.4 影响
|
||||
|
||||
- RectangleDetour 无法进入 Local G2,也无法进入其他依赖同一基线的平滑比较流程。
|
||||
- 任务 8 的专用流水线应把已验证原始基线视为前提,因此此问题必须优先解决。
|
||||
- 如果简单放松基线检查,可能把真正不可执行的路径传给后续 SQP 或控制模块,风险不可接受。
|
||||
|
||||
### 2.5 下一步措施
|
||||
|
||||
1. 为 RectangleDetour 建立最小诊断复现:记录每个方向段的原始点、重采样点、最大绝对车辆曲率、车辆曲率上限、最小净空和验证失败位置。
|
||||
2. 对同一粗路径比较原始点序列与 0.025 m 重采样后的几何结果,定位第一次超限或非有限值出现的位置。
|
||||
3. 根据证据只修复源头:若粗路径本身确实违反车辆约束,修复粗路径输出或场景;若重采样/端点分析失真,修复分析器并保留完整安全门。
|
||||
4. 将该场景加入专门回归,防止以后再次出现“规划成功但基线不可用”的断链。
|
||||
|
||||
### 2.6 验收条件
|
||||
|
||||
- RectangleDetour 的粗路径仍需保持规划成功。
|
||||
- 原始基线必须回到 Success,且仍经过相同的完整车体和扫掠复验。
|
||||
- 诊断测试能够指出首次异常的方向段和样本,而不是只返回笼统的 InvalidInput。
|
||||
- 不通过放宽曲率、碰撞或净空门限来获得绿色结果。
|
||||
|
||||
## 3. 问题二:窗口合并范围与候选长度上限不一致
|
||||
|
||||
### 3.1 现象
|
||||
|
||||
这是一个 **静态分析确认的逻辑缺口**。
|
||||
|
||||
窗口规划器用“事件位置左右各扩展最大窗口长度”的包络判断两个事件是否合并。默认最大窗口长度为 0.8 m,因此合并判断可使用约 1.6 m 宽的影响范围。
|
||||
|
||||
但实际生成候选窗口时,候选的总长度又被限制为不超过 0.8 m。于是两个相距较远、但仍落入合并包络的事件可能被合并为一个区域;合并后却没有一条长度不超过 0.8 m 的窗口能够同时覆盖它们,最终该区域没有合法候选。
|
||||
|
||||
### 3.2 生动例子
|
||||
|
||||
想象道路上有两个需要修补的小坑:
|
||||
|
||||
- 第一个坑在 0.4 m 处;
|
||||
- 第二个坑在 1.4 m 处;
|
||||
- 两坑相距 1.0 m。
|
||||
|
||||
系统先用一个很大的“可能影响范围”判断两坑会互相影响,于是把它们装进同一个维修任务。随后维修车被规定一次只能铺 0.8 m 长的补丁。要同时盖住相距 1.0 m 的两个坑,补丁至少要 1.0 m 长,因此没有任何合法补丁。
|
||||
|
||||
本来可以分别处理两个坑,结果因为过早合并,两者都没有被处理。
|
||||
|
||||
### 3.3 为什么会出现这个现象
|
||||
|
||||
当前窗口规划存在两套长度语义:
|
||||
|
||||
- 合并阶段的最大影响范围使用 event ± 0.8 m;
|
||||
- 候选阶段的最大总窗口长度使用 0.8 m。
|
||||
|
||||
如果“0.8 m”定义为总窗口长度,这两套语义不一致。合并阶段把每一侧都当作可以扩展 0.8 m,而候选阶段只能让左右两侧合计为 0.8 m。
|
||||
|
||||
现有检测测试覆盖了两个非常接近、确实应该合并的事件;尚未覆盖“会被合并,但无法被一个最大长度窗口同时覆盖”的中间距离场景。
|
||||
|
||||
### 3.4 影响
|
||||
|
||||
- 某些本可分别平滑的局部曲率跳变会被整体保留。
|
||||
- 任务 8 若直接消费空候选区域,可能把它报告为候选生成失败,掩盖真正的窗口规划逻辑问题。
|
||||
- 不同场景下的改善率可能不稳定:不是因为曲线质量差,而是因为区域边界定义不一致。
|
||||
|
||||
### 3.5 下一步措施
|
||||
|
||||
1. 先明确 0.8 m 的唯一语义:它是候选总长度,还是允许每一侧各 0.8 m。现有配置和候选生成逻辑均把它当作总长度。
|
||||
2. 增加窗口规划回归:两个相距 1.0 m 的事件在默认参数下应保持为两个可独立处理的区域,或在明确允许更长联合窗口时生成实际可用的联合候选。
|
||||
3. 让合并包络依据真实可生成的最大窗口范围计算,而不是使用大于候选总长度的宽泛包络。
|
||||
4. 对区域中候选数为零的情况提供稳定诊断,区分“没有可行曲线”和“窗口规划把可处理事件合并过度”。
|
||||
|
||||
### 3.6 验收条件
|
||||
|
||||
- 新增的 1.0 m 间距回归测试稳定通过。
|
||||
- 每个检测到的区域要么有至少一个符合长度约束的候选窗口,要么有明确且正确的不可用原因。
|
||||
- 既有重叠事件合并测试、近起点非对称窗口测试仍通过。
|
||||
|
||||
## 4. 问题三:连续处理多个区域时的弧长定位风险
|
||||
|
||||
### 4.1 现象
|
||||
|
||||
这是一个 **待验证集成风险**,不是已经在完整 Local G2 流水线中复现的故障。
|
||||
|
||||
局部拼接后,拼接器会根据新的几何形状重新计算整个方向段的局部弧长。候选评价器则会使用候选保存的起止弧长在当前路径中提取窗口。未来任务 8 需要顺序处理多个区域;若前一个区域改变了长度,后一个区域若仍使用原始弧长坐标,就可能定位到错误的位置。
|
||||
|
||||
### 4.2 生动例子
|
||||
|
||||
一条道路上有区域 A 和区域 B:
|
||||
|
||||
- 原始道路中,区域 A 位于 1.0–1.5 m;
|
||||
- 区域 B 位于 3.0–3.5 m;
|
||||
- 修补区域 A 后,道路局部变长了 0.06 m。
|
||||
|
||||
如果系统仍在“新道路”的 3.0–3.5 m 处寻找区域 B,它实际上会比原始区域 B 早 0.06 m 找到位置。轻则候选端点对不上而被拒绝,重则替换到了错误的局部区间。
|
||||
|
||||
上面的 0.06 m 只是帮助理解的示意数值,并非已经测得的实际误差。
|
||||
|
||||
### 4.3 为什么会出现这个现象
|
||||
|
||||
候选构造使用原始方向段和原始窗口的起止弧长。拼接器替换一处后会重算当前方向段内所有点的弧长。候选评价器随后从当前路径按候选的旧起止弧长提取窗口,并尝试再次拼接。
|
||||
|
||||
任务 8 的设计本身要求顺序保留已接受的早期替换,因此它必须明确回答一个问题:后续区域应使用原始参考弧长,还是当前路径弧长?当前候选层尚没有负责这类坐标映射的专用机制。
|
||||
|
||||
### 4.4 影响
|
||||
|
||||
- 同一方向段含多个彼此分离的曲率事件时,后续区域可能不能被正确处理。
|
||||
- 结果可能依赖区域处理顺序,破坏确定性。
|
||||
- 即使每个单独候选都能通过专项检查,组合处理时仍可能出现端点错配、错误替换或不必要回退。
|
||||
|
||||
### 4.5 下一步措施
|
||||
|
||||
1. 在任务 8 之前定义稳定坐标策略:可以保留原始参考弧长并建立“原始弧长到当前路径位置”的映射,也可以在每次成功拼接后重新定位剩余区域和重新生成候选。
|
||||
2. 新增双区域顺序替换回归:同一方向段内两个不重叠区域,第一处替换必须产生可观测长度变化,第二处仍必须命中原始语义上的正确窗口。
|
||||
3. 在测试中重复运行两次,比较状态、路径点坐标、区域报告和被选候选索引,验证处理顺序和结果确定性。
|
||||
4. 只有上述回归通过后,才实现任务 8 的多区域发布与全局回滚。
|
||||
|
||||
### 4.6 验收条件
|
||||
|
||||
- 区域 A 被接受且路径长度变化后,区域 B 的窗口端点仍与其原始参考位置对应。
|
||||
- 两区域替换后,完整路径通过相同的碰撞、净空、曲率和拓扑验证。
|
||||
- 同一输入连续运行两次,输出状态、点数、坐标和区域报告一致。
|
||||
|
||||
## 5. 进入任务 8 前的行动顺序与验收条件
|
||||
|
||||
| 优先级 | 行动 | 原因 | 完成标志 |
|
||||
|---|---|---|---|
|
||||
| P0 | 定位并修复 RectangleDetour 原始基线复验 | 没有可信原始基线,任何 G2 发布都失去安全前提 | 场景基线 Success,诊断可定位问题来源 |
|
||||
| P1 | 补充窗口合并边界回归并统一 0.8 m 语义 | 防止可独立平滑的事件被错误合并后放弃 | 1.0 m 间距场景有正确区域/候选结果 |
|
||||
| P1 | 补充双区域顺序替换回归并确定弧长坐标策略 | 防止多区域处理发生错位 | 第二个区域命中正确语义窗口且结果确定 |
|
||||
| P2 | 实现 LocalG2PreSmoothingPipeline 和服务分派 | 将候选层能力变为可发布的完整空间初始路径 | Local G2 端到端夹具、服务和完整回归全部通过 |
|
||||
|
||||
在 P0、P1 未完成前,不应把 Local G2 标为“可供下游正式消费”的平滑主路线。
|
||||
|
||||
## 6. 证据索引
|
||||
|
||||
- 端到端失败检查:ClumsyPilot/tests/verify_path_smoothing_integration.ps1
|
||||
- 原始基线构建:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Processing/RawPathBaselineBuilder.cs
|
||||
- 窗口规划:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/LocalG2WindowPlanner.cs
|
||||
- 局部拼接:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/LocalG2PathSplicer.cs
|
||||
- 候选评价:ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/LocalG2CandidateEvaluator.cs
|
||||
- Local G2 实施计划:docs/superpowers/plans/2026-07-30-local-g2-path-presmoothing.md
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Local G2:实际证据与正确预期</title>
|
||||
<style>
|
||||
:root { --ink:#173448; --muted:#5e7180; --paper:#f3f7f9; --panel:#fff; --line:#cddbe3; --actual:#b8323d; --actual-bg:#fff0f1; --expected:#24724c; --expected-bg:#ecf8f0; --info:#226b9c; --warn:#9a6312; }
|
||||
* { box-sizing:border-box; }
|
||||
body { margin:0; color:var(--ink); background:var(--paper); font-family:"Microsoft YaHei","PingFang SC",Arial,sans-serif; line-height:1.65; }
|
||||
main { max-width:1240px; margin:auto; padding:28px 20px 52px; }
|
||||
header { color:#fff; background:linear-gradient(135deg,#14374e,#2e6682); border-radius:18px; padding:29px; box-shadow:0 10px 24px #15364d2b; }
|
||||
h1,h2,h3,p { margin-top:0; } h1 { font-size:clamp(1.65rem,4vw,2.35rem); margin-bottom:7px; } h2 { font-size:clamp(1.28rem,3vw,1.65rem); margin:0; } h3 { margin-bottom:7px; font-size:1rem; }
|
||||
.eyebrow { font-size:.82rem; letter-spacing:.08em; opacity:.86; } .subtitle { max-width:900px; color:#e1f0f7; margin-bottom:16px; }
|
||||
.badges,.issue-selector,.issue-controls { display:flex; flex-wrap:wrap; gap:10px; }
|
||||
.badge { display:inline-block; border-radius:999px; padding:3px 10px; font-size:.83rem; font-weight:700; }
|
||||
.badge.repro { color:#7b1620; background:#ffd9dd; } .badge.static { color:#6f4808; background:#ffe8bc; } .badge.risk { color:#164e74; background:#d4ebfa; }
|
||||
.issue-selector { margin:24px 0 14px; } button { font:inherit; cursor:pointer; }
|
||||
.issue-button,.issue-controls button { border:1px solid #b8cad4; border-radius:10px; padding:10px 14px; color:var(--ink); background:#fff; font-weight:700; }
|
||||
.issue-button[aria-pressed="true"] { color:#fff; border-color:#174b68; background:#174b68; }
|
||||
button:focus-visible { outline:3px solid #f0ad32; outline-offset:3px; }
|
||||
.issue-stage { background:var(--panel); border:1px solid var(--line); border-radius:16px; padding:22px; box-shadow:0 4px 12px #15364d0d; }
|
||||
#issue-evidence { display:inline-block; margin-bottom:5px; color:var(--info); font-size:.87rem; font-weight:800; }
|
||||
.visual-wrap { margin:18px -4px; padding:4px; } #issue-visual { display:block; width:100%; height:auto; }
|
||||
.issue-scene { display:none; } #local-g2-issue-demo[data-issue="baseline"] .issue-scene[data-issue="baseline"], #local-g2-issue-demo[data-issue="window"] .issue-scene[data-issue="window"], #local-g2-issue-demo[data-issue="arclength"] .issue-scene[data-issue="arclength"] { display:block; }
|
||||
.compare-copy { display:grid; grid-template-columns:repeat(3,1fr); gap:13px; } .compare-copy article { border:1px solid var(--line); border-radius:10px; padding:14px; } .compare-copy article:nth-child(1) { border-top:4px solid var(--actual); } .compare-copy article:nth-child(2) { border-top:4px solid var(--expected); } .compare-copy article:nth-child(3) { border-top:4px solid var(--info); } .compare-copy p { margin-bottom:0; }
|
||||
.next-action { margin:15px 0 0; padding:12px 14px; border-radius:9px; background:#edf4f7; } .issue-controls { justify-content:space-between; margin-top:14px; } .issue-controls button { background:#eaf2f5; }
|
||||
.priority { display:grid; grid-template-columns:72px 1fr; margin-top:28px; overflow:hidden; border:1px solid var(--line); border-radius:14px; background:#fff; } .priority div { padding:12px 15px; border-bottom:1px solid var(--line); } .priority div:nth-last-child(-n+2) { border-bottom:0; } .priority .p0,.priority .p1,.priority .p2 { font-weight:800; text-align:center; } .p0 { background:#ffe5e7; color:#8a1722; } .p1 { background:#fff4dc; color:#79500b; } .p2 { background:#eaf5fd; color:#165a84; }
|
||||
footer { margin-top:25px; color:var(--muted); font-size:.86rem; }
|
||||
.lane { fill:#fbfcfd; stroke:#cbd9e2; stroke-width:2; } .lane-label { fill:#173448; font-size:18px; font-weight:800; } .label { fill:#415a6b; font-size:15px; font-weight:700; } .small { fill:#5e7180; font-size:13px; } .actual-box { fill:var(--actual-bg); stroke:var(--actual); stroke-width:2.5; } .expected-box { fill:var(--expected-bg); stroke:var(--expected); stroke-width:2.5; } .info-box { fill:#edf6fc; stroke:var(--info); stroke-width:2.5; } .path-old { fill:none; stroke:#9aa9b3; stroke-width:7; stroke-linecap:round; } .path-actual { fill:none; stroke:var(--actual); stroke-width:7; stroke-linecap:round; } .path-expected { fill:none; stroke:var(--expected); stroke-width:7; stroke-linecap:round; } .arrow { fill:none; stroke:#597181; stroke-width:2.5; marker-end:url(#arrow); } .dash { stroke-dasharray:8 7; } .measure { stroke:#637786; stroke-width:2; } .actual-text { fill:#9a202b; font-weight:800; } .expected-text { fill:#1d6744; font-weight:800; } .note-text { fill:#5e7180; font-size:13px; font-style:italic; }
|
||||
@media (max-width:680px) { main { padding:16px 12px 38px; } header,.issue-stage { padding:18px; } .compare-copy { grid-template-columns:1fr; } .issue-controls button { flex:1; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main id="local-g2-issue-demo" data-issue="baseline">
|
||||
<header>
|
||||
<div class="eyebrow">离线几何对照 · Local G2</div>
|
||||
<h1>把“实际发生”与“正确应有”放在同一把尺上</h1>
|
||||
<p class="subtitle">红色是已知实际或风险,绿色是正确预期。三类证据不能混用:端到端复现、静态分析确认与待验证集成风险分别标示。</p>
|
||||
<div class="badges"><span class="badge repro">已复现故障</span><span class="badge static">静态分析确认</span><span class="badge risk">待验证风险</span></div>
|
||||
</header>
|
||||
|
||||
<nav class="issue-selector" aria-label="选择要查看的 Local G2 问题">
|
||||
<button type="button" class="issue-button" data-issue="baseline" aria-pressed="true">问题一:基线失败</button>
|
||||
<button type="button" class="issue-button" data-issue="window" aria-pressed="false">问题二:窗口约束</button>
|
||||
<button type="button" class="issue-button" data-issue="arclength" aria-pressed="false">问题三:弧长错位</button>
|
||||
</nav>
|
||||
|
||||
<section class="issue-stage" aria-live="polite">
|
||||
<div class="issue-copy"><span id="issue-evidence">已复现故障 · RectangleDetour</span><h2 id="issue-title">原始基线在 Local G2 开始前被拒绝</h2></div>
|
||||
<div class="visual-wrap">
|
||||
<svg id="issue-visual" viewBox="0 0 1200 700" role="img" aria-labelledby="issue-svg-title issue-svg-desc">
|
||||
<title id="issue-svg-title">Local G2 问题的实际与正确几何对照</title><desc id="issue-svg-desc">选择一个问题,查看共享比例下的实际状态、正确预期与证据边界。</desc>
|
||||
<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0L10 5L0 10z" fill="#597181"/></marker></defs>
|
||||
<g class="issue-scene" data-issue="baseline">
|
||||
<rect class="lane" x="25" y="22" width="1150" height="200" rx="16"/><text class="lane-label" x="52" y="54">概念性 RectangleDetour 绕障路径(不是已定位的坏样本)</text>
|
||||
<path class="path-old" d="M95 158H480H1080"/><text class="small" x="96" y="187">灰色:原始路径</text><rect x="530" y="113" width="125" height="80" rx="7" fill="#687985"/><text fill="#fff" font-size="16" font-weight="700" x="568" y="157">障碍物</text>
|
||||
<path class="path-actual" d="M95 158H420Q450 158 462 130L485 82Q497 60 522 60H670Q696 60 709 86L732 133Q744 158 770 158H1080"/><text class="actual-text" x="270" y="116">概念绕障</text><circle cx="748" cy="136" r="21" fill="#fff0f1" stroke="#b8323d" stroke-width="3"/><text class="actual-text" x="741" y="144" font-size="25">?</text><text class="actual-text" x="780" y="126">待定位</text><text class="small" x="780" y="147">首次失败样本待定位</text>
|
||||
<rect class="lane" x="25" y="244" width="1150" height="182" rx="16"/><text class="lane-label" x="52" y="276">链路对照</text><text class="actual-text" x="58" y="308">实际</text>
|
||||
<rect class="info-box" x="135" y="286" width="205" height="60" rx="9"/><text class="label" x="178" y="322">Hybrid A*</text><text class="small" x="188" y="341">Success</text><path class="arrow" d="M340 316H432"/><text class="small" x="349" y="301">Success → InvalidInput</text><rect class="actual-box" x="432" y="286" width="245" height="60" rx="9"/><text class="actual-text" x="471" y="322">原始基线复验</text><text class="actual-text" x="506" y="341">InvalidInput ⛔</text><path class="arrow dash" d="M677 316H768"/><rect class="actual-box" x="768" y="286" width="250" height="60" rx="9"/><text class="actual-text" x="810" y="322">G2 候选未开始</text><text class="small" x="812" y="341">实际:没有候选</text>
|
||||
<text class="expected-text" x="58" y="388">正确</text><rect class="info-box" x="135" y="365" width="205" height="45" rx="9"/><text class="label" x="180" y="394">Hybrid A* Success</text><path class="arrow" d="M340 388H432"/><rect class="expected-box" x="432" y="365" width="245" height="45" rx="9"/><text class="expected-text" x="469" y="394">原始基线复验 Success</text><path class="arrow" d="M677 388H768"/><rect class="expected-box" x="768" y="365" width="250" height="45" rx="9"/><text class="expected-text" x="822" y="394">G2 候选评价</text>
|
||||
<rect x="25" y="448" width="1150" height="54" rx="12" fill="#edf4f7"/><text class="note-text" x="52" y="481">固定边界:上方为概念性几何,不代表尚未定位的实际坏样本;不能据此臆测碰撞、曲率违例或根因。</text>
|
||||
</g>
|
||||
<g class="issue-scene" data-issue="window">
|
||||
<rect class="lane" x="25" y="22" width="1150" height="160" rx="16"/><text class="lane-label" x="52" y="55">同一条典型路径上的事件与弧长标尺</text><path class="path-old" d="M110 112H1085"/><line class="measure" x1="420" y1="85" x2="620" y2="85"/><path class="arrow" d="M420 85h-1"/><path class="arrow" d="M620 85h-1"/><text class="label" x="486" y="76">中心距离 1.0 m</text><circle cx="420" cy="112" r="11" fill="#b8323d"/><circle cx="620" cy="112" r="11" fill="#b8323d"/><text class="actual-text" x="409" y="143">事件 A</text><text class="actual-text" x="609" y="143">事件 B</text><text class="small" x="110" y="167">弧长标尺 →</text>
|
||||
<rect class="lane" x="25" y="204" width="555" height="300" rx="16"/><text class="lane-label" x="52" y="238">实际:影响范围合并</text><path class="path-old" d="M82 330H525"/><rect x="145" y="294" width="245" height="72" rx="9" fill="#ffe1ae" stroke="#9a6312" stroke-width="2"/><rect x="275" y="294" width="245" height="72" rx="9" fill="#ffe1ae" fill-opacity=".75" stroke="#9a6312" stroke-width="2"/><text class="label" x="196" y="283">A ±0.8 m</text><text class="label" x="397" y="283">B ±0.8 m</text><path class="arrow" d="M300 374V415"/><rect class="actual-box" x="104" y="420" width="406" height="57" rx="9"/><text class="actual-text" x="160" y="446">合并总区间 > 0.8 m</text><text class="actual-text" x="194" y="467">✕ 无候选</text>
|
||||
<rect class="lane" x="600" y="204" width="575" height="300" rx="16"/><text class="lane-label" x="627" y="238">正确:一致语义或拆分</text><path class="path-old" d="M650 330H1120"/><rect class="expected-box" x="705" y="294" width="150" height="72" rx="9"/><rect class="expected-box" x="920" y="294" width="150" height="72" rx="9"/><text class="expected-text" x="728" y="283">窗口 A</text><text class="expected-text" x="943" y="283">窗口 B</text><path class="arrow" d="M785 374V415"/><path class="arrow" d="M995 374V415"/><rect class="expected-box" x="705" y="420" width="365" height="57" rx="9"/><text class="expected-text" x="786" y="446">✓ 可评价候选</text><text class="small" x="742" y="467">拆分窗口或一致长度策略</text>
|
||||
<rect x="25" y="526" width="1150" height="54" rx="12" fill="#fff4dc"/><text class="note-text" x="52" y="559">静态分析确认的逻辑缺口:范围合并规则与候选总长度约束没有共同的可行性判断。</text>
|
||||
</g>
|
||||
<g class="issue-scene" data-issue="arclength">
|
||||
<rect class="lane" x="25" y="22" width="1150" height="180" rx="16"/><text class="lane-label" x="52" y="54">替换前:A、B 在原始弧长标尺上的局部窗口</text><path class="path-old" d="M105 126H1090"/><rect class="info-box" x="300" y="92" width="130" height="68" rx="9"/><rect class="info-box" x="760" y="92" width="130" height="68" rx="9"/><text class="label" x="350" y="120">窗口 A</text><text class="label" x="810" y="120">窗口 B</text><text class="small" x="316" y="145">原始 sA</text><text class="small" x="776" y="145">原始 sB</text><text class="small" x="105" y="183">原始弧长标尺 →</text>
|
||||
<rect class="lane" x="25" y="224" width="555" height="350" rx="16"/><text class="lane-label" x="52" y="258">实际风险:B-old 仍按旧弧长</text><path class="path-actual" d="M88 342H195Q230 342 251 304L276 265Q292 238 325 238H410Q446 238 469 275L493 315Q508 342 545 342"/><text class="actual-text" x="73" y="299">A 替换后长度改变</text><line class="measure" x1="80" y1="390" x2="545" y2="390"/><text class="small" x="80" y="416">当前路径弧长标尺</text><path class="arrow dash" d="M810 164C760 250 614 418 320 445"/><rect class="actual-box" x="230" y="438" width="168" height="72" rx="9"/><text class="actual-text" x="264" y="466">B-old 偏早</text><text class="small" x="249" y="489">虚线:旧映射</text><text class="actual-text" x="422" y="470">实际风险</text>
|
||||
<rect class="lane" x="600" y="224" width="575" height="350" rx="16"/><text class="lane-label" x="627" y="258">正确:弧长重算 / 稳定锚点重定位</text><path class="path-expected" d="M660 342H760Q792 342 815 302L841 258Q856 234 887 234H970Q1002 234 1023 273L1050 316Q1065 342 1120 342"/><text class="expected-text" x="650" y="299">A 替换后重算当前弧长</text><line class="measure" x1="650" y1="390" x2="1120" y2="390"/><text class="small" x="650" y="416">当前路径弧长标尺</text><path class="arrow" d="M810 164C850 250 915 370 985 440"/><rect class="expected-box" x="900" y="438" width="170" height="72" rx="9"/><text class="expected-text" x="928" y="466">B-new 重定位</text><text class="small" x="925" y="489">实线:新映射</text><text class="expected-text" x="1081" y="470">正确</text>
|
||||
<rect x="25" y="596" width="1150" height="54" rx="12" fill="#edf6fc"/><text class="note-text" x="52" y="629">固定边界:待正式多区域流水线接入后,通过“区域 A 改变长度、区域 B 仍准确定位”的回归测试验证。</text>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="compare-copy">
|
||||
<article><h3>实际发生</h3><p id="issue-actual">Hybrid A* 粗路径规划成功,但原始基线统一复验返回 InvalidInput;候选生成没有开始。</p></article>
|
||||
<article><h3>正确应有</h3><p id="issue-expected">同一条成功规划的粗路径应先作为可行基线通过统一复验,再进入候选评价。</p></article>
|
||||
<article><h3>差异原因</h3><p id="issue-cause">首次非法数值或超限曲率样本尚未定位;不能把该失败归因于 G2 候选。</p></article>
|
||||
</div>
|
||||
<p class="next-action"><strong>下一步:</strong><span id="issue-action">记录首次异常的方向段、样本、曲率、净空和验证结果,在不放松安全门的前提下定位源头。</span></p>
|
||||
</section>
|
||||
<div class="issue-controls"><button id="prev-issue" type="button">上一个问题</button><button id="next-issue" type="button">下一个问题</button></div>
|
||||
|
||||
<section aria-labelledby="priority-title"><h2 id="priority-title" style="margin-top:28px">紧凑行动顺序</h2><div class="priority" role="table" aria-label="问题处置优先级"><div class="p0" role="cell">P0</div><div role="cell"><strong>定位 RectangleDetour 基线失败。</strong>记录首次异常样本,保持安全门。</div><div class="p1" role="cell">P1</div><div role="cell"><strong>补 1.0 m 间距窗口回归。</strong>统一 ±0.8 m 与候选总长度的语义。</div><div class="p1" role="cell">P1</div><div role="cell"><strong>补双区域替换回归。</strong>确认弧长重算后区域 B 仍正确定位。</div><div class="p2" role="cell">P2</div><div role="cell"><strong>再接入正式多区域流水线。</strong>完成端到端验证。</div></div></section>
|
||||
<footer>对应主报告:02-local-g2-issues-and-next-actions-report.md · 单文件离线 HTML,不依赖外部资源。</footer>
|
||||
</main>
|
||||
<script>
|
||||
'use strict';
|
||||
const issues = Object.freeze({
|
||||
baseline: Object.freeze({ evidence: '已复现故障 · RectangleDetour', title: '原始基线在 Local G2 开始前被拒绝', actual: 'Hybrid A* 粗路径规划成功,但原始基线统一复验返回 InvalidInput;候选生成没有开始。', expected: '同一条成功规划的粗路径应先作为可行基线通过统一复验,再进入候选评价。', cause: '首次非法数值或超限曲率样本尚未定位;不能把该失败归因于 G2 候选。', action: '记录首次异常的方向段、样本、曲率、净空和验证结果,在不放松安全门的前提下定位源头。' }),
|
||||
window: Object.freeze({ evidence: '静态分析确认的逻辑缺口', title: '合并范围比可用候选窗口更宽', actual: '相距 1.0 m 的事件被 ±0.8 m 范围合并,但候选总长度不能超过 0.8 m,结果没有候选。', expected: '窗口合并和最大总长度应采用一致语义,或在不满足时拆分为可行局部窗口。', cause: '影响范围的合并规则与候选总长度约束没有共同的可行性判断。', action: '加入 1.0 m 间距回归,统一窗口长度语义并验证候选仍可生成。' }),
|
||||
arclength: Object.freeze({ evidence: '待验证集成风险', title: '区域 A 替换后,区域 B 的弧长坐标可能陈旧', actual: 'A 拼接并重算弧长后,B 若仍使用替换前坐标,可能指向错误局部。', expected: '处理 B 前应按当前路径重定位,或由稳定锚点映射恢复其原始语义位置。', cause: '候选记录的原始弧长与每次拼接后重新计算的当前弧长处于不同坐标系。', action: '构造 A 改变长度、B 仍准确定位的双区域回归,再接入正式流水线。' })
|
||||
});
|
||||
const issueIds = ['baseline', 'window', 'arclength'];
|
||||
const issueButtons = Array.from(document.querySelectorAll('.issue-button'));
|
||||
function selectIssue(issueId) {
|
||||
const issue = issues[issueId];
|
||||
if (!issue) return;
|
||||
document.getElementById('local-g2-issue-demo').dataset.issue = issueId;
|
||||
document.getElementById('issue-evidence').textContent = issue.evidence;
|
||||
document.getElementById('issue-title').textContent = issue.title;
|
||||
document.getElementById('issue-actual').textContent = issue.actual;
|
||||
document.getElementById('issue-expected').textContent = issue.expected;
|
||||
document.getElementById('issue-cause').textContent = issue.cause;
|
||||
document.getElementById('issue-action').textContent = issue.action;
|
||||
issueButtons.forEach((button) => button.setAttribute('aria-pressed', String(button.dataset.issue === issueId)));
|
||||
}
|
||||
function moveIssue(offset) { const current = document.getElementById('local-g2-issue-demo').dataset.issue; const index = issueIds.indexOf(current); selectIssue(issueIds[(index + offset + issueIds.length) % issueIds.length]); }
|
||||
issueButtons.forEach((button) => button.addEventListener('click', () => selectIssue(button.dataset.issue)));
|
||||
document.getElementById('prev-issue').addEventListener('click', () => moveIssue(-1));
|
||||
document.getElementById('next-issue').addEventListener('click', () => moveIssue(1));
|
||||
selectIssue('baseline');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
# Local G2 最小曲率越界可行性验证报告
|
||||
|
||||
> 文档定位:记录 Local G2 最小曲率越界(curvature excursion)受控探测的结论、改动边界和后续动作,供路径平滑模块的日常协作查阅。
|
||||
>
|
||||
> 证据边界:本报告只摘要正式证据报告中的固定 SingleTurn 场景结果。它不是生产发布说明,也不把一次性 probe 中的测量改动描述为共享生产代码改动。
|
||||
|
||||
对应可视化附录:[03-local-g2-curvature-excursion-feasibility-visualization.html](03-local-g2-curvature-excursion-feasibility-visualization.html)。
|
||||
|
||||
## 1. 结论摘要
|
||||
|
||||
本轮最小曲率越界可行性探测的最终状态是 **QUALITY_RED**。它给出的授权结论很明确:**不修改生产 evaluator(候选评估器)**。
|
||||
|
||||
这不是因为运行超时,也不是因为证据无效。候选搜索、性能和重复运行均完成了预定验证;问题在于,没有候选同时满足严格接纳条件,因此没有可发布的替换路径。
|
||||
|
||||
| 项目 | 本轮结果 | 正确解读 |
|
||||
| --- | --- | --- |
|
||||
| 严格合格候选 | 0 | 原始严格范围条件下没有可接纳候选。 |
|
||||
| 物理约束合格候选 | 3 | 仅说明它们满足该层物理约束,不能等同于最终接受。 |
|
||||
| 曲率越界合格候选 | 0 | 没有可报告的最小可行越界值。 |
|
||||
| 管线输出 | Unchanged | 原路径没有被替换。 |
|
||||
| 性能超限 | False | 本轮未因性能失败。 |
|
||||
| 证据有效性 | valid | 本轮结论可复核,但结论是不能修改 evaluator。 |
|
||||
|
||||
## 2. 本轮做了什么
|
||||
|
||||
本轮不是在共享生产源码中直接“放宽曲率”,而是在一次性、可丢弃的 probe core 中回答一个更小的问题:
|
||||
|
||||
> 在不改变严格生产接纳语义的前提下,是否存在一个能消除局部曲率突变、并以最小必要越界满足全部质量门的候选?
|
||||
|
||||
验证分为两条互相隔离的路径:
|
||||
|
||||
1. **Strict 路径**:保持共享 evaluator 的原始严格语义,判定候选能否被正式接纳。
|
||||
2. **Measurement 路径**:仅为了记录被严格 raw 曲率范围提前阻断后的后续质量门状态,允许诊断继续走到后面的检查点。它不是生产实现,也不改变 Strict 路径的结论。
|
||||
|
||||
这样可以把“候选的几何和车辆物理约束是否可行”与“候选是否允许进入正式输出”分开观察,避免为了得到绿色结果而直接放宽生产门槛。
|
||||
|
||||
## 3. 本轮修改范围
|
||||
|
||||
| 范围 | 改动内容 | 边界与结果 |
|
||||
| --- | --- | --- |
|
||||
| 一次性 probe core | 增加受控搜索、候选账本、严格审计和证据生成能力。 | 只用于本轮验证,不回写共享生产源码。 |
|
||||
| Measurement root | 仅改动 LocalG2CandidateEvaluator.cs 中 raw 范围提前返回后的测量延续与 trace 捕获。 | 用于定位后续质量门;不是生产 evaluator 改动。 |
|
||||
| 严格 root | 保持 evaluator 与共享基线一致。 | 严格结论仍是 0 个可接纳候选。 |
|
||||
| 共享分支 | 发布正式证据报告。 | 没有提交 probe 源码,也没有修改生产 evaluator。 |
|
||||
| 本日报目录 | 新增本 Markdown 摘要和对应离线 HTML 可视化。 | 仅整理结论与证据入口,不改变路径平滑行为。 |
|
||||
|
||||
相关身份如下:
|
||||
|
||||
| 身份 | 提交 |
|
||||
| --- | --- |
|
||||
| 共享基线 | da9157b17a7e4206ed4cdebd1985ee2577fae480 |
|
||||
| 冻结 core / Strict | 3006aa0fd8dac8e4665ff3b89b7cda139e88e940 |
|
||||
| Measurement | c92c9c5b8e1995f61d4685f9a6ee23a6f8d5f825 |
|
||||
| 共享分支正式证据报告 | 67f86581a06f754ae166c6145478f454afefbf17 |
|
||||
|
||||
## 4. 候选搜索结果
|
||||
|
||||
固定 SingleTurn 场景中的搜索预算和结果如下:
|
||||
|
||||
| 指标 | 结果 |
|
||||
| --- | ---: |
|
||||
| 规划窗口数 | 8 |
|
||||
| 已尝试组合数 | 24 |
|
||||
| solver 调用数 | 30 |
|
||||
| 已生成候选数 | 6 |
|
||||
| 失败组合数 | 18 |
|
||||
| 最大 interval 数 | 2 |
|
||||
| 搜索停止原因 | None |
|
||||
| 严格合格 / 物理约束合格 / 越界合格 | 0 / 3 / 0 |
|
||||
|
||||
因此,本轮不是“没有生成任何曲线”。相反,系统生成了 6 个候选,其中 3 个通过了车辆物理约束层;但没有一个通过严格接纳层,也没有一个成为可报告的最小曲率越界方案。
|
||||
|
||||
## 5. 为什么最终没有路径变得更平滑
|
||||
|
||||
结论不能简化为“候选曲率一定比原路径更大”。更准确的过程是:
|
||||
|
||||
1. 候选生成器确实构造了局部替换曲线。
|
||||
2. Strict 路径先检查 raw 曲率范围。候选没有满足这一严格范围条件,因此严格合格数为 0。
|
||||
3. Measurement 路径只为观察决策链而继续记录后续门。3 个物理约束合格候选仍在净空门被阻断,未进入最终质量评价和接受流程。
|
||||
4. 没有候选被选中,预平滑管线保持 Unchanged,原路径不替换。
|
||||
|
||||
这里有两个不同层次的概念:
|
||||
|
||||
| 层次 | 回答的问题 | 本轮状态 |
|
||||
| --- | --- | --- |
|
||||
| 车辆物理约束 | 车辆最大曲率、接缝、偏移等基础几何约束是否可行? | 有 3 个候选通过。 |
|
||||
| 严格接纳与质量门 | 候选是否能在现有生产语义下安全、完整地替换原路径? | 没有候选通过。 |
|
||||
|
||||
所以“物理约束合格”不是“平滑方案已经有效”。当前实际效果是:**候选层被执行并留下可复核证据,但没有改变输出路径。**
|
||||
|
||||
## 6. 性能与确定性
|
||||
|
||||
性能验证先进行 5 次预热,再进行 30 次测量运行。30 次测量只得到 1 个确定性签名,说明在该固定场景与固定环境下结果没有随机漂移。
|
||||
|
||||
| 指标 | 中位数 | 最坏值 | 限制 | 结果 |
|
||||
| --- | ---: | ---: | ---: | --- |
|
||||
| Solver 时间 | 4.93545 ms | 7.7368 ms | 10 / 25 ms | 通过 |
|
||||
| Region 时间 | 10.09185 ms | 23.2227 ms | 25 / 50 ms | 通过 |
|
||||
|
||||
性能通过只说明这次受控探测没有超过时间预算;它不能覆盖严格接纳失败,也不能把 QUALITY_RED 转为可发布状态。
|
||||
|
||||
## 7. 这份结果说明什么,不说明什么
|
||||
|
||||
| 可以说明 | 不能说明 |
|
||||
| --- | --- |
|
||||
| 当前固定 SingleTurn 场景中,严格语义下不存在可接纳的最小曲率越界候选。 | 所有地图、所有转弯或全部 Local G2 场景都不可行。 |
|
||||
| 结果不是因超时或随机性造成。 | 只要放宽 evaluator 就应当发布。 |
|
||||
| Measurement 路径有助于定位 raw 范围之后的净空阻断。 | Measurement 改动已经进入生产 evaluator。 |
|
||||
| 当前授权边界是“不修改 evaluator”。 | 前两份报告中的基线、窗口语义和多区域弧长风险已经解决。 |
|
||||
|
||||
特别需要保留的边界是:前两份日报中记录的 RectangleDetour 基线复验、窗口合并语义和多区域弧长定位问题,不会因为本次单场景 probe 结束而自动关闭。
|
||||
|
||||
## 8. 后续动作
|
||||
|
||||
1. 保持 QUALITY_RED 的授权边界:不把 Measurement 改动复制到生产 evaluator。
|
||||
2. 不以“变绿”为目的放宽 raw 曲率范围、净空或其他质量门。
|
||||
3. 继续按已有优先级处理基线复验、窗口长度语义和多区域弧长定位风险。
|
||||
4. 若要评估新的几何策略或新的场景范围,应另起独立计划,重新定义候选、质量门和验收证据,而不是从本次结果直接推导发布结论。
|
||||
|
||||
## 9. 证据索引
|
||||
|
||||
| 证据 | 用途 |
|
||||
| --- | --- |
|
||||
| docs/superpowers/reports/2026-08-01-local-g2-minimum-curvature-excursion-feasibility-report.md | 本日报所有数值和最终授权边界的正式来源。 |
|
||||
| 3006aa0fd8dac8e4665ff3b89b7cda139e88e940 | 冻结 core 与 Strict 验证身份。 |
|
||||
| c92c9c5b8e1995f61d4685f9a6ee23a6f8d5f825 | Measurement 专用、可丢弃的 evaluator trace 身份。 |
|
||||
| 67f86581a06f754ae166c6145478f454afefbf17 | 共享分支上发布正式证据报告的提交。 |
|
||||
| 03-local-g2-curvature-excursion-feasibility-visualization.html | 本报告的离线交互式可视化附录。 |
|
||||
-616
@@ -1,616 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Local G2 最小曲率越界可行性验证|结果可视化</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light;
|
||||
--ink: #172a36;
|
||||
--muted: #62727b;
|
||||
--paper: #f4f7f6;
|
||||
--panel: #ffffff;
|
||||
--line: #c8d4d5;
|
||||
--teal: #126d70;
|
||||
--teal-pale: #e0f1ef;
|
||||
--green: #257a4d;
|
||||
--green-pale: #e7f4eb;
|
||||
--amber: #9b5f13;
|
||||
--amber-pale: #fff1dc;
|
||||
--red: #b1373e;
|
||||
--red-pale: #fbe9ea;
|
||||
--slate: #596b75;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--paper);
|
||||
color: var(--ink);
|
||||
font: 16px/1.6 system-ui, -apple-system, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
main {
|
||||
width: min(1120px, 100%);
|
||||
margin: 0 auto;
|
||||
padding: 32px 24px 48px;
|
||||
}
|
||||
|
||||
header {
|
||||
border-bottom: 2px solid var(--ink);
|
||||
padding-bottom: 22px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 6px;
|
||||
color: var(--teal);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
h1, h2, h3, p { margin-top: 0; }
|
||||
|
||||
h1 {
|
||||
margin-bottom: 10px;
|
||||
font-size: 2.25rem;
|
||||
line-height: 1.18;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 12px;
|
||||
font-size: 1.45rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 6px;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
max-width: 780px;
|
||||
margin-bottom: 16px;
|
||||
color: var(--muted);
|
||||
font-size: 1.03rem;
|
||||
}
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
border: 1px solid currentColor;
|
||||
border-radius: 6px;
|
||||
padding: 4px 9px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.badge.red { color: var(--red); background: var(--red-pale); }
|
||||
.badge.green { color: var(--green); background: var(--green-pale); }
|
||||
.badge.teal { color: var(--teal); background: var(--teal-pale); }
|
||||
|
||||
.report-nav {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
margin: 24px 0 0;
|
||||
}
|
||||
|
||||
button {
|
||||
min-height: 44px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 9px 12px;
|
||||
color: var(--ink);
|
||||
background: var(--panel);
|
||||
font: inherit;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover { border-color: var(--teal); }
|
||||
button:focus-visible { outline: 3px solid #f0b535; outline-offset: 2px; }
|
||||
button[aria-pressed="true"] { border-color: var(--teal); color: #ffffff; background: var(--teal); }
|
||||
|
||||
.visual-band {
|
||||
margin-top: 16px;
|
||||
border-top: 1px solid var(--line);
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
.view-copy {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 20px;
|
||||
align-items: end;
|
||||
padding: 22px 22px 12px;
|
||||
}
|
||||
|
||||
.view-copy p {
|
||||
margin-bottom: 0;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.view-state {
|
||||
margin: 0;
|
||||
color: var(--teal);
|
||||
font-weight: 800;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.visual-stage { padding: 0 22px 24px; }
|
||||
|
||||
.visual-view { display: none; }
|
||||
[data-view="funnel"] .visual-view[data-view="funnel"],
|
||||
[data-view="gates"] .visual-view[data-view="gates"],
|
||||
[data-view="performance"] .visual-view[data-view="performance"] { display: block; }
|
||||
|
||||
.funnel {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
align-items: stretch;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.funnel li {
|
||||
position: relative;
|
||||
min-height: 142px;
|
||||
border: 1px solid var(--line);
|
||||
border-top: 5px solid var(--slate);
|
||||
border-radius: 6px;
|
||||
padding: 16px 12px;
|
||||
background: #fbfcfc;
|
||||
}
|
||||
|
||||
.funnel li:not(:last-child)::after {
|
||||
position: absolute;
|
||||
top: 58px;
|
||||
right: -9px;
|
||||
z-index: 1;
|
||||
width: 17px;
|
||||
color: var(--muted);
|
||||
background: var(--panel);
|
||||
content: "→";
|
||||
font-size: 1.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.funnel li.physical { border-top-color: var(--green); }
|
||||
.funnel li.blocked { border-top-color: var(--red); }
|
||||
.funnel li.final { border-top-color: var(--slate); }
|
||||
|
||||
.metric {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
color: var(--ink);
|
||||
font-size: 2.25rem;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.funnel strong, .funnel small { display: block; }
|
||||
.funnel small { margin-top: 4px; color: var(--muted); }
|
||||
|
||||
.gate-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.gate {
|
||||
min-height: 154px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
background: #fbfcfc;
|
||||
}
|
||||
|
||||
.gate .step {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: var(--muted);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.gate p { margin-bottom: 0; color: var(--muted); }
|
||||
.gate.accepted { border-top: 5px solid var(--green); }
|
||||
.gate.blocked { border-top: 5px solid var(--red); }
|
||||
.gate.measurement { border-top: 5px solid var(--amber); }
|
||||
.gate.output { border-top: 5px solid var(--slate); }
|
||||
|
||||
.gate-result {
|
||||
display: inline-block;
|
||||
margin-top: 12px;
|
||||
border-radius: 5px;
|
||||
padding: 3px 7px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.gate-result.green { color: var(--green); background: var(--green-pale); }
|
||||
.gate-result.red { color: var(--red); background: var(--red-pale); }
|
||||
.gate-result.amber { color: var(--amber); background: var(--amber-pale); }
|
||||
.gate-result.slate { color: var(--slate); background: #e9eef0; }
|
||||
|
||||
.measurement-note {
|
||||
margin: 14px 0 0;
|
||||
border-left: 4px solid var(--amber);
|
||||
padding: 10px 12px;
|
||||
color: #6e4915;
|
||||
background: var(--amber-pale);
|
||||
}
|
||||
|
||||
.performance-layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 250px;
|
||||
gap: 28px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.timing-list {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.timing-row {
|
||||
display: grid;
|
||||
grid-template-columns: 132px minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.timing-label { font-weight: 800; }
|
||||
|
||||
.timing-bar {
|
||||
display: grid;
|
||||
grid-template-columns: var(--median) var(--worst) 1fr;
|
||||
min-height: 40px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 5px;
|
||||
background: #f6f8f8;
|
||||
}
|
||||
|
||||
.timing-bar span {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-width: 0;
|
||||
padding: 3px;
|
||||
color: #ffffff;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.timing-bar .median { background: var(--teal); }
|
||||
.timing-bar .worst { background: var(--green); }
|
||||
.timing-bar .remaining { color: var(--muted); background: #edf2f1; }
|
||||
|
||||
.determinism {
|
||||
display: grid;
|
||||
align-content: center;
|
||||
border-left: 1px solid var(--line);
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
.determinism strong {
|
||||
display: block;
|
||||
color: var(--teal);
|
||||
font-size: 2.85rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.determinism p { margin: 8px 0 0; color: var(--muted); }
|
||||
|
||||
.section {
|
||||
padding: 30px 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.section-intro {
|
||||
max-width: 780px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.facts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.fact {
|
||||
border-left: 4px solid var(--teal);
|
||||
padding: 4px 0 4px 14px;
|
||||
}
|
||||
|
||||
.fact:nth-child(2) { border-left-color: var(--red); }
|
||||
.fact:nth-child(3) { border-left-color: var(--amber); }
|
||||
.fact p { margin-bottom: 0; color: var(--muted); }
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
th, td {
|
||||
border-bottom: 1px solid var(--line);
|
||||
padding: 11px 12px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th { color: var(--muted); font-size: 0.9rem; }
|
||||
tr:last-child td { border-bottom: 0; }
|
||||
|
||||
.actions {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
counter-reset: action;
|
||||
}
|
||||
|
||||
.actions li {
|
||||
counter-increment: action;
|
||||
position: relative;
|
||||
padding-left: 42px;
|
||||
}
|
||||
|
||||
.actions li::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 50%;
|
||||
color: var(--teal);
|
||||
background: var(--panel);
|
||||
content: counter(action);
|
||||
font-weight: 800;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding-top: 24px;
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
main { padding: 24px 14px 38px; }
|
||||
h1 { font-size: 1.85rem; }
|
||||
.report-nav, .facts { grid-template-columns: 1fr; }
|
||||
.view-copy, .performance-layout { grid-template-columns: 1fr; }
|
||||
.view-state { text-align: left; }
|
||||
.funnel, .gate-grid { grid-template-columns: 1fr; }
|
||||
.funnel li:not(:last-child)::after {
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: -16px;
|
||||
left: calc(50% - 9px);
|
||||
content: "↓";
|
||||
}
|
||||
.determinism {
|
||||
border-top: 1px solid var(--line);
|
||||
border-left: 0;
|
||||
padding-top: 20px;
|
||||
padding-left: 0;
|
||||
}
|
||||
.timing-row { grid-template-columns: 1fr; gap: 5px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main id="excursion-report" data-view="funnel">
|
||||
<header>
|
||||
<p class="eyebrow">离线结果可视化 · Local G2</p>
|
||||
<h1>最小曲率越界探测:没有新的可采纳路径</h1>
|
||||
<p class="subtitle">固定 SingleTurn 场景中,候选搜索、性能和确定性验证均已完成;但严格接纳条件下没有候选通过,预平滑管线保持原样。</p>
|
||||
<div class="badges" aria-label="结论状态">
|
||||
<span class="badge red">QUALITY_RED</span>
|
||||
<span class="badge green">性能通过</span>
|
||||
<span class="badge teal">生产 evaluator 不变</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="report-nav" aria-label="选择结果视图">
|
||||
<button type="button" class="view-button" data-view="funnel" aria-pressed="true">候选结果漏斗</button>
|
||||
<button type="button" class="view-button" data-view="gates" aria-pressed="false">质量门阻断链路</button>
|
||||
<button type="button" class="view-button" data-view="performance" aria-pressed="false">性能与确定性</button>
|
||||
</nav>
|
||||
|
||||
<section class="visual-band" aria-live="polite">
|
||||
<div class="view-copy">
|
||||
<div>
|
||||
<h2 id="view-title">候选已经生成,但没有进入最终输出</h2>
|
||||
<p id="view-description">6 个候选中有 3 个达到车辆物理约束层;严格 raw 曲率范围合格数仍为 0,因此不能把任何候选当作可发布的平滑路径。</p>
|
||||
</div>
|
||||
<p id="view-state" class="view-state">结果:Unchanged</p>
|
||||
</div>
|
||||
|
||||
<div class="visual-stage">
|
||||
<div class="visual-view" data-view="funnel">
|
||||
<ol class="funnel" aria-label="候选审核结果漏斗">
|
||||
<li><span class="metric">6</span><strong>已生成候选</strong><small>30 次 solver 调用</small></li>
|
||||
<li class="physical"><span class="metric">3</span><strong>物理约束合格</strong><small>基础几何层</small></li>
|
||||
<li class="blocked"><span class="metric">0</span><strong>严格范围合格</strong><small>raw 曲率范围</small></li>
|
||||
<li class="blocked"><span class="metric">0</span><strong>越界合格</strong><small>无最小值可报告</small></li>
|
||||
<li class="final"><span class="metric">0</span><strong>替换输出</strong><small>管线 Unchanged</small></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="visual-view" data-view="gates">
|
||||
<div class="gate-grid" aria-label="严格与测量路径的质量门状态">
|
||||
<article class="gate accepted">
|
||||
<span class="step">步骤 1</span>
|
||||
<h3>候选生成</h3>
|
||||
<p>局部替换曲线被构造并进入审核。</p>
|
||||
<span class="gate-result green">6 个候选</span>
|
||||
</article>
|
||||
<article class="gate blocked">
|
||||
<span class="step">步骤 2</span>
|
||||
<h3>Strict raw 曲率范围</h3>
|
||||
<p>严格路径首先判定候选是否保持原有接纳语义。</p>
|
||||
<span class="gate-result red">0 个严格合格</span>
|
||||
</article>
|
||||
<article class="gate measurement">
|
||||
<span class="step">步骤 3</span>
|
||||
<h3>Measurement trace</h3>
|
||||
<p>只为取证而继续记录后续质量门,不改变 Strict 结论。</p>
|
||||
<span class="gate-result amber">一次性测量路径</span>
|
||||
</article>
|
||||
<article class="gate output">
|
||||
<span class="step">步骤 4</span>
|
||||
<h3>净空与最终输出</h3>
|
||||
<p>3 个物理约束合格候选在净空门阻断,未被接受。</p>
|
||||
<span class="gate-result slate">原路径保持</span>
|
||||
</article>
|
||||
</div>
|
||||
<p class="measurement-note">Measurement 的作用是把阻断位置记录完整,不是放宽生产质量门。它不能授权修改 evaluator,也不能让候选进入正式输出。</p>
|
||||
</div>
|
||||
|
||||
<div class="visual-view" data-view="performance">
|
||||
<div class="performance-layout">
|
||||
<div class="timing-list" aria-label="性能汇总,单位为毫秒">
|
||||
<div class="timing-row">
|
||||
<span class="timing-label">Solver 中位 / 限制</span>
|
||||
<div class="timing-bar" style="--median: 49%; --worst: 0%;">
|
||||
<span class="median">4.94 ms</span>
|
||||
<span class="worst"></span>
|
||||
<span class="remaining">限制 10 ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timing-row">
|
||||
<span class="timing-label">Solver 最坏 / 限制</span>
|
||||
<div class="timing-bar" style="--median: 31%; --worst: 0%;">
|
||||
<span class="median">7.74 ms</span>
|
||||
<span class="worst"></span>
|
||||
<span class="remaining">限制 25 ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timing-row">
|
||||
<span class="timing-label">Region 中位 / 限制</span>
|
||||
<div class="timing-bar" style="--median: 40%; --worst: 0%;">
|
||||
<span class="median">10.09 ms</span>
|
||||
<span class="worst"></span>
|
||||
<span class="remaining">限制 25 ms</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timing-row">
|
||||
<span class="timing-label">Region 最坏 / 限制</span>
|
||||
<div class="timing-bar" style="--median: 46%; --worst: 0%;">
|
||||
<span class="median">23.22 ms</span>
|
||||
<span class="worst"></span>
|
||||
<span class="remaining">限制 50 ms</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="determinism">
|
||||
<strong>1</strong>
|
||||
<p>个确定性签名<br>5 次预热 + 30 次测量<br>性能超限:False</p>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2>如何理解“平滑方案效果”</h2>
|
||||
<p class="section-intro">本次结果不是“完全没有曲线”,也不能直接写成“所有候选曲率都比原路径更大”。真正的结论是,候选在不同质量层的状态不同,且没有一个最终满足现有严格接纳条件。</p>
|
||||
<div class="facts">
|
||||
<article class="fact">
|
||||
<h3>候选层确实执行</h3>
|
||||
<p>系统生成了 6 个局部候选,并对它们完成了有界搜索和账本审计。</p>
|
||||
</article>
|
||||
<article class="fact">
|
||||
<h3>严格接纳没有通过</h3>
|
||||
<p>raw 曲率范围严格合格数为 0,因此不能把任何候选写成可发布的路径平滑结果。</p>
|
||||
</article>
|
||||
<article class="fact">
|
||||
<h3>输出没有变化</h3>
|
||||
<p>Measurement 继续记录后,候选仍被净空门阻断;管线最终保持 Unchanged。</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2>本轮修改边界</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>范围</th><th>改动</th><th>结论</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>一次性 probe core</td><td>候选搜索、账本、严格审计与证据生成。</td><td>只用于验证,不回写生产源码。</td></tr>
|
||||
<tr><td>Measurement root</td><td>LocalG2CandidateEvaluator.cs 的测量延续与 trace 捕获。</td><td>只用于取证,不是生产 evaluator 变更。</td></tr>
|
||||
<tr><td>共享分支</td><td>发布正式证据报告。</td><td>没有提交 probe 源码,也没有修改 evaluator。</td></tr>
|
||||
<tr><td>本日报目录</td><td>新增本页及对应 Markdown 摘要。</td><td>仅整理事实与证据入口,不改变路径平滑行为。</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2>后续边界</h2>
|
||||
<ol class="actions">
|
||||
<li>保持 QUALITY_RED 对应的授权结论:不把 Measurement 改动复制到生产 evaluator。</li>
|
||||
<li>不为了得到绿色结果而放宽 raw 曲率范围、净空或其他质量门。</li>
|
||||
<li>继续按已有优先级处理基线复验、窗口长度语义与多区域弧长定位风险。</li>
|
||||
<li>新的几何策略或场景范围需要独立计划和新的验收证据,不能从本次 SingleTurn 结果直接推导发布结论。</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
对应主报告:03-local-g2-curvature-excursion-feasibility-report.md。数据来源:docs/superpowers/reports/2026-08-01-local-g2-minimum-curvature-excursion-feasibility-report.md。单文件离线 HTML,无外部资源依赖。
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const views = Object.freeze({
|
||||
funnel: Object.freeze({
|
||||
title: '候选已经生成,但没有进入最终输出',
|
||||
description: '6 个候选中有 3 个达到车辆物理约束层;严格 raw 曲率范围合格数仍为 0,因此不能把任何候选当作可发布的平滑路径。',
|
||||
state: '结果:Unchanged'
|
||||
}),
|
||||
gates: Object.freeze({
|
||||
title: '严格路径阻断,测量路径只补全证据',
|
||||
description: 'Strict 保持共享 evaluator 语义并在 raw 曲率范围处拒绝候选。Measurement 仅为追踪后续质量门,不能改变严格结论或生产代码。',
|
||||
state: '授权:不修改 evaluator'
|
||||
}),
|
||||
performance: Object.freeze({
|
||||
title: '时间预算与结果确定性均通过',
|
||||
description: '5 次预热和 30 次测量均在既定性能阈值内完成,且只产生 1 个确定性签名;这些结果不覆盖严格接纳失败。',
|
||||
state: '性能超限:False'
|
||||
})
|
||||
});
|
||||
|
||||
const buttons = Array.from(document.querySelectorAll('.view-button'));
|
||||
|
||||
function selectView(viewId) {
|
||||
const view = views[viewId];
|
||||
if (!view) return;
|
||||
const root = document.getElementById('excursion-report');
|
||||
root.dataset.view = viewId;
|
||||
document.getElementById('view-title').textContent = view.title;
|
||||
document.getElementById('view-description').textContent = view.description;
|
||||
document.getElementById('view-state').textContent = view.state;
|
||||
buttons.forEach((button) => button.setAttribute('aria-pressed', String(button.dataset.view === viewId)));
|
||||
}
|
||||
|
||||
buttons.forEach((button) => button.addEventListener('click', () => selectView(button.dataset.view)));
|
||||
selectView('funnel');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,72 +0,0 @@
|
||||
# MovementTest README 完整结构重构设计
|
||||
|
||||
## 背景
|
||||
|
||||
`ClumsyPilot/ParkrobTrajplanner/tarjplanner_movementtest/README.md` 已经说明 EM 轨迹观察会话的只读边界、规划模式、配置和可视化,但章节组织、中英文一致性以及当前目录文件覆盖度仍弱于 `CoarsePath/README.md`。本次更新以粗路径 README 的阅读路径为参照,不机械复制其术语,而是按 MovementTest 的观察、闭环测试、诊断和停止职责重新组织内容。
|
||||
|
||||
## 目标
|
||||
|
||||
- 让读者先理解模块职责和安全边界,再理解文件、数据流、配置、操作和故障诊断。
|
||||
- 用完整文件树覆盖目标目录当前源码,包括观察入口、闭环入口、控制轨迹适配器、规划截止时间和各类诊断/快照/可视化组件。
|
||||
- 明确只读观察模式与闭环测试的能力边界,避免把诊断控制意图误认为可直接下发的硬件命令。
|
||||
- 根据当前源码核实入口名称、字段、默认值、报告路径、停止行为和可视化行为。
|
||||
- 仅修改目标 README,不修改其他源码或用户已有变更。
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 不改变规划、观察、控制或可视化行为。
|
||||
- 不新增 MovementTest 入口、配置字段或测试代码。
|
||||
- 不重构 `CoarsePath`、`PathSmoothing`、`EMPlanner` 或 `TrajectoryExecution` 文档。
|
||||
- 不清理、恢复或提交工作区内与本任务无关的改动。
|
||||
|
||||
## 文档结构
|
||||
|
||||
README 按以下阅读顺序重构:
|
||||
|
||||
1. 模块定位与安全声明。
|
||||
2. 模块说明:列出上游规划模块、执行模块和当前宿主的职责边界。
|
||||
3. 文件结构:逐项覆盖目标目录当前文件及职责。
|
||||
4. 运行数据流:分别呈现只读观察链路和闭环测试链路,明确二者共享与分离的部分。
|
||||
5. 运行状态与停止:说明启动、运行、取消、故障和资源清理行为。
|
||||
6. 坐标与单位:统一解释世界坐标、参考路径坐标、时间和运动学量。
|
||||
7. 最小使用示例:以 UI 操作和关键配置为主,不虚构独立公共 API。
|
||||
8. 会话冻结、规划周期与轨迹发布:说明完整方向段和滚动模式。
|
||||
9. 详细操作指南:准备目标与障碍物、启动、检查状态、观察图层、停止。
|
||||
10. 网页看板与可选 Painter:说明端口、令牌、刷新、交互和异常隔离。
|
||||
11. 报告与诊断:说明报告位置、主要状态和诊断用途。
|
||||
12. 常见错误:覆盖定位/速度读取、目标或障碍物、规划失败、可视化和误用控制意图。
|
||||
13. 当前限制:陈述现有模式的能力边界,不把未来设想写成已实现功能。
|
||||
|
||||
## 文件结构覆盖原则
|
||||
|
||||
文件树以磁盘上的实际文件为准,至少显式包含:
|
||||
|
||||
- `MovementTest.TrajectoryObservationTest.cs`
|
||||
- `MovementTest.EmClosedLoopTest.cs`
|
||||
- `EmControlTrajectoryAdapter.cs`
|
||||
- `TrajectoryObservationPlanningDeadline.cs`
|
||||
- `TrajectoryObservationPipeline.cs`
|
||||
- `TrajectoryObservationContracts.cs`
|
||||
- `TrajectoryObservationDiagnostics.cs`
|
||||
- `TrajectoryObservationSegmentTracker.cs`
|
||||
- 静态与动态快照构建器
|
||||
- 运动学图表、交接分析、呈现、可视化发布和报告写入组件
|
||||
|
||||
相近文件可以在树中逐项列出;正文可按职责分组解释,避免重复。
|
||||
|
||||
## 内容约束
|
||||
|
||||
- 以中文为主,保留必要的类型名、字段名、状态枚举和界面标识。
|
||||
- 保留 `OBSERVE_ONLY: no chassis command is sent.` 等具有运行识别价值的原始状态文本。
|
||||
- 参数表区分 MovementTest UI 默认值和契约默认值。
|
||||
- 所有命令、路径、入口和配置名称必须能从当前 README 或源码中找到依据。
|
||||
- 闭环测试涉及真实控制能力时,以源码中的安全前置条件、停止策略和命令出口为依据,避免沿用只读观察模式的绝对表述。
|
||||
- 不使用容易过时的实现细节替代稳定的使用契约。
|
||||
|
||||
## 验证方式
|
||||
|
||||
- 将文件树与目标目录的实际文件列表逐项比对。
|
||||
- 用源码搜索核实两个 UI 入口、配置字段、报告路径、停止/清理逻辑和安全状态文本。
|
||||
- 检查 Markdown 标题层级、代码块、表格和相对链接。
|
||||
- 扫描 `TODO`、`TBD`、占位文本和相互矛盾的安全描述。
|
||||
- 使用 `git diff --check` 并确认最终变更只包含目标 README;规格文档单独提交。
|
||||
Reference in New Issue
Block a user