2026-07-31 11:54:53 +08:00
<!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 : 1240 px ; margin : auto ; padding : 28 px 20 px 52 px ; }
header { color : #fff ; background : linear-gradient ( 135 deg , #14374e , #2e6682 ); border-radius : 18 px ; padding : 29 px ; box-shadow : 0 10 px 24 px #15364d 2 b ; }
h1 , h2 , h3 , p { margin-top : 0 ; } h1 { font-size : clamp ( 1.65 rem , 4 vw , 2.35 rem ); margin-bottom : 7 px ; } h2 { font-size : clamp ( 1.28 rem , 3 vw , 1.65 rem ); margin : 0 ; } h3 { margin-bottom : 7 px ; font-size : 1 rem ; }
. eyebrow { font-size : .82 rem ; letter-spacing : .08 em ; opacity : .86 ; } . subtitle { max-width : 900 px ; color : #e1f0f7 ; margin-bottom : 16 px ; }
. badges , . issue-selector , . issue-controls { display : flex ; flex-wrap : wrap ; gap : 10 px ; }
. badge { display : inline-block ; border-radius : 999 px ; padding : 3 px 10 px ; font-size : .83 rem ; font-weight : 700 ; }
. badge . repro { color : #7b1620 ; background : #ffd9dd ; } . badge . static { color : #6f4808 ; background : #ffe8bc ; } . badge . risk { color : #164e74 ; background : #d4ebfa ; }
. issue-selector { margin : 24 px 0 14 px ; } button { font : inherit ; cursor : pointer ; }
. issue-button , . issue-controls button { border : 1 px solid #b8cad4 ; border-radius : 10 px ; padding : 10 px 14 px ; color : var ( -- ink ); background : #fff ; font-weight : 700 ; }
. issue-button [ aria-pressed = "true" ] { color : #fff ; border-color : #174b68 ; background : #174b68 ; }
button : focus-visible { outline : 3 px solid #f0ad32 ; outline-offset : 3 px ; }
. issue-stage { background : var ( -- panel ); border : 1 px solid var ( -- line ); border-radius : 16 px ; padding : 22 px ; box-shadow : 0 4 px 12 px #15364d 0 d ; }
# issue-evidence { display : inline-block ; margin-bottom : 5 px ; color : var ( -- info ); font-size : .87 rem ; font-weight : 800 ; }
2026-07-31 12:18:34 +08:00
. visual-wrap { margin : 18 px -4 px ; padding : 4 px ; } # issue-visual { display : block ; width : 100 % ; height : auto ; }
2026-07-31 11:54:53 +08:00
. 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 , 1 fr ); gap : 13 px ; } . compare-copy article { border : 1 px solid var ( -- line ); border-radius : 10 px ; padding : 14 px ; } . compare-copy article : nth-child ( 1 ) { border-top : 4 px solid var ( -- actual ); } . compare-copy article : nth-child ( 2 ) { border-top : 4 px solid var ( -- expected ); } . compare-copy article : nth-child ( 3 ) { border-top : 4 px solid var ( -- info ); } . compare-copy p { margin-bottom : 0 ; }
. next-action { margin : 15 px 0 0 ; padding : 12 px 14 px ; border-radius : 9 px ; background : #edf4f7 ; } . issue-controls { justify-content : space-between ; margin-top : 14 px ; } . issue-controls button { background : #eaf2f5 ; }
. priority { display : grid ; grid-template-columns : 72 px 1 fr ; margin-top : 28 px ; overflow : hidden ; border : 1 px solid var ( -- line ); border-radius : 14 px ; background : #fff ; } . priority div { padding : 12 px 15 px ; border-bottom : 1 px 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 : 25 px ; color : var ( -- muted ); font-size : .86 rem ; }
. lane { fill : #fbfcfd ; stroke : #cbd9e2 ; stroke-width : 2 ; } . lane-label { fill : #173448 ; font-size : 18 px ; font-weight : 800 ; } . label { fill : #415a6b ; font-size : 15 px ; font-weight : 700 ; } . small { fill : #5e7180 ; font-size : 13 px ; } . 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 : 13 px ; font-style : italic ; }
@ media ( max-width : 680px ) { main { padding : 16 px 12 px 38 px ; } header , . issue-stage { padding : 18 px ; } . compare-copy { grid-template-columns : 1 fr ; } . 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 >