diff --git a/docs/en/phase-0-reactflow-parity-audit.md b/docs/en/phase-0-reactflow-parity-audit.md index 9cbb1244..87093db8 100644 --- a/docs/en/phase-0-reactflow-parity-audit.md +++ b/docs/en/phase-0-reactflow-parity-audit.md @@ -194,6 +194,10 @@ Phase 536 is GitHub #195 / `avalonia-node-map-uvd`, the lasso screenshot route a Phase 537 is GitHub #197 / `avalonia-node-map-w9h`, the lasso toolbar UX and public activation ergonomics boundary. This implementation slice adds `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(...)` and the hosted Authoring Tools buttons `PART_PointerModeMarqueeButton` / `PART_PointerModeLassoButton`. The actions set the existing `NodeCanvas.SelectionMode` property to `NodeCanvasSelectionMode.Marquee` or `NodeCanvasSelectionMode.Lasso`; they stay `GraphEditorCommandSourceKind.Host` actions with no runtime command id, so they do not create a parallel selection model. `HostedActions_PointerModeActionsSwitchNodeCanvasSelectionModeWithoutRuntimeCommandRoute` and `AuthoringToolsChrome_ProjectsPointerModeActionsThroughNodeCanvasSelectionMode` guard the public helper and hosted toolbar route. This authorizes no eraser, no drawing primitives, no persistence, no renderer rewrite, no strict pixel baselines, no retained API removal, and no full whiteboard parity. +## Phase 538 Update + +Phase 538 is GitHub #199 / `avalonia-node-map-a3w`, the eraser behavior/API feasibility gate. This docs/tests-only slice records that AsterGraph's current source-backed deletion evidence is graph-selection deletion through `selection.delete`, the `Delete Selection` command descriptor, and the stock `selection-delete` placement. That route can delete selected graph nodes through the existing command system, but it is not an eraser cursor, collision trail, or eraser-specific hit-testing behavior. It authorizes no eraser cursor, no collision trail, no eraser-specific hit-testing, no drawing primitives, no persistence, no renderer rewrite, no strict pixel baseline enforcement, no retained API removal, and no full whiteboard parity. + ## Phase 489 Update Phase 489 closed GitHub #101 / `avalonia-node-map-6sc` through PR #102 as a renderer virtualization design spike on branch `perf/renderer-virtualization-spike`. This slice was docs/tests only: it defined the proof contract required before any future ItemsRepeater/Skia-style renderer virtualization, background graph index, or graph-size claim expansion. It made no public API change and no runtime change. The current evidence remains viewport-budgeted scene projection/rendering, not a true renderer virtualization contract; `xlarge` stays telemetry-only. @@ -368,7 +372,7 @@ Phase 529 records the whiteboard/lasso/eraser feasibility audit through GitHub # | Rectangle marquee selection | Present / guarded | `GetSelectionRectangleSnapshot`, `UpdateMarqueeSelection`, `Queries_GetSelectionRectangleSnapshot_ReturnsNodesAndConnectionsInRectangle`, `UpdateMarqueeSelection_WithFinalizeTrue_UsesBackendSelectionRectangleQuery`, `interaction-selection-marquee-route`, `selection-marquee-workbench`, and `v079-selection-rectangle-route` prove rectangular selection evidence. | This is axis-aligned rectangle/marquee selection, not lasso/freehand selection or a drawing tool. | | Multi-select and command projection | Present / guarded | `selection.select-all`, `selection.select-none`, `selection.invert`, `selection.delete`, and `selection.transform.move` expose current selection and manipulation commands. | Command projection operates on graph selections; it does not add eraser hit trails, drawn shape lifecycle, or whiteboard-specific edit modes. | | Lasso/freehand selection | Public Avalonia lasso selection mode with hosted toolbar activation and transient visual feedback / whiteboard gap retained | `GetSelectionLassoSnapshot`, `GraphEditorSelectionLassoSnapshot`, `Queries_GetSelectionLassoSnapshot_ReturnsCenterContainedNodesAndConnections`, `Queries_GetSelectionLassoSnapshot_UsesNodeCenterInsteadOfBoundsIntersection`, `Queries_GetSelectionLassoSnapshot_WithOpenOrDegeneratePath_ReturnsDeterministicResults`, `UpdateLassoSelection_WithFinalizeTrue_UsesBackendSelectionLassoQuery`, `LassoSelection_RoutesThroughCanvasBridge_AndSelectsContainedNodes`, `NodeCanvasSelectionGestureKind.Lasso`, `TryBeginLassoSelection_WithLassoGestureKind_RecordsStartAndMoveAfterThreshold`, `HandleMoved_WhenCanvasSelectionUsesLassoGesture_RecordsLassoPointAndSkipsMarqueeUpdate`, `HandleReleased_AfterLassoSelection_FinalizesLassoSelectionAndResetsSession`, `NodeCanvasSelectionMode.Lasso`, `LassoSelectionMode_RoutesThroughCanvasPointerHandlers_AndSelectsContainedNodes`, `UpdateLassoFeedback`, `ClearLassoFeedback`, `LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag`, `CreatePointerSelectionModeActions`, `pointer-mode.lasso-selection`, `PART_PointerModeLassoButton`, `HostedActions_PointerModeActionsSwitchNodeCanvasSelectionModeWithoutRuntimeCommandRoute`, and `AuthoringToolsChrome_ProjectsPointerModeActionsThroughNodeCanvasSelectionMode` prove the active-scope backend query, internal Avalonia bridge, internal gesture capture route, public pointer-mode activation route, hosted toolbar route, and transient visual feedback route. The query treats freeform points as a closed polygon, selects nodes by center-point containment, and selects connections when both endpoint nodes are selected. | No eraser behavior, drawing primitives, persistence, renderer layer, strict pixel baselines, retained API removal, or full React Flow whiteboard parity is implemented. This remains not full React Flow whiteboard parity. | -| Eraser tool | Gap retained | `selection.delete` can delete the current graph selection, but there is no eraser cursor, collision trail, or eraser-specific hit-testing path. | Needs a later behavior/API issue before claiming eraser tool parity; this slice adds no runtime UI behavior changes. | +| Eraser tool | Feasibility gate recorded / gap retained | `selection.delete`, the `Delete Selection` descriptor, and the stock `selection-delete` placement prove graph-selection deletion evidence only. | Phase 538 records that graph-selection deletion is not an eraser cursor, collision trail, or eraser-specific hit-testing path. No eraser cursor, no collision trail, no eraser-specific hit-testing, no drawing primitives, no persistence, no renderer rewrite, no strict pixel baseline enforcement, no retained API removal, and no full whiteboard parity are implemented. | | Rectangle/freehand drawing | Gap retained | Existing rectangle evidence is selection-only. There are no rectangle/freehand drawing tools, whiteboard primitives, shape nodes, brush/color state, or drawing persistence contracts. | Needs later API/model/renderer work before claiming rectangle draw or freehand draw parity. | | Whiteboard persistence/render layer | Gap retained | Current Cookbook and screenshot rows cover graph scenes and built-in components, not whiteboard annotations or drawing state. | Future work would need persistence, renderer layer, hit-testing, React Flow-like examples, and screenshot manifest expansion; Phase 529 adds none of those. | @@ -501,12 +505,14 @@ Phase 536 adds the bounded lasso screenshot proof through GitHub #195 / `avaloni Phase 537 adds the lasso toolbar ergonomics route through GitHub #197 / `avalonia-node-map-w9h`. It adds `CreatePointerSelectionModeActions(...)`, `pointer-mode.lasso-selection`, and `PART_PointerModeLassoButton` as host-facing activation over `NodeCanvas.SelectionMode` / `NodeCanvasSelectionMode.Lasso`, while retaining eraser behavior, drawing primitives, persistence, renderer rewrite, strict pixel baselines, retained API removal, and full whiteboard parity as gaps. +Phase 538 records the eraser behavior/API feasibility gate through GitHub #199 / `avalonia-node-map-a3w`. It keeps `selection.delete`, `Delete Selection`, and `selection-delete` tied to graph-selection deletion evidence only, while retaining eraser cursor, collision trail, eraser-specific hit-testing, drawing primitives, persistence, renderer rewrite, strict pixel baselines, retained API removal, and full whiteboard parity as gaps. + | GitHub | Bead | Title | Priority | Likely write set | Parallelism | | --- | --- | --- | --- | --- | --- | | #193 | `avalonia-node-map-8l6` | Phase 535: refresh post-lasso visual feedback parity queue | P2 | parity roadmap docs and focused docs tests | Current docs/test queue refresh. Blocks the next implementation wave because it replaces the stale Phase 534 current row with tracker-backed follow-ups. | | #195 | `avalonia-node-map-uvd` | Phase 536: lasso screenshot route and Cookbook proof boundary | P2 | Cookbook screenshot manifest, Demo fixture route, scene/shell screenshot tests, and parity docs | Current visual proof slice. Blocks lasso toolbar work until the screenshot route and Cookbook proof boundary are stable. | -| #197 | `avalonia-node-map-w9h` | Phase 537: lasso toolbar UX and public activation ergonomics boundary | P2 | hosted authoring tools, `NodeCanvas.SelectionMode` activation surface, Demo/Cookbook route, and editor/Avalonia tests | Current toolbar ergonomics slice. It stays on hosted actions over the existing canvas selection mode and does not create whiteboard primitives. | -| TBD | TBD | Phase 538: eraser behavior/API feasibility gate | P3 | editor selection/delete commands, Avalonia hit-testing route, parity docs, and focused feasibility tests | Can run after Phase 535 in parallel with drawing model planning if it avoids shared pointer-mode state edits. | +| #197 | `avalonia-node-map-w9h` | Phase 537: lasso toolbar UX and public activation ergonomics boundary | P2 | hosted authoring tools, `NodeCanvas.SelectionMode` activation surface, Demo/Cookbook route, and editor/Avalonia tests | Merged toolbar ergonomics slice. It stays on hosted actions over the existing canvas selection mode and does not create whiteboard primitives. | +| #199 | `avalonia-node-map-a3w` | Phase 538: eraser behavior/API feasibility gate | P3 | graph-selection deletion evidence, parity roadmap docs, and focused docs tests | Current eraser feasibility slice. It keeps `selection.delete` scoped to graph-selection deletion evidence and does not create an eraser cursor, collision trail, or eraser-specific hit-testing path. | | TBD | TBD | Phase 539: rectangle/freehand drawing primitive model gate | P3 | Core/Editor model contract docs/tests and whiteboard primitive API inventory | Can run after Phase 535 in parallel with eraser feasibility if it stays docs/model-only and does not touch Avalonia pointer coordinators. | | TBD | TBD | Phase 540: whiteboard persistence and render-layer readiness gate | P4 | persistence/schema planning docs, renderer-layer boundary docs, screenshot policy notes, and focused docs tests | Depends on Phase 539 model decisions; do not implement persistence or renderer behavior in the queue refresh. | @@ -546,8 +552,8 @@ Phase 537 adds the lasso toolbar ergonomics route through GitHub #197 / `avaloni - `docs/phase-528-panel-overlay-boundary`: owns #179 / `avalonia-node-map-9ow`; current docs/test worktree for the Panel versus viewport-attached overlay boundary. - `docs/phase-535-post-lasso-queue-refresh`: owns #193 / `avalonia-node-map-8l6`; current docs/test queue refresh after transient lasso feedback, with no runtime/API/UI/screenshot-manifest/whiteboard implementation changes. - `visual/phase-536-lasso-screenshot-proof`: owns #195 / `avalonia-node-map-uvd`; current slice for `cookbook-interaction-lasso-screenshot-proof`, `shell-cookbook-lasso-screenshot-proof`, and the bounded lasso screenshot proof boundary. -- `feature/phase-537-lasso-toolbar-ergonomics`: future candidate for lasso toolbar UX and public activation ergonomics after Phase 535. -- `feature/phase-538-eraser-feasibility`: future candidate for eraser behavior/API feasibility after Phase 535. +- `feature/phase-537-lasso-toolbar-ergonomics`: owned #197 / `avalonia-node-map-w9h`; merged worktree for lasso toolbar UX and public activation ergonomics. +- `feature/phase-538-eraser-feasibility`: owns #199 / `avalonia-node-map-a3w`; current worktree for eraser behavior/API feasibility with graph-selection deletion evidence only. - `docs/phase-539-drawing-primitive-model-gate`: future candidate for rectangle/freehand drawing primitive model decisions after Phase 535. - `docs/phase-540-whiteboard-render-persistence-gate`: future candidate for persistence/render-layer readiness after drawing model decisions. diff --git a/docs/zh-CN/phase-0-reactflow-parity-audit.md b/docs/zh-CN/phase-0-reactflow-parity-audit.md index cf406651..c735908f 100644 --- a/docs/zh-CN/phase-0-reactflow-parity-audit.md +++ b/docs/zh-CN/phase-0-reactflow-parity-audit.md @@ -194,6 +194,10 @@ Phase 536 是 GitHub #195 / `avalonia-node-map-uvd`,承接 lasso screenshot ro Phase 537 是 GitHub #197 / `avalonia-node-map-w9h`,承接 lasso toolbar UX and public activation ergonomics boundary。本实现 slice 新增 `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(...)`,并在 hosted Authoring Tools 中投影 `PART_PointerModeMarqueeButton` / `PART_PointerModeLassoButton`。这些 action 只把现有 `NodeCanvas.SelectionMode` 设置为 `NodeCanvasSelectionMode.Marquee` 或 `NodeCanvasSelectionMode.Lasso`;它们保持为无 runtime command id 的 `GraphEditorCommandSourceKind.Host` action,不创建第二套 selection model。`HostedActions_PointerModeActionsSwitchNodeCanvasSelectionModeWithoutRuntimeCommandRoute` 与 `AuthoringToolsChrome_ProjectsPointerModeActionsThroughNodeCanvasSelectionMode` 守住 public helper 和 hosted toolbar route。它不授权 no eraser、no drawing primitives、no persistence、no renderer rewrite、no strict pixel baselines、no retained API removal 或 no full whiteboard parity。 +## Phase 538 更新 + +Phase 538 是 GitHub #199 / `avalonia-node-map-a3w`,承接 eraser behavior/API feasibility gate。本 docs/tests-only slice 记录 AsterGraph 当前有 source-backed deletion evidence,但它只是通过 `selection.delete`、`Delete Selection` command descriptor 和 stock `selection-delete` placement 提供 graph-selection deletion。该 route 可以通过现有 command system 删除已选 graph nodes,但它 is not an eraser cursor、collision trail 或 eraser-specific hit-testing behavior。它不授权 no eraser cursor、no collision trail、no eraser-specific hit-testing、no drawing primitives、no persistence、no renderer rewrite、no strict pixel baseline enforcement、no retained API removal 或 no full whiteboard parity。 + ## Phase 489 更新 Phase 489 通过 PR #102 关闭 GitHub #101 / `avalonia-node-map-6sc`,完成 `perf/renderer-virtualization-spike` 分支上的 renderer virtualization design spike。本 slice 只做 docs/tests:先定义未来声明 ItemsRepeater/Skia-style renderer virtualization、background graph index 或扩大 graph-size claim 前必须满足的 proof contract。不做 public API change,也不做 runtime change。当前证据仍只支持 viewport-budgeted scene projection/rendering,不是真正的 renderer virtualization contract;`xlarge` 继续保持 telemetry-only。 @@ -368,7 +372,7 @@ Phase 529 记录 whiteboard/lasso/eraser feasibility audit,对应 GitHub #181 | Rectangle marquee selection | Present / guarded | `GetSelectionRectangleSnapshot`、`UpdateMarqueeSelection`、`Queries_GetSelectionRectangleSnapshot_ReturnsNodesAndConnectionsInRectangle`、`UpdateMarqueeSelection_WithFinalizeTrue_UsesBackendSelectionRectangleQuery`、`interaction-selection-marquee-route`、`selection-marquee-workbench` 和 `v079-selection-rectangle-route` 证明 rectangular selection evidence。 | 这是 axis-aligned rectangle/marquee selection,不是 lasso/freehand selection 或 drawing tool。 | | Multi-select and command projection | Present / guarded | `selection.select-all`、`selection.select-none`、`selection.invert`、`selection.delete` 和 `selection.transform.move` 暴露当前 selection 与 manipulation commands。 | Command projection 操作 graph selections;它不新增 eraser hit trails、drawn shape lifecycle 或 whiteboard-specific edit modes。 | | Lasso/freehand selection | Public Avalonia lasso selection mode with hosted toolbar activation and transient visual feedback / whiteboard gap retained | `GetSelectionLassoSnapshot`、`GraphEditorSelectionLassoSnapshot`、`Queries_GetSelectionLassoSnapshot_ReturnsCenterContainedNodesAndConnections`、`Queries_GetSelectionLassoSnapshot_UsesNodeCenterInsteadOfBoundsIntersection`、`Queries_GetSelectionLassoSnapshot_WithOpenOrDegeneratePath_ReturnsDeterministicResults`、`UpdateLassoSelection_WithFinalizeTrue_UsesBackendSelectionLassoQuery`、`LassoSelection_RoutesThroughCanvasBridge_AndSelectsContainedNodes`、`NodeCanvasSelectionGestureKind.Lasso`、`TryBeginLassoSelection_WithLassoGestureKind_RecordsStartAndMoveAfterThreshold`、`HandleMoved_WhenCanvasSelectionUsesLassoGesture_RecordsLassoPointAndSkipsMarqueeUpdate`、`HandleReleased_AfterLassoSelection_FinalizesLassoSelectionAndResetsSession`、`NodeCanvasSelectionMode.Lasso`、`LassoSelectionMode_RoutesThroughCanvasPointerHandlers_AndSelectsContainedNodes`、`UpdateLassoFeedback`、`ClearLassoFeedback`、`LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag`、`CreatePointerSelectionModeActions`、`pointer-mode.lasso-selection`、`PART_PointerModeLassoButton`、`HostedActions_PointerModeActionsSwitchNodeCanvasSelectionModeWithoutRuntimeCommandRoute` 和 `AuthoringToolsChrome_ProjectsPointerModeActionsThroughNodeCanvasSelectionMode` 证明 active-scope backend query、internal Avalonia bridge、internal gesture capture route、public pointer-mode activation route、hosted toolbar route 和 transient visual feedback route。该 query 把 freeform points 当作 closed polygon,用 center-point containment 选择 node,并在两个 endpoint node 都选中时选择 connection。 | 尚未实现 eraser behavior、drawing primitives、persistence、renderer layer、strict pixel baselines、retained API removal 或 full React Flow whiteboard parity。该边界仍是 not full React Flow whiteboard parity。 | -| Eraser tool | Gap retained | `selection.delete` 可以删除当前 graph selection,但没有 eraser cursor、collision trail 或 eraser-specific hit-testing path。 | 声明 eraser tool parity 之前需要后续 behavior/API issue;本 slice 不新增 runtime UI behavior changes。 | +| Eraser tool | Feasibility gate recorded / gap retained | `selection.delete`、`Delete Selection` descriptor 和 stock `selection-delete` placement 只证明 graph-selection deletion evidence。 | Phase 538 记录 graph-selection deletion is not an eraser cursor、collision trail 或 eraser-specific hit-testing path。尚未实现 no eraser cursor、no collision trail、no eraser-specific hit-testing、no drawing primitives、no persistence、no renderer rewrite、no strict pixel baseline enforcement、no retained API removal 或 no full whiteboard parity。 | | Rectangle/freehand drawing | Gap retained | 现有 rectangle evidence 只属于 selection。当前没有 rectangle/freehand drawing tools、whiteboard primitives、shape nodes、brush/color state 或 drawing persistence contracts。 | 声明 rectangle draw 或 freehand draw parity 前,需要后续 API/model/renderer 工作。 | | Whiteboard persistence/render layer | Gap retained | 当前 Cookbook 和 screenshot rows 覆盖 graph scenes 与 built-in components,不覆盖 whiteboard annotations 或 drawing state。 | 后续若推进,需要 persistence、renderer layer、hit-testing、React Flow-like examples 和 screenshot manifest expansion;Phase 529 均不新增。 | @@ -501,12 +505,14 @@ Phase 536 通过 GitHub #195 / `avalonia-node-map-uvd` 新增 bounded lasso scre Phase 537 通过 GitHub #197 / `avalonia-node-map-w9h` 新增 lasso toolbar ergonomics route。它加入 `CreatePointerSelectionModeActions(...)`、`pointer-mode.lasso-selection` 和 `PART_PointerModeLassoButton`,作为 `NodeCanvas.SelectionMode` / `NodeCanvasSelectionMode.Lasso` 上的 host-facing activation,同时继续把 eraser behavior、drawing primitives、persistence、renderer rewrite、strict pixel baselines、retained API removal 和 full whiteboard parity 保留为 gaps。 +Phase 538 通过 GitHub #199 / `avalonia-node-map-a3w` 记录 eraser behavior/API feasibility gate。它把 `selection.delete`、`Delete Selection` 和 `selection-delete` 限定为 graph-selection deletion evidence,同时继续把 eraser cursor、collision trail、eraser-specific hit-testing、drawing primitives、persistence、renderer rewrite、strict pixel baselines、retained API removal 和 full whiteboard parity 保留为 gaps。 + | GitHub | Bead | 标题 | 优先级 | 可能 write set | 并行边界 | | --- | --- | --- | --- | --- | --- | | #193 | `avalonia-node-map-8l6` | Phase 535: refresh post-lasso visual feedback parity queue | P2 | parity roadmap docs 和 focused docs tests | Current docs/test queue refresh。它用 tracker-backed follow-ups 替换 stale Phase 534 current row,因此会阻塞下一批 implementation wave。 | | #195 | `avalonia-node-map-uvd` | Phase 536: lasso screenshot route and Cookbook proof boundary | P2 | Cookbook screenshot manifest、Demo fixture route、scene/shell screenshot tests 和 parity docs | Current visual proof slice。它会先稳定 screenshot route 与 Cookbook proof boundary,再进入 lasso toolbar work。 | -| #197 | `avalonia-node-map-w9h` | Phase 537: lasso toolbar UX and public activation ergonomics boundary | P2 | hosted authoring tools、`NodeCanvas.SelectionMode` activation surface、Demo/Cookbook route 和 editor/Avalonia tests | Current toolbar ergonomics slice。它只在 existing canvas selection mode 上投影 hosted actions,不创建 whiteboard primitives。 | -| TBD | TBD | Phase 538: eraser behavior/API feasibility gate | P3 | editor selection/delete commands、Avalonia hit-testing route、parity docs 和 focused feasibility tests | Phase 535 后可与 drawing model planning 并行,只要不共享 pointer-mode state edits。 | +| #197 | `avalonia-node-map-w9h` | Phase 537: lasso toolbar UX and public activation ergonomics boundary | P2 | hosted authoring tools、`NodeCanvas.SelectionMode` activation surface、Demo/Cookbook route 和 editor/Avalonia tests | Merged toolbar ergonomics slice。它只在 existing canvas selection mode 上投影 hosted actions,不创建 whiteboard primitives。 | +| #199 | `avalonia-node-map-a3w` | Phase 538: eraser behavior/API feasibility gate | P3 | graph-selection deletion evidence、parity roadmap docs 和 focused docs tests | Current eraser feasibility slice。它把 `selection.delete` 限定为 graph-selection deletion evidence,不创建 eraser cursor、collision trail 或 eraser-specific hit-testing path。 | | TBD | TBD | Phase 539: rectangle/freehand drawing primitive model gate | P3 | Core/Editor model contract docs/tests 和 whiteboard primitive API inventory | Phase 535 后可与 eraser feasibility 并行,只要保持 docs/model-only 且不触碰 Avalonia pointer coordinators。 | | TBD | TBD | Phase 540: whiteboard persistence and render-layer readiness gate | P4 | persistence/schema planning docs、renderer-layer boundary docs、screenshot policy notes 和 focused docs tests | 依赖 Phase 539 model decisions;本 queue refresh 不实现 persistence 或 renderer behavior。 | @@ -546,8 +552,8 @@ Phase 537 通过 GitHub #197 / `avalonia-node-map-w9h` 新增 lasso toolbar ergo - `docs/phase-528-panel-overlay-boundary`:负责 #179 / `avalonia-node-map-9ow`;当前 docs/test worktree,用于 Panel versus viewport-attached overlay boundary。 - `docs/phase-535-post-lasso-queue-refresh`:负责 #193 / `avalonia-node-map-8l6`;当前 docs/test queue refresh,承接 transient lasso feedback 后续拆分,不做 runtime/API/UI/screenshot-manifest/whiteboard implementation changes。 - `visual/phase-536-lasso-screenshot-proof`:负责 #195 / `avalonia-node-map-uvd`;当前 slice,用于 `cookbook-interaction-lasso-screenshot-proof`、`shell-cookbook-lasso-screenshot-proof` 和 bounded lasso screenshot proof boundary。 -- `feature/phase-537-lasso-toolbar-ergonomics`:future candidate,用于 Phase 535 后的 lasso toolbar UX 和 public activation ergonomics。 -- `feature/phase-538-eraser-feasibility`:future candidate,用于 Phase 535 后的 eraser behavior/API feasibility。 +- `feature/phase-537-lasso-toolbar-ergonomics`:负责 #197 / `avalonia-node-map-w9h`;已合并的 worktree,用于 lasso toolbar UX 和 public activation ergonomics。 +- `feature/phase-538-eraser-feasibility`:负责 #199 / `avalonia-node-map-a3w`;当前 worktree,用 graph-selection deletion evidence 记录 eraser behavior/API feasibility。 - `docs/phase-539-drawing-primitive-model-gate`:future candidate,用于 Phase 535 后的 rectangle/freehand drawing primitive model decisions。 - `docs/phase-540-whiteboard-render-persistence-gate`:future candidate,用于 drawing model decisions 后的 persistence/render-layer readiness。 diff --git a/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs b/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs index 5cad8e8c..cabeb6c6 100644 --- a/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs +++ b/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs @@ -1031,6 +1031,42 @@ public void ParityRoadmapDocs_RecordPhase537LassoToolbarErgonomicsInBothLocales( AssertPostPhase537Queue(ExtractIssueWaveTable(chineseParity)); } + [Fact] + public void ParityRoadmapDocs_RecordPhase538EraserBehaviorApiFeasibilityGateInBothLocales() + { + var englishParity = ReadRepoFile("docs/en/phase-0-reactflow-parity-audit.md"); + var chineseParity = ReadRepoFile("docs/zh-CN/phase-0-reactflow-parity-audit.md"); + + foreach (var contents in new[] { englishParity, chineseParity }) + { + Assert.Contains("Phase 538", contents, StringComparison.Ordinal); + Assert.Contains("GitHub #199", contents, StringComparison.Ordinal); + Assert.Contains("avalonia-node-map-a3w", contents, StringComparison.Ordinal); + Assert.Contains("eraser behavior/API feasibility gate", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("selection.delete", contents, StringComparison.Ordinal); + Assert.Contains("Delete Selection", contents, StringComparison.Ordinal); + Assert.Contains("selection-delete", contents, StringComparison.Ordinal); + Assert.Contains("graph-selection deletion", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("not an eraser cursor", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no eraser cursor", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no collision trail", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no eraser-specific hit-testing", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no drawing primitives", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no persistence", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no renderer rewrite", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no strict pixel baseline", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no retained API removal", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no full whiteboard parity", contents, StringComparison.OrdinalIgnoreCase); + } + + AssertPostPhase538Queue(ExtractIssueWaveTable(englishParity)); + AssertPostPhase538Queue(ExtractIssueWaveTable(chineseParity)); + AssertPhase538WorktreePlan(ExtractRecommendedWorktreePlan(englishParity)); + AssertPhase538WorktreePlan(ExtractRecommendedWorktreePlan(chineseParity)); + AssertWhiteboardLassoEraserFeasibilityAudit(ExtractWhiteboardLassoEraserFeasibilityAudit(englishParity)); + AssertWhiteboardLassoEraserFeasibilityAudit(ExtractWhiteboardLassoEraserFeasibilityAudit(chineseParity)); + } + [Fact] public void AuthoringSurfaceRecipeDocs_SurfacePhase537PointerModeToolbarRoute() { @@ -1145,7 +1181,9 @@ private static void AssertPostPhase534Queue(string table) Assert.Contains("TBD", table, StringComparison.Ordinal); Assert.Contains("Cookbook screenshot manifest", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("hosted authoring tools", table, StringComparison.OrdinalIgnoreCase); - Assert.Contains("editor selection/delete commands", table, StringComparison.OrdinalIgnoreCase); + Assert.True( + table.Contains("editor selection/delete commands", StringComparison.OrdinalIgnoreCase) + || table.Contains("graph-selection deletion evidence", StringComparison.OrdinalIgnoreCase)); Assert.Contains("Core/Editor model contract", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("persistence/schema planning", table, StringComparison.OrdinalIgnoreCase); Assert.True( @@ -1168,10 +1206,45 @@ private static void AssertPostPhase537Queue(string table) Assert.Contains("Phase 540: whiteboard persistence and render-layer readiness gate", table, StringComparison.Ordinal); Assert.Contains("TBD", table, StringComparison.Ordinal); Assert.Contains("hosted authoring tools", table, StringComparison.OrdinalIgnoreCase); - Assert.Contains("editor selection/delete commands", table, StringComparison.OrdinalIgnoreCase); + Assert.True( + table.Contains("editor selection/delete commands", StringComparison.OrdinalIgnoreCase) + || table.Contains("graph-selection deletion evidence", StringComparison.OrdinalIgnoreCase)); + Assert.Contains("Core/Editor model contract", table, StringComparison.OrdinalIgnoreCase); + Assert.Contains("persistence/schema planning", table, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("| TBD | TBD | Phase 537: lasso toolbar UX and public activation ergonomics boundary", table, StringComparison.Ordinal); + } + + private static void AssertPostPhase538Queue(string table) + { + Assert.Contains("| #197 | `avalonia-node-map-w9h` | Phase 537: lasso toolbar UX and public activation ergonomics boundary", table, StringComparison.Ordinal); + Assert.Contains("| #199 | `avalonia-node-map-a3w` | Phase 538: eraser behavior/API feasibility gate", table, StringComparison.Ordinal); + Assert.Contains("Phase 539: rectangle/freehand drawing primitive model gate", table, StringComparison.Ordinal); + Assert.Contains("Phase 540: whiteboard persistence and render-layer readiness gate", table, StringComparison.Ordinal); + Assert.Contains("TBD", table, StringComparison.Ordinal); + Assert.Contains("graph-selection deletion evidence", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("Core/Editor model contract", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("persistence/schema planning", table, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("| TBD | TBD | Phase 537: lasso toolbar UX and public activation ergonomics boundary", table, StringComparison.Ordinal); + Assert.DoesNotContain("| TBD | TBD | Phase 538: eraser behavior/API feasibility gate", table, StringComparison.Ordinal); + Assert.DoesNotContain("Current toolbar ergonomics slice", table, StringComparison.OrdinalIgnoreCase); + } + + private static void AssertPhase538WorktreePlan(string plan) + { + Assert.Contains("feature/phase-537-lasso-toolbar-ergonomics", plan, StringComparison.Ordinal); + Assert.Contains("avalonia-node-map-w9h", plan, StringComparison.Ordinal); + Assert.True( + plan.Contains("merged worktree", StringComparison.OrdinalIgnoreCase) + || plan.Contains("已合并", StringComparison.Ordinal), + "Expected Phase 537 worktree plan entry to be marked merged."); + Assert.Contains("feature/phase-538-eraser-feasibility", plan, StringComparison.Ordinal); + Assert.Contains("avalonia-node-map-a3w", plan, StringComparison.Ordinal); + Assert.True( + plan.Contains("current worktree", StringComparison.OrdinalIgnoreCase) + || plan.Contains("当前 worktree", StringComparison.Ordinal), + "Expected Phase 538 worktree plan entry to be marked current."); + Assert.Contains("graph-selection deletion evidence", plan, StringComparison.OrdinalIgnoreCase); + Assert.DoesNotContain("feature/phase-538-eraser-feasibility`: future candidate", plan, StringComparison.Ordinal); } private static void AssertBuiltInComponentMatrix(string table) @@ -1304,7 +1377,7 @@ private static void AssertWhiteboardLassoEraserFeasibilityAudit(string table) Assert.Contains("| Rectangle marquee selection | Present / guarded |", table, StringComparison.Ordinal); Assert.Contains("| Multi-select and command projection | Present / guarded |", table, StringComparison.Ordinal); Assert.Contains("| Lasso/freehand selection | Public Avalonia lasso selection mode with hosted toolbar activation and transient visual feedback / whiteboard gap retained |", table, StringComparison.Ordinal); - Assert.Contains("| Eraser tool | Gap retained |", table, StringComparison.Ordinal); + Assert.Contains("| Eraser tool | Feasibility gate recorded / gap retained |", table, StringComparison.Ordinal); Assert.Contains("| Rectangle/freehand drawing | Gap retained |", table, StringComparison.Ordinal); Assert.Contains("| Whiteboard persistence/render layer | Gap retained |", table, StringComparison.Ordinal); Assert.Contains("https://reactflow.dev/learn/advanced-use/whiteboard", table, StringComparison.Ordinal); @@ -1344,7 +1417,14 @@ private static void AssertWhiteboardLassoEraserFeasibilityAudit(string table) Assert.Contains("selection.select-none", table, StringComparison.Ordinal); Assert.Contains("selection.invert", table, StringComparison.Ordinal); Assert.Contains("selection.delete", table, StringComparison.Ordinal); + Assert.Contains("Delete Selection", table, StringComparison.Ordinal); + Assert.Contains("selection-delete", table, StringComparison.Ordinal); Assert.Contains("selection.transform.move", table, StringComparison.Ordinal); + Assert.Contains("graph-selection deletion", table, StringComparison.OrdinalIgnoreCase); + Assert.Contains("not an eraser cursor", table, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no eraser cursor", table, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no collision trail", table, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no eraser-specific hit-testing", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("public pointer-mode activation route", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("transient visual feedback", table, StringComparison.OrdinalIgnoreCase); Assert.Contains("hosted toolbar", table, StringComparison.OrdinalIgnoreCase); @@ -1464,6 +1544,26 @@ private static string ExtractIssueWaveTable(string contents) return contents[tableStart..nextHeading]; } + private static string ExtractRecommendedWorktreePlan(string contents) + { + var headingStart = contents.IndexOf("\n## Recommended Parallel Worktree Plan", StringComparison.Ordinal); + if (headingStart < 0) + { + headingStart = contents.IndexOf("\n## 推荐并行 Worktree 计划", StringComparison.Ordinal); + } + + Assert.True(headingStart >= 0, "Expected recommended worktree plan heading."); + + var nextHeading = contents.IndexOf("\n## UI Verification Policy", headingStart, StringComparison.Ordinal); + if (nextHeading < 0) + { + nextHeading = contents.IndexOf("\n## UI 验证策略", headingStart, StringComparison.Ordinal); + } + + Assert.True(nextHeading > headingStart, "Expected UI verification heading after recommended worktree plan."); + return contents[headingStart..nextHeading]; + } + private static string ReadRepoFile(string relativePath) => File.ReadAllText(Path.Combine(GetRepositoryRoot(), relativePath));