# 路口主导的短路段整条置灰 父任务:`.trellis/tasks/08-26-direct-manipulation-road-editor`。约束模型与编辑所有权的权威定义在父任务 `design.md`。 ## 问题 `src/compile/direct-edit-solver.js` 里 `editable: false` 的唯一来源是 `unavailable`: ```js const start = Math.min(1, startReserve); const end = Math.max(0, 1 - endReserve); const unavailable = start >= end; ``` 但 `junctionReserves()` 给每端保留区的比例有硬上限 `Math.min(0.45, cutback / length)`, 于是 `start ≤ 0.45`、`end ≥ 0.55`,`start >= end` 结构上永远为假。 **该分支是死代码,连带那句提示语「该道路全部位于路口保留区,请进入 JunctionTools 编辑。」永远不可能显示。** 实测 `test/fixtures/fengshu-er-road.osm`:126 个道路手柄,0 个 `editable: false`。 后果是短路段拿到了一条无意义的编辑带(`test/fixtures/fengshu-er-road.osm`,20 个有保留区的段): | 路长(米) | 总宽(米) | 窗口 | 可编辑带(米) | | --- | --- | --- | --- | | 14.5 | 9.8 | [0.45,0.55] | 1.5 | | 15.4 | 9.8 | [0.45,0.55] | 1.5 | | 18.6 | 9.8 | [0.45,0.55] | 1.9 | | 19.1 | 9.8 | [0.45,0.55] | 1.9 | | 19.2 | 9.8 | [0.45,0.55] | 1.9 | | 19.6 | 6.5 | [0.45,0.55] | 2.0 | | 82.2 | 9.8 | [0.17,0.83] | 54.9 | | 199.2 | 9.8 | [0.00,0.93] | 185.6 | 第一行那条路只有 14.5 米长、9.8 米宽,cutback 是 `max(宽度) × 1.4 ≈ 13.7` 米—— **每一端**的路口都要这条路的 94%,两端合计 188%,远超全长。上限把它压成各 45%, 凭空造出中间 10%(1.5 米)的「可编辑带」。 这违反两条已写明的约定: - 父任务不变量「相邻 profile 之间必须有可计算的过渡」。约束默认 `transition: 'smoothstep'` 作用于区间两端回归基线,1.5 米的区间两侧紧贴保留区,没有任何余量做过渡。 - 父任务「编辑所有权」:主地图只编辑两个 junction reserve **之间**的道路内部 interval。 这种路的真实路口几何占满全长,根本不存在「之间」。 ## 目标 让路口几何占满的短路段整条归 JunctionTools,恢复那个分支的可达性, 并使父任务 prd 的验收标准「落在 junction reserve 内的手柄不可拖动,并提示进入 JunctionTools」 从空真变成可演示。 ## 判据 **可编辑带长度(米)< 道路总宽度(米)→ 该 segment 的所有道路手柄 `editable: false`。** 用物理长度而非归一化 station,理由是过渡段需要的是实际距离,与道路长短无关。 一条比自身宽度还短的编辑带装不下横断面的平滑变化。 在上表数据上分界干净,无边界模糊样本:1.5 < 9.8 置灰;54.9 > 9.8 保留。 恰好切出可编辑带 < 10 米的那 6 段。 判断必须在上限生效**之后**用实际窗口算,而不是拿未截断的 `cutback / length` 之和—— 后者与「过渡段放不下」这件事没有直接关系。 ## 验收标准 - [ ] 可编辑带短于道路宽度的 segment,其全部 `road-*` 手柄 `editable: false` 且带 `disabledReason`。 - [ ] `disabledReason` 复用既有文案,引导进入 JunctionTools。 - [ ] 可编辑带不短于道路宽度的 segment,行为与当前 main 完全一致(手柄数量、位置、`editable: true`)。 - [ ] 置灰不改变 `reserves` 本身,也不改变任何几何输出:`compileGeometry` 结果与置灰前逐字节一致。 - [ ] 置灰的 segment 仍然出现在 manifest 中(不是被删除),否则客户端无法解释为什么不能编辑。 - [ ] junction 手柄不受影响,仍然 `editable: true`。 - [ ] `test/direct-edit-solver.js` 覆盖:短路段全部置灰、正常路段不受影响、判据边界(带长 ≈ 宽度)。 - [ ] `npm run test`、`npm run test:client`、`npm run test:client:unit`、`npm run format:check`、`npm run build` 全绿。 - [ ] 客户端无需改动即可显示灰色手柄与原因(`08-26-direct-edit-map-editor` 已实现该路径)。 ## 不做 - 不改 `junctionReserves()` 的 0.45 上限本身。上限保护的是 reserve 语义,改它会牵动 junction 侧几何。 - 不改 cutback 的推导公式。 - 不实现 JunctionTools 侧的编辑能力(属 `08-26-direct-edit-junction-tools`)。 - 不做客户端改动。 - 不把置灰的 segment 从 manifest 里移除。 ## 顺序依赖 与 `08-26-direct-edit-map-editor` 的第 4、5 步无依赖,可并行或后置。 客户端置灰渲染路径已在该任务第 3 步交付并有单测覆盖,本任务只补上服务端的输入。