diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 586ba8b8..d76142ed 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -368,14 +368,14 @@ {"_type":"issue","id":"avalonia-node-map-amv.4","title":"Phase 391: v0.63 Discoverability Handoff","description":"Aggregate v0.63 proof markers, update docs/status, and recommend the next feature or adopter-driven line.","acceptance_criteria":"Project status, requirements, roadmap, feature catalog, quick-start, support-bundle docs, and milestone notes summarize phases 388-390; release closure tests guard v0.63 aggregate markers beside existing evidence; next recommendation is explicit; markers WORKBENCH_DISCOVERABILITY_HANDOFF_OK, WORKBENCH_DISCOVERABILITY_SCOPE_BOUNDARY_OK, V063_MILESTONE_PROOF_OK are covered.","notes":"Starting Phase 391. Scope: aggregate v0.63 layout/discovery/recents-favorites proof markers into project status, feature catalog, quick-start, support-bundle and milestone handoff docs; keep scope boundary explicit and recommend next line without adding runtime/API changes.","status":"closed","priority":2,"issue_type":"feature","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-04-28T15:18:03Z","created_by":"ExplodingUFO","updated_at":"2026-04-28T16:43:11Z","started_at":"2026-04-28T16:36:34Z","closed_at":"2026-04-28T16:43:11Z","close_reason":"Completed Phase 391 v0.63 discoverability handoff. Aggregated layout preset, panel state, unified discovery, and recents/favorites evidence into proof markers, project status, feature catalog, quick-start, support-bundle docs, public checklist, and release closure tests. Verified ConsumerSample proof tests, docs/release closure tests, Release build, and full no-build solution tests.","labels":["discoverability","docs","handoff","layout","milestone","phase-391","v0.63","workbench"],"dependencies":[{"issue_id":"avalonia-node-map-amv.4","depends_on_id":"avalonia-node-map-amv","type":"parent-child","created_at":"2026-04-28T15:18:03Z","created_by":"ExplodingUFO","metadata":"{}"},{"issue_id":"avalonia-node-map-amv.4","depends_on_id":"avalonia-node-map-amv.3","type":"blocks","created_at":"2026-04-28T15:18:56Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-7ig.4","title":"Phase 387: v0.62 Interaction Reliability Handoff","description":"Close v0.62 with aggregate proof, clean docs/status, and a clear recommendation for the next work line.","acceptance_criteria":"Project status, requirements, roadmap, and milestone notes summarize phases 384-386; release closure tests guard aggregate v0.62 markers; next recommendation is explicit; markers INTERACTION_RELIABILITY_HANDOFF_OK, INTERACTION_SCOPE_BOUNDARY_OK, V062_MILESTONE_PROOF_OK are covered.","notes":"Starting Phase 387. Scope: close v0.62 interaction reliability handoff with aggregate markers, status/docs updates, release closure tests, and next-line recommendation; keep this documentation/proof-only unless tests reveal a missing contract.","status":"closed","priority":2,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-04-28T14:17:48Z","created_by":"ExplodingUFO","updated_at":"2026-04-28T15:01:52Z","started_at":"2026-04-28T14:52:43Z","closed_at":"2026-04-28T15:01:52Z","close_reason":"Completed Phase 387 v0.62 interaction reliability handoff. Added aggregate ConsumerSample proof markers, release closure tests, status/checklist/feature catalog/support bundle docs, and explicit v0.63 Workbench Convenience recommendation. Verified focused ConsumerSample/Demo release tests, Release build, and full solution no-build tests.","labels":["docs","handoff","interaction","milestone","phase-387","v0.62","workbench"],"dependencies":[{"issue_id":"avalonia-node-map-7ig.4","depends_on_id":"avalonia-node-map-7ig","type":"parent-child","created_at":"2026-04-28T14:17:47Z","created_by":"ExplodingUFO","metadata":"{}"},{"issue_id":"avalonia-node-map-7ig.4","depends_on_id":"avalonia-node-map-7ig.3","type":"blocks","created_at":"2026-04-28T14:17:50Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-c6a","title":"Infra: Repair bd dolt push Windows path failure","description":"bd dolt push and direct dolt fsck fail on Windows with invalid path CreateFile \\\\F:\\CodeProjects\\DotnetCore\\avalonia-node-map\\.beads\\dolt\\avalonia_node_map\\.dolt\\noms. bd dolt show/test can connect to 127.0.0.1:3306 and git-backed .beads export is pushed, but Dolt CLI remote push needs separate safe repair.","acceptance_criteria":"bd dolt push succeeds without dangling chunk/path errors, bd doctor has no Dolt remote sync error beyond intentional remotesapi configuration, and no project task beads are blocked.","notes":"Starting safe repair. Plan: do not stop Docker; preserve .beads/issues.jsonl as authority; backup local Dolt store; rebuild local store/config so bd dolt push can succeed.\nRepair applied without stopping Docker. Confirmed docker container dolt-sql-server stayed running and bd dolt test connects to 127.0.0.1:3306. Root cause: Windows local CLI mirror under .beads/dolt/avalonia_node_map triggers Dolt path/chunk check failure; the Docker server database at /var/lib/dolt/avalonia_node_map fsck passes. Moved corrupt local mirror to .beads/backup/manual-corrupt-dolt-store-20260428-145716 and left it for recovery evidence. Container-side dolt push origin main succeeded, then normal bd dolt push succeeded once the corrupt local mirror path was absent. Remaining caveat: bd doctor in server mode still warns that CLI remote query cannot chdir to .beads/dolt/avalonia_node_map; this is a doctor/server-mode diagnostic mismatch, tracked separately.","status":"closed","priority":2,"issue_type":"bug","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-04-28T03:34:53Z","created_by":"ExplodingUFO","updated_at":"2026-04-28T07:06:58Z","started_at":"2026-04-28T06:49:54Z","closed_at":"2026-04-28T07:06:58Z","close_reason":"Fixed bd dolt push without stopping Docker. Corrupt Windows local CLI mirror was moved to .beads/backup/manual-corrupt-dolt-store-20260428-145716; Docker server database fsck passed; container dolt push and normal bd dolt push both succeeded. Follow-up avalonia-node-map-pjf tracks bd doctor server-mode CLI remote warning.","defer_until":"2026-04-29T03:34:53Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"avalonia-node-map-71c","title":"Phase 555: whiteboard primitive eraser behavior route","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/229\n\nPhase 538 deliberately kept `selection.delete` scoped to graph-selection deletion evidence and did not implement an eraser cursor, collision trail, or eraser-specific hit-testing. Once Phase 547-554 establish whiteboard primitive state, projection, activation, gesture capture, and Cookbook UX, eraser behavior can be considered as its own narrow behavior slice.\n\nThis phase owns eraser behavior for whiteboard primitives only, without broad graph deletion or full React Flow whiteboard parity claims.\n\n## Scope\nImplement a bounded eraser-on-primitive behavior contract:\n- define how eraser activation is selected separately from graph-selection delete;\n- use primitive hit-testing evidence to remove or mark whiteboard primitives through a controlled edit lifecycle;\n- keep graph node/connection deletion behavior unchanged;\n- add focused tests proving eraser hit-testing, no accidental graph deletion, and cancel/finalize behavior;\n- update docs/Cookbook evidence only as needed for this behavior.\n\n## Out of scope\nNo broad eraser cursor visual redesign, no persisted whiteboard primitive state unless a prior persistence phase has landed, no GraphDocument schema changes, no renderer rewrite, no toolbar redesign beyond necessary activation projection, no retained API removal, and no full React Flow whiteboard parity claim.\n\n## Dependency / stacking\nDepends on Phase 554 and must not merge before the authoring toolbar/Cookbook UX route lands.\r\n","acceptance_criteria":"Eraser behavior targets whiteboard primitives through primitive hit-testing and does not use graph-selection deletion as a proxy; existing graph deletion commands remain unchanged and separately tested; focused tests prove eraser hit-testing, edit lifecycle, and no accidental graph node/connection deletion; verification includes focused eraser behavior tests, affected editor/Avalonia tests, relevant docs/Cookbook tests, and git diff --check.","status":"open","priority":3,"issue_type":"task","owner":"1034917216@qq.com","created_at":"2026-05-13T05:29:24Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T05:29:24Z","external_ref":"gh-229","labels":["enhancement"],"dependencies":[{"issue_id":"avalonia-node-map-71c","depends_on_id":"avalonia-node-map-kpy","type":"blocks","created_at":"2026-05-13T13:29:23Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} +{"_type":"issue","id":"avalonia-node-map-71c","title":"Phase 555: whiteboard primitive eraser behavior route","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/229\n\nPhase 538 deliberately kept `selection.delete` scoped to graph-selection deletion evidence and did not implement an eraser cursor, collision trail, or eraser-specific hit-testing. Once Phase 547-554 establish whiteboard primitive state, projection, activation, gesture capture, and Cookbook UX, eraser behavior can be considered as its own narrow behavior slice.\n\nThis phase owns eraser behavior for whiteboard primitives only, without broad graph deletion or full React Flow whiteboard parity claims.\n\n## Scope\nImplement a bounded eraser-on-primitive behavior contract:\n- define how eraser activation is selected separately from graph-selection delete;\n- use primitive hit-testing evidence to remove or mark whiteboard primitives through a controlled edit lifecycle;\n- keep graph node/connection deletion behavior unchanged;\n- add focused tests proving eraser hit-testing, no accidental graph deletion, and cancel/finalize behavior;\n- update docs/Cookbook evidence only as needed for this behavior.\n\n## Out of scope\nNo broad eraser cursor visual redesign, no persisted whiteboard primitive state unless a prior persistence phase has landed, no GraphDocument schema changes, no renderer rewrite, no toolbar redesign beyond necessary activation projection, no retained API removal, and no full React Flow whiteboard parity claim.\n\n## Dependency / stacking\nDepends on Phase 554 and must not merge before the authoring toolbar/Cookbook UX route lands.\r\n","acceptance_criteria":"Eraser behavior targets whiteboard primitives through primitive hit-testing and does not use graph-selection deletion as a proxy; existing graph deletion commands remain unchanged and separately tested; focused tests prove eraser hit-testing, edit lifecycle, and no accidental graph node/connection deletion; verification includes focused eraser behavior tests, affected editor/Avalonia tests, relevant docs/Cookbook tests, and git diff --check.","notes":"2026-05-13: Claiming Phase 555 implementation prep. Starting stacked worktree .worktrees/phase-555-whiteboard-eraser-behavior from feature/phase-554-whiteboard-authoring-cookbook / PR #234. Scope remains eraser-on-whiteboard-primitives only: no broad eraser cursor visual redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, no toolbar redesign beyond necessary activation projection, no retained API removal, and no full React Flow whiteboard parity claim. Merge remains blocked until Phase 554 / PR #234 and earlier stack land.\n2026-05-13: Implemented Phase 555 in stacked PR https://github.com/ExplodingUFO/AsterGraph/pull/235 against feature/phase-554-whiteboard-authoring-cookbook / PR #234. Commit 1829064 adds NodeCanvasWhiteboardDrawingMode.Eraser, host-source whiteboard-drawing.eraser, PART_WhiteboardEraserButton projection, TryEraseWhiteboardPrimitive(...) hit-test removal, and coordinator press handling that removes only transient whiteboard primitives without invoking graph selection.delete. Local verification passed: AsterGraph.Editor.Tests 880/880, AsterGraph.Demo.Tests 300/300, public API surface validation for Release/net9.0, and git diff --check. PR #235 is MERGEABLE but CI is still running/UNSTABLE at creation time; keep BLOCKED until Phase 554 / PR #234 and lower stack, especially PR #200 required review, land.\n2026-05-13: Remote GitHub CI for PR #235 is all green and PR merge state is CLEAN/MERGEABLE. Checks passed: hygiene-proof, framework-matrix net8.0/net9.0/net10.0, linux-validation, macos-validation, contract-proof, and release-validation. PR remains BLOCKED only for stack ordering behind Phase 554 / PR #234 and lower stack, especially PR #200 required review; do not merge Phase 555 early.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-13T05:29:24Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T10:51:28Z","started_at":"2026-05-13T09:50:48Z","external_ref":"gh-229","labels":["enhancement"],"dependencies":[{"issue_id":"avalonia-node-map-71c","depends_on_id":"avalonia-node-map-kpy","type":"blocks","created_at":"2026-05-13T13:29:23Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-kpy","title":"Phase 554: whiteboard authoring toolbar and Cookbook UX route","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/228\n\nAfter Phase 552 defines public activation and Phase 553 wires pointer gesture capture, users still need a polished hosted authoring UX and Cookbook guidance before the feature is discoverable or demo-quality.\n\nThis phase owns the hosted toolbar and Cookbook UX route for rectangle/freehand whiteboard authoring, with screenshot-backed proof only after the underlying activation and gesture routes exist.\n\n## Scope\nAdd a bounded hosted authoring UX and Cookbook route:\n- project rectangle/freehand authoring actions through the hosted authoring surface;\n- add a Cookbook route that demonstrates the supported authoring flow with minimal, idiomatic sample code;\n- update screenshot/shell proof metadata only as needed for this route;\n- verify non-overlap and professional visual layout for the authored primitive route;\n- document the feature without claiming full React Flow whiteboard parity.\n\n## Out of scope\nNo new core model design, no pointer coordinator redesign, no eraser behavior, no GraphDocument schema changes, no persisted whiteboard primitive claim, no renderer rewrite, no broad UI redesign, no retained API removal, and no full React Flow whiteboard parity claim.\n\n## Dependency / stacking\nDepends on Phase 553 and must not merge before pointer gesture capture exists.\r\n","acceptance_criteria":"Hosted authoring actions expose rectangle/freehand authoring without duplicating selection/lasso controls; Cookbook route loads directly and demonstrates the supported authoring flow; screenshot proof captures the route with non-overlap metadata and stable proof markers; verification includes focused hosted authoring tests, Cookbook/screenshot tests, full relevant test project(s), and git diff --check.","notes":"2026-05-13: Claiming Phase 554 implementation prep. Starting stacked worktree .worktrees/phase-554-whiteboard-authoring-cookbook from feature/phase-553-whiteboard-pointer-gestures / PR #233. Scope: hosted authoring toolbar/Cookbook UX route only; no new core model design, pointer coordinator redesign, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, renderer rewrite, broad UI redesign, retained API removal, or full React Flow whiteboard parity claim. Keep blocked for merge ordering behind Phase 553 / PR #233 and earlier stack.\n2026-05-13: Implemented Phase 554 in stacked PR https://github.com/ExplodingUFO/AsterGraph/pull/234 against feature/phase-553-whiteboard-pointer-gestures / PR #233. Commit 9b1fdb9 adds hosted GraphEditorView rectangle/freehand drawing toolbar projection, Cookbook route whiteboard-authoring-cookbook-route, screenshot route cookbook-whiteboard-authoring-cookbook-route, shell state shell-cookbook-whiteboard-authoring-cookbook-route, bilingual docs, and focused tests. Local verification passed: AsterGraph.Editor.Tests 877/877, AsterGraph.Demo.Tests 299/299, Cookbook|ReactFlowParityRoadmapDocsTests 140/140, focused shell/public-doc/Phase554/catalog tests 10/10, public API surface validation for Release/net9.0, git diff --check, and public-doc prohibited-term grep with no matches. Keep BLOCKED until Phase 553 / PR #233 and earlier stack land; do not merge Phase 554 out of order.\n2026-05-13: Remote GitHub CI for PR #234 is all green and PR merge state is CLEAN. Checks passed: hygiene-proof, framework-matrix net8.0/net9.0/net10.0, linux-validation, macos-validation, contract-proof, and release-validation. PR remains BLOCKED only for stack ordering behind Phase 553 / PR #233 and earlier stack; do not merge Phase 554 early.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-13T05:29:10Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T08:57:22Z","started_at":"2026-05-13T07:30:19Z","external_ref":"gh-228","labels":["enhancement"],"dependencies":[{"issue_id":"avalonia-node-map-kpy","depends_on_id":"avalonia-node-map-9f0","type":"blocks","created_at":"2026-05-13T13:29:10Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-wjr","title":"Phase 550: whiteboard primitive Cookbook screenshot implementation gate","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/223\n\nPhase 547 / PR #218 added the first internal renderer-neutral whiteboard primitive model skeleton. Phase 548 / PR #220 adds the first internal renderer-neutral renderer adapter and hit-testing skeleton. Phase 549 / PR #222 adds the persistence decision gate that keeps current whiteboard primitives outside the current `GraphDocument` schema and records a separate annotation surface decision.\n\nThe next tracker-backed slice in the React Flow parity roadmap is Phase 550: a whiteboard primitive Cookbook screenshot implementation gate. This must provide visual-proof plumbing for future whiteboard primitive examples without widening runtime drawing/tool activation claims or adding unproven persisted whiteboard state.\n\n## Scope\nAdd a bounded Cookbook/screenshot implementation gate after Phase 549:\n- define the minimum Cookbook route and screenshot manifest contract needed to prove future whiteboard primitive visual evidence;\n- add focused docs/tests that require Phase 550 tracker IDs and preserve stack ordering behind Phase 549;\n- if implementation remains proof-only, use existing fixture/catalog routes and metadata rather than adding runtime drawing state;\n- keep route metadata, shell state, before/after evidence expectations, and non-overlap requirements explicit;\n- keep any Avalonia pointer coordinator, toolbar activation, eraser behavior, persisted state, public drawing API, and full whiteboard parity claim as separate follow-ups.\n\n## Out of scope\nNo new public drawing API, no pointer coordinator edits, no toolbar/tool activation, no eraser behavior, no persisted whiteboard primitive state, no `GraphDocument` schema change, no schema version bump, no renderer rewrite, no UI redesign, no retained API removal, and no full React Flow whiteboard parity claim.\n\nNo screenshot manifest expansion should be merged unless focused failing tests prove the exact Cookbook/screenshot contract and the PR body calls out route metadata, shell state, and visual-proof boundaries explicitly.\n\n## Dependency / stacking\nDepends on Phase 549 / PR #222 and therefore on the earlier Phase 537-549 stack. This may be implemented as a stacked branch based on `feature/phase-549-whiteboard-persistence-decision`, but it must not merge before PR #222 and the earlier stack land.","acceptance_criteria":"Focused tests prove the Phase 550 Cookbook/screenshot contract and route metadata boundary; docs/tests replace the Phase 550 TBD row with GitHub #223 and this Beads ID; any screenshot route or shell-state manifest change is explicitly covered by tests and metadata expectations; tests/docs prove the slice does not add public drawing APIs, pointer coordinators, toolbar activation, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, schema version bumps, renderer rewrites, UI redesign, retained API removal, or a full React Flow whiteboard parity claim; verification includes focused screenshot/Cookbook tests, focused ReactFlowParityRoadmapDocsTests coverage, full AsterGraph.Demo.Tests, Release build, and git diff --check.","notes":"2026-05-13: Created as Phase 550 tracker after GitHub #223. Blocked for stack ordering behind Phase 549 / PR #222 and earlier stack; implementation may prepare on a stacked branch but must not merge before Phase 549 lands.\n2026-05-13: Created Phase 550 worktree .worktrees/phase-550-whiteboard-cookbook-screenshot-gate on branch feature/phase-550-whiteboard-cookbook-screenshot-gate from origin/feature/phase-549-whiteboard-persistence-decision. Baseline passed: ReactFlowParityRoadmapDocsTests 46/46 and DemoCookbookScreenshotGateTests 13/13 after rerunning once because the first concurrent run hit a build file-lock on AsterGraph.Abstractions.dll. Keep BLOCKED for stack ordering behind Phase 549 / PR #222 and earlier stack.\n2026-05-13: Implemented Phase 550 on commit ba47a68 and opened stacked PR https://github.com/ExplodingUFO/AsterGraph/pull/224 against feature/phase-549-whiteboard-persistence-decision. Added proof-only Cookbook recipe `whiteboard-primitive-screenshot-proof-route`, scene route `cookbook-whiteboard-primitive-screenshot-proof`, shell state `shell-cookbook-whiteboard-primitive-screenshot-proof`, bilingual docs, and focused tests. Verification passed: focused Phase 550 roadmap test; focused Phase 550 screenshot route test; ReactFlowParityRoadmapDocsTests 47/47; DemoCookbookDocsTests + DemoCookbookCatalogTests 18/18; DemoCookbookScreenshotGateTests 14/14; ShellVisualCoveragePlanningDocsTests 7/7; PublicDocs_DoNotNameExternalInspirationProjects 1/1; full AsterGraph.Demo.Tests 290/290; `dotnet build AsterGraph.sln -c Release -v:minimal` 0 warnings/0 errors; `git diff --check`. PR #224 remains BLOCKED / unstable until Phase 549 PR #222 and earlier stack land; do not merge early.\n2026-05-13: Restacked PR #224 onto updated Phase 549 / PR #222 after Phase 549 was rebased. New head bcd8a5b986245161cb42a2986b810499d95ae077; GitHub PR #224 reports MERGEABLE/CLEAN. GitHub CI passed for hygiene-proof, framework-matrix net8.0/net9.0/net10.0, linux-validation, macos-validation, contract-proof, and release-validation on the new head. Local verification passed after rebase: focused Phase 550 screenshot/roadmap tests 2/2, ReactFlowParityRoadmapDocsTests 50/50, Cookbook screenshot/docs/catalog/shell/public-doc gate tests 40/40, Release build 0 warnings/0 errors, full AsterGraph.Demo.Tests 293/293, and git diff --check clean. Keep BLOCKED until PR #222 and earlier stack land; do not merge Phase 550 out of order.","status":"blocked","priority":3,"issue_type":"task","owner":"1034917216@qq.com","created_at":"2026-05-13T00:11:00Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T05:02:25Z","external_ref":"gh-223","labels":["enhancement","phase-550","screenshot","whiteboard"],"dependencies":[{"issue_id":"avalonia-node-map-wjr","depends_on_id":"avalonia-node-map-3l6","type":"blocks","created_at":"2026-05-13T08:11:50Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-3l6","title":"Phase 549: whiteboard primitive persistence decision implementation gate","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/221\n\nPhase 547 / PR #218 added the first internal renderer-neutral whiteboard primitive model skeleton. Phase 548 / PR #220 adds the first internal renderer-neutral renderer adapter and hit-testing skeleton. The next tracker-backed slice in the parity roadmap is Phase 549: a whiteboard primitive persistence decision implementation gate.\n\nPhase 544 already recorded the policy gate: first-class drawing state must explicitly choose between the current `GraphDocument` schema and a separate annotation surface before any saved whiteboard primitive claim. Phase 549 should make that decision executable and test-backed without widening public API or visual parity claims.\n\n## Scope\nAdd a narrow persistence-decision implementation gate after Phase 548:\n- define the minimal internal decision/policy contract for whiteboard primitive persistence ownership;\n- prove with focused tests whether the current slice keeps whiteboard primitives out of `GraphDocument` schema or deliberately chooses a separate annotation surface;\n- prove `GraphDocumentSerializer`, `GraphDocumentCompatibility`, and current schema-version behavior remain graph-document scoped unless this issue explicitly owns a schema change;\n- document migration criteria and compatibility coverage required before any future persisted whiteboard primitive state is allowed;\n- update EN/ZH parity roadmap docs with this GitHub issue and Beads identifiers;\n- keep Phase 550 Cookbook screenshot implementation and any runtime drawing/tool activation as separate tracker-backed follow-ups.\n\n## Out of scope\nNo public drawing API claim, no Avalonia pointer coordinator edits, no toolbar/tool activation, no eraser behavior, no screenshot manifest expansion, no Cookbook visual proof implementation, no renderer rewrite, no UI redesign, no retained API removal, and no full React Flow whiteboard parity claim.\n\nNo `GraphDocument` schema change, schema version bump, public API baseline change, or workspace persistence behavior change is allowed unless focused failing tests prove the exact missing persistence-decision contract and the PR body calls out the schema/migration impact explicitly.\n\n## Dependency / stacking\nDepends on Phase 548 / PR #220 and therefore on the earlier Phase 537-548 stack. This may be implemented as a stacked branch based on `feature/phase-548-whiteboard-renderer-adapter-skeleton`, but it must not merge before PR #220 and the earlier stack land.","acceptance_criteria":"Focused tests prove the internal whiteboard persistence decision contract and storage ownership boundary; tests prove current GraphDocument serialization remains unchanged unless this PR explicitly owns a schema version change and migration policy; tests or docs prove GraphDocumentSerializer, GraphDocumentCompatibility, workspace persistence, clipboard fragments, screenshot artifacts, renderer projection, and public drawing APIs remain separate from persisted whiteboard primitive state in this slice; EN/ZH parity roadmap docs replace the Phase 549 TBD row with GitHub #221 and this Beads ID while keeping Phase 550 as a future tracker-backed follow-up; verification includes focused new persistence-decision tests, focused ReactFlowParityRoadmapDocsTests coverage, full AsterGraph.Demo.Tests, Release build, and git diff --check.","notes":"2026-05-13: Implementation branch pushed and stacked PR opened: https://github.com/ExplodingUFO/AsterGraph/pull/222. Verification passed: RED first failed on missing persistence decision types; focused Phase 549 persistence decision tests 2/2; focused Editor persistence/renderer/serialization tests 30/30; focused ReactFlowParityRoadmapDocsTests 46/46; full AsterGraph.Demo.Tests 288/288; dotnet build AsterGraph.sln -c Release -v:minimal (0 warnings, 0 errors); git diff --check exit 0 with LF-to-CRLF notices only. PR #222 targets feature/phase-548-whiteboard-renderer-adapter-skeleton and remains BLOCKED for stack ordering behind Phase 548 / PR #220 and earlier stack.\n2026-05-13: Restacked PR #222 onto updated Phase 548 / PR #220 after Phase 548 was rebased. New head 99937c8a3f05150deb2c7679fb8c24fffe54978a; GitHub PR #222 reports MERGEABLE/CLEAN. GitHub CI passed for hygiene-proof, framework-matrix net8.0/net9.0/net10.0, linux-validation, macos-validation, contract-proof, and release-validation on the new head, replacing the earlier stale failed push-run state. Local verification passed after rebase: WhiteboardPrimitivePersistenceDecisionContractsTests 2/2, ReactFlowParityRoadmapDocsTests 49/49, Release build 0 warnings/0 errors, full AsterGraph.Demo.Tests 291/291, and git diff --check clean. Keep BLOCKED until PR #220 and earlier stack land; do not merge Phase 549 out of order.","status":"blocked","priority":3,"issue_type":"task","owner":"1034917216@qq.com","created_at":"2026-05-12T23:47:55Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T04:48:54Z","external_ref":"gh-221","labels":["enhancement","persistence","phase-549","whiteboard"],"dependencies":[{"issue_id":"avalonia-node-map-3l6","depends_on_id":"avalonia-node-map-10p","type":"blocks","created_at":"2026-05-13T07:48:03Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-b31","title":"Phase 542: whiteboard primitive core model contract gate","description":"## Context\nPhase 539 records the rectangle/freehand drawing primitive model gate and Phase 540 records persistence/render-layer readiness. The first implementation-adjacent slice must define the core model contract before any UI or renderer behavior is added.\n\n## Scope\nDefine a narrow future contract for first-class whiteboard primitives:\n- decide where model identity, geometry, style/brush state, and edit lifecycle metadata belong;\n- separate graph nodes/connections/groups from rectangle/freehand annotation primitives;\n- define tests/docs required before adding any production model type or public API;\n- keep renderer, persistence, and pointer behavior as follow-up work unless this issue explicitly proves a smaller safe write set.\n\n## Out of scope\nNo runtime UI behavior, no renderer work, no persistence/schema migration, no screenshot manifest expansion, no toolbar/tool activation, no eraser behavior, no retained API removal, and no full React Flow whiteboard parity claim.\n\n## Dependency\nDepends on Phase 541 and the Phase 540 readiness gate.","acceptance_criteria":"The issue remains blocked until Phase 541 lands; it has a narrow model-contract write set; acceptance requires source-backed docs/tests before any model/API implementation; non-goals explicitly exclude renderer, persistence, pointer coordinator, screenshot manifest, and full whiteboard parity work.","notes":"2026-05-13: Created as future post-Phase-541 follow-up. Keep blocked until Phase 541 lands and stack ordering is resolved.\n2026-05-13: Started Phase 542 as a stacked docs/tests-only model-contract gate on top of Phase 541 / PR #210. Scope remains model contract evidence only: no runtime UI behavior, no renderer work, no persistence/schema migration, no screenshot manifest expansion, no toolbar/tool activation, no eraser behavior, no retained API removal, and no full React Flow whiteboard parity claim.\n2026-05-13: Implemented docs/tests-only Phase 542 model-contract gate in PR #211 (https://github.com/ExplodingUFO/AsterGraph/pull/211) on stacked base docs/phase-541-post-whiteboard-wave-split / PR #210. Local verification passed: focused Phase 542 roadmap-doc test, full ReactFlowParityRoadmapDocsTests, full AsterGraph.Demo.Tests, and git diff --check. PR is mergeable but CI was still in progress at creation check; keep blocked on PR #211 review/CI and stack ordering behind PR #210/#204/#202/#200/#198.\n2026-05-13: Restacked PR #211 onto updated docs/phase-541-post-whiteboard-wave-split / PR #210 after Phase 541 was rebased. New head e3858ff; PR is CLEAN/MERGEABLE with all GitHub checks passing. Local verification passed: focused Phase 542 roadmap-doc test, full ReactFlowParityRoadmapDocsTests, full AsterGraph.Demo.Tests, and git diff --check. Still do not merge before PR #210 / Phase 541 and earlier stack.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T21:29:58Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T03:03:38Z","started_at":"2026-05-12T21:46:24Z","external_ref":"gh-206","labels":["documentation"],"dependencies":[{"issue_id":"avalonia-node-map-b31","depends_on_id":"avalonia-node-map-2z1","type":"blocks","created_at":"2026-05-13T05:30:07Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-2z1","title":"Phase 541: post-Phase-540 whiteboard implementation wave split","description":"## Context\nPhase 540 is tracked by GitHub #203 / `avalonia-node-map-91b` and PR #204. It records the readiness gate for future whiteboard persistence and render-layer work, but the roadmap still needs a concrete tracker-backed implementation wave after that gate.\n\nAsterGraph must not jump directly from readiness wording into broad whiteboard implementation. The next step is a docs/tests-only queue split that converts the remaining whiteboard pressure into small, dependency-aware issues with clear write sets and merge ordering.\n\n## Scope\nCreate the post-Phase-540 implementation wave split:\n- inspect the current EN/ZH React Flow parity roadmap and Phase 540 readiness criteria;\n- identify the smallest next tracker-backed slices for model contract, renderer/hit-testing proof, persistence/schema policy, and Cookbook/screenshot proof;\n- update EN/ZH parity docs with GitHub issue and Beads identifiers for the new wave;\n- preserve stack ordering behind Phase 540 / PR #204;\n- add focused docs tests that fail if the roadmap leaves the next whiteboard implementation wave implicit or TBD.\n\n## Out of scope\nNo runtime behavior changes, no public API changes, no model/schema changes, no renderer-layer changes, no screenshot manifest expansion, no Avalonia pointer coordinator edits, no UI redesign, no drawing tool implementation, no eraser behavior, no toolbar work, no retained API removal, and no full React Flow whiteboard parity claim.\n\n## Dependency / stacking\nDepends on Phase 540 / PR #204. May be implemented as a stacked docs/test branch based on `docs/phase-540-whiteboard-persistence-render-gate`, but must not merge before Phase 540.","acceptance_criteria":"EN/ZH parity docs record Phase 541 with GitHub issue and Beads ID; the roadmap converts the post-Phase-540 whiteboard pressure into tracker-backed follow-up rows with concrete GitHub and Beads IDs; each follow-up row has a narrow write set, dependency/parallelism guidance, and explicit non-goal boundaries; focused docs tests guard the new wave in both locales and fail if the next whiteboard implementation wave remains TBD; verification includes focused docs tests, full ReactFlowParityRoadmapDocsTests, full AsterGraph.Demo.Tests, and git diff --check.","notes":"2026-05-13: Started Phase 541 as a stacked docs/tests-only roadmap split after Phase 540 / PR #204. Scope is to update EN/ZH parity docs with concrete tracker-backed Phase 542-545 rows; no runtime/API/model/schema/renderer/screenshot/UI changes.\n2026-05-13: Implemented docs/tests-only Phase 541 split in PR #210 (https://github.com/ExplodingUFO/AsterGraph/pull/210) on stacked base docs/phase-540-whiteboard-persistence-render-gate / PR #204. Local verification passed: focused Phase 541 roadmap-doc test, full ReactFlowParityRoadmapDocsTests, full AsterGraph.Demo.Tests, and git diff --check. PR is mergeable but CI was still in progress at creation check; keep blocked on PR #210 review/CI and stack ordering behind PR #204/#202/#200/#198.\n2026-05-13: Restacked PR #210 onto updated docs/phase-540-whiteboard-persistence-render-gate / PR #204 after resolving roadmap docs/test conflicts. New head 61faa0b; PR is CLEAN/MERGEABLE with all GitHub checks passing. Still do not merge before PR #204 / Phase 540 and earlier stack.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T21:29:54Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T02:46:10Z","started_at":"2026-05-12T21:30:42Z","external_ref":"gh-205","labels":["documentation"],"dependencies":[{"issue_id":"avalonia-node-map-2z1","depends_on_id":"avalonia-node-map-91b","type":"blocks","created_at":"2026-05-13T05:29:55Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":4,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-rwr","title":"Phase 539: rectangle/freehand drawing primitive model gate","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/201\n\nPhase 537 and Phase 538 are implemented as PR #198 and PR #200, but both are waiting on required review. The next non-overlapping React Flow whiteboard follow-up in the parity roadmap is Phase 539: rectangle/freehand drawing primitive model gate.\n\nReact Flow treats Rectangle draw and Freehand draw as distinct whiteboard examples. AsterGraph currently has rectangle marquee selection, lasso selection evidence, selection deletion evidence, and Cookbook screenshot proof for lasso feedback, but it does not have drawing primitives, shape lifecycle, brush/color state, persistence, renderer-layer support, or a public whiteboard drawing API.\n\n## Scope\nCreate a bounded docs/tests feasibility gate for the rectangle/freehand drawing primitive model:\n- inventory existing graph model, editor command, selection, and Cookbook evidence that could be reused for future drawing primitives;\n- record the exact boundary between selection rectangles/lasso paths and actual rectangle/freehand drawing tools;\n- decide what minimal future model/API contract would be required before any drawing behavior is implemented;\n- update EN/ZH React Flow parity roadmap docs with GitHub issue and Beads identifiers;\n- add focused docs tests that fail if the roadmap claims rectangle/freehand drawing parity prematurely;\n- update the Next Issue Wave so Phase 539 is no longer TBD while preserving Phase 540 as future work.\n\n## Out of scope\nNo runtime behavior changes, no public API changes, no Avalonia pointer coordinator edits, no renderer-layer changes, no persistence/schema changes, no screenshot manifest expansion, no UI redesign, no eraser behavior, no toolbar work, no retained API removal, and no full React Flow whiteboard parity claim.","acceptance_criteria":"EN/ZH parity docs record Phase 539 with GitHub #201 and this bead ID; docs explicitly separate rectangle marquee selection and lasso selection evidence from rectangle/freehand drawing primitives; docs identify the minimum future contract needed for drawing primitives, including model identity, geometry, style/brush state, hit-testing/edit lifecycle, renderer projection, persistence, and Cookbook/screenshot evidence; focused docs tests guard the Phase 539 boundary in both locales and fail if docs imply rectangle/freehand draw parity is already supported; Next Issue Wave replaces the Phase 539 TBD row while preserving Phase 540 as future persistence/render-layer readiness work; verification includes focused docs tests, full AsterGraph.Demo.Tests, and git diff whitespace checks.","notes":"2026-05-13: Started Phase 539 from GitHub #201. Scope is docs/tests-only rectangle/freehand drawing primitive model gate; avoid PR #198 hosted toolbar files and PR #200 eraser wording where possible; no runtime/API/UI/pointer coordinator/renderer/persistence changes.\n2026-05-13: PR https://github.com/ExplodingUFO/AsterGraph/pull/202 opened for Phase 539. Local verification passed: focused Phase 539 docs test, full ReactFlowParityRoadmapDocsTests, full AsterGraph.Demo.Tests, and git diff --check. GitHub CI is green; mergeStateStatus=BLOCKED because reviewDecision=REVIEW_REQUIRED.\n2026-05-13: After Phase 538 CI recovery/tracker commit, PR #202 reports mergeable=CONFLICTING / mergeStateStatus=DIRTY against master despite CI still green. Scratch rebase rehearsal in .worktrees/scratch-phase-539-rebase-check showed conflicts only in docs/en/phase-0-reactflow-parity-audit.md, docs/zh-CN/phase-0-reactflow-parity-audit.md, and tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs. Expected resolution is to preserve Phase 537 merged wording, Phase 538 current/graph-selection deletion wording, and Phase 539 as the next stacked gate, then cascade/restack later PRs. Do not merge PR #202 before PR #200; avoid partial restack until review/admin decision on PR #200 is resolved.\n2026-05-13: Restacked PR #202 onto feature/phase-538-eraser-feasibility / PR #200 after resolving roadmap docs/test conflicts. New head fe178ca; PR is CLEAN/MERGEABLE with all GitHub checks passing. Still do not merge before PR #200.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T20:35:46Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T02:05:10Z","started_at":"2026-05-12T20:37:03Z","external_ref":"gh-201","labels":["documentation"],"dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"avalonia-node-map-a3w","title":"Phase 538: eraser behavior/API feasibility gate","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/199\n\nPhase 537 is implemented in PR #198 but is blocked by required review. The parity roadmap still identifies the next independent whiteboard/lasso candidate as Phase 538: eraser behavior/API feasibility gate.\n\nReact Flow's whiteboard track treats Eraser as a distinct advanced behavior. AsterGraph currently has graph selection/delete commands and lasso/marquee selection evidence, but it must not claim eraser parity until the API and behavior boundary is explicitly analyzed and guarded.\n\n## Scope\nCreate a bounded feasibility gate for eraser behavior/API that answers what AsterGraph can safely expose next without inventing a broad whiteboard system:\n- inspect existing selection/delete commands and Avalonia hit-testing seams;\n- decide whether eraser should remain a documented gap, become a command/API proposal, or get a minimal tracker-backed route;\n- add focused docs/tests that record the exact boundary and prevent accidental eraser parity claims;\n- update EN/ZH parity docs and public API/Cookbook guidance only as needed;\n- avoid overlapping Phase 537's hosted toolbar implementation and avoid changing `NodeCanvas.SelectionMode` unless the gate proves it is necessary.\n\n## Out of scope\nNo drawing primitives, no persistence, no renderer rewrite, no strict pixel baselines, no retained API removal, no full whiteboard parity, and no broad UI redesign. Do not implement a full eraser cursor/trail unless this gate first proves the minimal API/behavior contract and verification route.\n\n## Dependencies / Parallelism\nCan run while PR #198 waits for review if the implementation avoids Phase 537's hosted toolbar files and avoids shared pointer-mode state edits. It should not merge over PR #198 without checking current `master` and the PR state.","acceptance_criteria":"The repository records Phase 538 with GitHub #199 and this bead ID in EN/ZH parity docs; focused tests prove the eraser feasibility boundary and fail if docs claim full React Flow whiteboard/eraser parity prematurely; existing `selection.delete` behavior is explicitly reused as graph-selection deletion evidence or separated from eraser tool behavior with clear wording; Next Issue Wave removes Phase 538 as TBD while preserving Phase 539-540 as future tracker-backed work; verification includes focused docs tests plus any focused editor/Avalonia tests required by the chosen boundary.","notes":"2026-05-13: PR #200 is open: https://github.com/ExplodingUFO/AsterGraph/pull/200. Fresh local checks passed: focused Phase 538 docs test, full AsterGraph.Demo.Tests 279/279, and git diff --check. GitHub CI is green. Merge is blocked only by branch protection review requirement: reviewDecision=REVIEW_REQUIRED, mergeStateStatus=BLOCKED, mergeable=MERGEABLE. Keep worktree .worktrees/phase-538-eraser-feasibility and branch feature/phase-538-eraser-feasibility pending review. Do not admin-bypass without explicit authorization.\n2026-05-13: Amended PR #200 to d05ab2a after CI exposed stale Phase 537 roadmap guard wording. Local focused Phase 537/538 roadmap-doc tests now pass, git diff --check reported only the existing LF-to-CRLF warning, and GitHub CI is green. Remaining blocker is reviewDecision=REVIEW_REQUIRED; do not admin-bypass without explicit authorization.\n2026-05-13: Stack audit after restacking Phases 547-550 confirms PR #200 remains the lowest open stack blocker: PR #198 is already MERGED, PR #200 is MERGEABLE/BLOCKED only by REVIEW_REQUIRED with all GitHub checks passing, and downstream PRs #202/#204/#210/#211/#212/#213/#214/#216/#218/#220/#222/#224 are CLEAN/MERGEABLE with GitHub checks passing. Keep Phase 538 BLOCKED pending required review; do not admin-bypass or merge out of order without explicit authorization.\n2026-05-13: Fresh PR #200 review pass found no correctness issues in the docs/test-only Phase 538 boundary diff. Verified in .worktrees/phase-538-eraser-feasibility with focused Phase 538 docs test, full AsterGraph.Demo.Tests 281/281, dotnet build AsterGraph.sln -c Release, and git diff --check. Posted readiness note at https://github.com/ExplodingUFO/AsterGraph/pull/200#issuecomment-4437543013. Remaining blocker is still reviewDecision=REVIEW_REQUIRED; do not admin-bypass or merge out of order without explicit authorization.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T20:09:55Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T05:17:59Z","started_at":"2026-05-12T20:10:02Z","external_ref":"gh-199","labels":["documentation"],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"avalonia-node-map-a3w","title":"Phase 538: eraser behavior/API feasibility gate","description":"## Context\nGitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/199\n\nPhase 537 is implemented in PR #198 but is blocked by required review. The parity roadmap still identifies the next independent whiteboard/lasso candidate as Phase 538: eraser behavior/API feasibility gate.\n\nReact Flow's whiteboard track treats Eraser as a distinct advanced behavior. AsterGraph currently has graph selection/delete commands and lasso/marquee selection evidence, but it must not claim eraser parity until the API and behavior boundary is explicitly analyzed and guarded.\n\n## Scope\nCreate a bounded feasibility gate for eraser behavior/API that answers what AsterGraph can safely expose next without inventing a broad whiteboard system:\n- inspect existing selection/delete commands and Avalonia hit-testing seams;\n- decide whether eraser should remain a documented gap, become a command/API proposal, or get a minimal tracker-backed route;\n- add focused docs/tests that record the exact boundary and prevent accidental eraser parity claims;\n- update EN/ZH parity docs and public API/Cookbook guidance only as needed;\n- avoid overlapping Phase 537's hosted toolbar implementation and avoid changing `NodeCanvas.SelectionMode` unless the gate proves it is necessary.\n\n## Out of scope\nNo drawing primitives, no persistence, no renderer rewrite, no strict pixel baselines, no retained API removal, no full whiteboard parity, and no broad UI redesign. Do not implement a full eraser cursor/trail unless this gate first proves the minimal API/behavior contract and verification route.\n\n## Dependencies / Parallelism\nCan run while PR #198 waits for review if the implementation avoids Phase 537's hosted toolbar files and avoids shared pointer-mode state edits. It should not merge over PR #198 without checking current `master` and the PR state.","acceptance_criteria":"The repository records Phase 538 with GitHub #199 and this bead ID in EN/ZH parity docs; focused tests prove the eraser feasibility boundary and fail if docs claim full React Flow whiteboard/eraser parity prematurely; existing `selection.delete` behavior is explicitly reused as graph-selection deletion evidence or separated from eraser tool behavior with clear wording; Next Issue Wave removes Phase 538 as TBD while preserving Phase 539-540 as future tracker-backed work; verification includes focused docs tests plus any focused editor/Avalonia tests required by the chosen boundary.","notes":"2026-05-13: PR #200 is open: https://github.com/ExplodingUFO/AsterGraph/pull/200. Fresh local checks passed: focused Phase 538 docs test, full AsterGraph.Demo.Tests 279/279, and git diff --check. GitHub CI is green. Merge is blocked only by branch protection review requirement: reviewDecision=REVIEW_REQUIRED, mergeStateStatus=BLOCKED, mergeable=MERGEABLE. Keep worktree .worktrees/phase-538-eraser-feasibility and branch feature/phase-538-eraser-feasibility pending review. Do not admin-bypass without explicit authorization.\n2026-05-13: Amended PR #200 to d05ab2a after CI exposed stale Phase 537 roadmap guard wording. Local focused Phase 537/538 roadmap-doc tests now pass, git diff --check reported only the existing LF-to-CRLF warning, and GitHub CI is green. Remaining blocker is reviewDecision=REVIEW_REQUIRED; do not admin-bypass without explicit authorization.\n2026-05-13: Stack audit after restacking Phases 547-550 confirms PR #200 remains the lowest open stack blocker: PR #198 is already MERGED, PR #200 is MERGEABLE/BLOCKED only by REVIEW_REQUIRED with all GitHub checks passing, and downstream PRs #202/#204/#210/#211/#212/#213/#214/#216/#218/#220/#222/#224 are CLEAN/MERGEABLE with GitHub checks passing. Keep Phase 538 BLOCKED pending required review; do not admin-bypass or merge out of order without explicit authorization.\n2026-05-13: Fresh PR #200 review pass found no correctness issues in the docs/test-only Phase 538 boundary diff. Verified in .worktrees/phase-538-eraser-feasibility with focused Phase 538 docs test, full AsterGraph.Demo.Tests 281/281, dotnet build AsterGraph.sln -c Release, and git diff --check. Posted readiness note at https://github.com/ExplodingUFO/AsterGraph/pull/200#issuecomment-4437543013. Remaining blocker is still reviewDecision=REVIEW_REQUIRED; do not admin-bypass or merge out of order without explicit authorization.\n2026-05-13: Human decision needed to unblock stack. PR #200 is the lowest open PR in the whiteboard stack and is MERGEABLE with all GitHub checks passing, but mergeStateStatus remains BLOCKED because reviewDecision=REVIEW_REQUIRED. Repository collaborators list only ExplodingUFO, PR has no review request target, classic branch protection endpoint reports not protected, ruleset default-main is active, and non-admin auto-merge failed because repository auto-merge is disabled. Options: provide required GitHub review/approval for PR #200, explicitly authorize admin bypass, or add an eligible reviewer. Do not merge downstream PRs #202-#234 until #200 is resolved.","status":"blocked","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T20:09:55Z","created_by":"ExplodingUFO","updated_at":"2026-05-13T09:18:37Z","started_at":"2026-05-12T20:10:02Z","external_ref":"gh-199","labels":["documentation","human"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-9ow","title":"Phase 528: Panel versus viewport-attached overlay boundary","description":"Replace the Phase 528 TBD roadmap entry with a guarded docs/tests-only gate defining the boundary between the current standalone AsterGraphPanel primitive and broader viewport-attached overlay parity claims. Acceptance: EN/ZH parity docs replace the TBD row with GitHub issue gh-179 and this bead id; docs cover AsterGraphPanel, AsterGraphPanelPosition, nine placement values, Offset, Padding, CornerRadius, host-owned content composition, focus boundary, built-in catalog/Cookbook route, and screenshot route; docs keep the claim partial/guarded with no full React Flow Panel parity, no new viewport runtime, no panel persistence, no remote sync, no shell dependency, and no workflow engine; focused roadmap docs guard fails before docs update and passes after; no runtime/API/UI/manifest/screenshot changes.","status":"closed","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T10:05:12Z","created_by":"ExplodingUFO","updated_at":"2026-05-12T10:47:48Z","started_at":"2026-05-12T10:05:47Z","closed_at":"2026-05-12T10:47:48Z","close_reason":"Completed by PR #180 merged as 3295f85: bilingual Phase 528 Panel overlay boundary docs/tests record GitHub #179 / avalonia-node-map-9ow, replace the TBD row, and keep the claim guarded with no runtime/API/UI/screenshot manifest changes.","external_ref":"gh-179","labels":["documentation"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-dim","title":"Phase 527: Background variant public surface gate","description":"Docs/tests-only Phase 527 parity gate for Background/Grid variant public surface coverage.\n\nAcceptance criteria:\n- English and Chinese parity audit docs replace the Phase 527 TBD row with GitHub issue #177 and this bead ID.\n- Docs define the Background variant public surface gate covering current GridBackground line-grid rendering, CanvasStyleOptions grid tokens, bounded line-density behavior, snap-to-grid/session command evidence, built-in catalog/Cookbook route, and screenshot-gate coverage.\n- Claim remains partial/guarded while retaining dots/lines/cross variants, gap/size public API policy, background graph indexing, second renderer/new layout runtime, and full React Flow Background parity as explicit gaps.\n- No runtime/API/UI/manifest/screenshot changes are included.\n- Focused docs guard test fails before the docs update and passes after.","status":"closed","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T09:24:25Z","created_by":"ExplodingUFO","updated_at":"2026-05-12T09:52:01Z","started_at":"2026-05-12T09:24:42Z","closed_at":"2026-05-12T09:52:01Z","close_reason":"Phase 527 merged via PR #178","external_ref":"gh-177","labels":["documentation"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"avalonia-node-map-ayx","title":"Phase 521: define strict pixel-baseline comparator readiness gate","description":"GitHub issue: https://github.com/ExplodingUFO/AsterGraph/issues/163\n\nTurn the Phase 515 strict pixel-baseline deferral into a concrete readiness gate for any future host-keyed or tolerant comparator. Scope is docs/tests only; no strict enforcement, shell visual manifest additions, visual redesign, runtime behavior change, or public API change.","acceptance_criteria":"Docs specify the readiness contract for strict pixel-baseline comparator work; current artifacts preserve StrictPixelBaselineEnforced=false; focused docs tests guard the no-enforcement boundary; git diff --check passes.","status":"closed","priority":3,"issue_type":"task","assignee":"ExplodingUFO","owner":"1034917216@qq.com","created_at":"2026-05-12T04:42:16Z","created_by":"ExplodingUFO","updated_at":"2026-05-12T05:53:50Z","started_at":"2026-05-12T05:34:13Z","closed_at":"2026-05-12T05:53:50Z","close_reason":"Completed by GitHub PR #167 merged as 9e2d3f961350b9e6b6367380c21cd3d7658a1e83; issue #163 closed.","external_ref":"gh-163","labels":["docs","phase-521","roadmap"],"dependencies":[{"issue_id":"avalonia-node-map-ayx","depends_on_id":"avalonia-node-map-rs5","type":"blocks","created_at":"2026-05-12T12:43:09Z","created_by":"ExplodingUFO","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} diff --git a/docs/en/authoring-surface-recipe.md b/docs/en/authoring-surface-recipe.md index a9cca091..0bb48e7d 100644 --- a/docs/en/authoring-surface-recipe.md +++ b/docs/en/authoring-surface-recipe.md @@ -81,7 +81,7 @@ Use one hosted handoff from definitions to proof instead of stitching together s 4. Write values back through `TrySetSelectedNodeParameterValue(...)` or `TrySetNodeParameterValue(...)`; keep validation on the shared session command path instead of adding a second editor model. 5. Project host commands from `GetCommandDescriptors()` so toolbars, menus, shortcuts, and palette actions stay on the same shared command route. 6. For hosted pointer-mode controls, render `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(canvas)` into the same authoring toolbar row. These actions set `NodeCanvas.SelectionMode` to `NodeCanvasSelectionMode.Marquee` or `NodeCanvasSelectionMode.Lasso`; they do not add a session command, a parallel selection model, or whiteboard drawing state. -7. For hosted whiteboard drawing-tool activation, render `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(canvas)` beside the pointer-mode controls. These actions set only `NodeCanvas.WhiteboardDrawingMode` to `NodeCanvasWhiteboardDrawingMode.Rectangle` or `NodeCanvasWhiteboardDrawingMode.Freehand`; `whiteboard-drawing.rectangle` and `whiteboard-drawing.freehand` have no runtime command id. The stock canvas now consumes that activation on subsequent left-drag pointer gestures to create transient internal whiteboard primitive state only. +7. For hosted whiteboard drawing-tool activation, render `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(canvas)` beside the pointer-mode controls. These actions set only `NodeCanvas.WhiteboardDrawingMode` to `NodeCanvasWhiteboardDrawingMode.Rectangle`, `NodeCanvasWhiteboardDrawingMode.Freehand`, or `NodeCanvasWhiteboardDrawingMode.Eraser`; `whiteboard-drawing.rectangle`, `whiteboard-drawing.freehand`, and `whiteboard-drawing.eraser` have no runtime command id. The stock canvas consumes rectangle/freehand activation on subsequent left-drag pointer gestures to create transient internal whiteboard primitive state, and consumes eraser activation to hit-test/remove those transient primitives without using graph `selection.delete`. 8. Close the handoff with `src/AsterGraph.Demo -- --proof` and expect `PORT_HANDLE_ID_OK:True`, `PORT_GROUP_AUTHORING_OK:True`, `PORT_CONNECTION_HINT_OK:True`, `PORT_AUTHORING_SCOPE_BOUNDARY_OK:True`, `CUSTOM_EXTENSION_SURFACE_OK:True`, and `AUTHORING_SURFACE_OK:True`. ## Copy path @@ -92,7 +92,7 @@ Use one hosted handoff from definitions to proof instead of stitching together s 4. Replace editor bodies through `INodeParameterEditorRegistry`. 5. Render any host-owned edge overlay from `GetConnectionGeometrySnapshots()`. 6. Add lasso activation through `CreatePointerSelectionModeActions(...)` when the host needs a toolbar affordance for `NodeCanvasSelectionMode.Lasso`. -7. Add rectangle/freehand whiteboard activation through `CreateWhiteboardDrawingToolActions(...)` when the host needs a public activation affordance for `NodeCanvas.WhiteboardDrawingMode`, `NodeCanvasWhiteboardDrawingMode.Rectangle`, and `NodeCanvasWhiteboardDrawingMode.Freehand`. The stock hosted Authoring Tools toolbar now projects those actions as `PART_WhiteboardDrawingRectangleButton` and `PART_WhiteboardDrawingFreehandButton`; custom hosts can project the same descriptors in their own chrome. This remains hosted activation plus internal pointer capture only: no runtime command id, no eraser behavior, no persistence/schema changes, no renderer changes, and no full React Flow whiteboard parity. +7. Add rectangle/freehand/eraser whiteboard activation through `CreateWhiteboardDrawingToolActions(...)` when the host needs a public activation affordance for `NodeCanvas.WhiteboardDrawingMode`, `NodeCanvasWhiteboardDrawingMode.Rectangle`, `NodeCanvasWhiteboardDrawingMode.Freehand`, and `NodeCanvasWhiteboardDrawingMode.Eraser`. The stock hosted Authoring Tools toolbar now projects those actions as `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, and `PART_WhiteboardEraserButton`; custom hosts can project the same descriptors in their own chrome. This remains hosted activation plus internal pointer capture/primitive erasing only: no runtime command id, no persistence/schema changes, no renderer changes, and no full React Flow whiteboard parity. 8. Keep runtime decorations on `IGraphRuntimeOverlayProvider` and inspector snapshots; do not move graph execution into the editor. ## Related docs diff --git a/docs/en/demo-cookbook.md b/docs/en/demo-cookbook.md index ac65542b..b4342d85 100644 --- a/docs/en/demo-cookbook.md +++ b/docs/en/demo-cookbook.md @@ -37,7 +37,7 @@ Use it when you want to move from "I can see the Demo" to "I know which code and | `interaction-selection-marquee-route` / Interaction selection marquee route | Authoring | `src/AsterGraph.Editor/Runtime/IGraphEditorQueries.cs` (`GetSelectionRectangleSnapshot`); `src/AsterGraph.Avalonia/Controls/Internal/Overlay/NodeCanvasOverlayCoordinator.cs` (`UpdateMarqueeSelection`); `src/AsterGraph.Editor/Runtime/IGraphEditorCommands.cs` (`SelectAll`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`); `tests/AsterGraph.Editor.Tests/GraphEditorSelectionTransformContractsTests.cs` (`Queries_GetSelectionRectangleSnapshot_ReturnsNodesAndConnectionsInRectangle`); `tests/AsterGraph.Editor.Tests/NodeCanvasOverlayCoordinatorTests.cs` (`UpdateMarqueeSelection_WithFinalizeTrue_UsesBackendSelectionRectangleQuery`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `INTERACTION_SELECTION_MARQUEE_FIXTURE_OK` | `INTERACTION_SELECTION_MARQUEE_FIXTURE_OK`, `SELECTION_RECTANGLE_QUERY_OK`, `SELECTION_RECTANGLE_MARQUEE_OK` | | `interaction-lasso-screenshot-proof-route` / Interaction lasso screenshot proof route | Authoring | `src/AsterGraph.Avalonia/Controls/NodeCanvasSelectionMode.cs` (`Lasso`); `src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`UpdateLassoFeedback`, `ClearLassoFeedback`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`); `tests/AsterGraph.Editor.Tests/NodeCanvasStandaloneTests.cs` (`LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag`); `tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-lasso-screenshot-proof`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `LASSO_SCREENSHOT_PROOF_BOUNDARY_OK` | `LASSO_SCREENSHOT_PROOF_BOUNDARY_OK`, `NodeCanvasSelectionMode.Lasso`, `LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag` | | `whiteboard-primitive-screenshot-proof-route` / Whiteboard primitive screenshot proof route | Authoring | `src/AsterGraph.Core/Models/GraphWhiteboardPrimitive.cs` (`GraphWhiteboardPrimitive`); `src/AsterGraph.Core/Models/GraphWhiteboardPrimitiveRendererAdapter.cs` (`GraphWhiteboardPrimitiveRendererAdapter`); `src/AsterGraph.Core/Models/GraphWhiteboardPrimitivePersistenceDecision.cs` (`GraphWhiteboardPrimitivePersistenceDecision`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`); `tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-primitive-screenshot-proof`); `tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-primitive-screenshot-proof`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `WHITEBOARD_PRIMITIVE_SCREENSHOT_GATE_OK` | `WHITEBOARD_PRIMITIVE_SCREENSHOT_GATE_OK`, `GraphWhiteboardPrimitivePersistenceDecision`, `cookbook-whiteboard-primitive-screenshot-proof` | -| `whiteboard-authoring-cookbook-route` / Whiteboard authoring toolbar and Cookbook UX route | Authoring | `src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs` (`CreateWhiteboardDrawingToolActions`); `src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs` (`PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`); `src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`WhiteboardDrawingModeProperty`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`); `tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`); `tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-authoring-cookbook-route`); `tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-authoring-cookbook-route`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`; [Parity audit](./phase-0-reactflow-parity-audit.md); catalog path: `docs/en/phase-0-reactflow-parity-audit.md`; evidence: `Phase 554` | `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`, `CreateWhiteboardDrawingToolActions`, `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` | +| `whiteboard-authoring-cookbook-route` / Whiteboard authoring toolbar and Cookbook UX route | Authoring | `src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs` (`CreateWhiteboardDrawingToolActions`); `src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs` (`PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, `PART_WhiteboardEraserButton`); `src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`WhiteboardDrawingModeProperty`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`); `tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`); `tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-authoring-cookbook-route`); `tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-authoring-cookbook-route`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`; [Parity audit](./phase-0-reactflow-parity-audit.md); catalog path: `docs/en/phase-0-reactflow-parity-audit.md`; evidence: `Phase 554` | `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`, `CreateWhiteboardDrawingToolActions`, `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` | | `interaction-keyboard-navigation-route` / Interaction keyboard navigation route | Authoring | `src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`HandleCanvasKeyDown`, `TryHandleCanvasArrowKey`); `src/AsterGraph.Avalonia/Controls/Internal/Automation/NodeCanvasAutomationPeer.cs` (`NodeCanvasAutomationPeer`); `src/AsterGraph.Editor/Runtime/Internal/GraphEditorCommandDescriptorCatalog.cs` (`viewport.zoom-in`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`keyboard-navigation-lab`); `tests/AsterGraph.Editor.Tests/NodeCanvasStandaloneTests.cs` (`ArrowKey_Nudge_MovesSelectedNodesWhenNodesAreSelected`, `ArrowKey_Navigate_SelectsNearestNodeWhenNoSelection`); `tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`DefaultChromeMode_ExposesCanvasAndNodeAutomationPeers`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `INTERACTION_KEYBOARD_NAVIGATION_FIXTURE_OK` | `INTERACTION_KEYBOARD_NAVIGATION_FIXTURE_OK`, `CANVAS_KEYBOARD_NAVIGATION_OK`, `ARROW_KEY_NEAREST_NODE_OK` | | `interaction-host-event-inspector-route` / Interaction host event inspector route | ReviewHelp | `src/AsterGraph.Editor/Runtime/IGraphEditorEvents.cs` (`IGraphEditorEvents`); `src/AsterGraph.Editor/Runtime/Mutation/GraphEditorSessionMutation.cs` (`BeginMutation`, `FlushPendingEvents`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`host-event-inspector`); `tests/AsterGraph.Editor.Tests/GraphEditorSessionTests.cs` (`SessionEvents_SubscribeAndUnsubscribe_DoNotLeakMemory`, `SessionEvents_SelectionChanges_AreThrottledToBoundedCadence`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `INTERACTION_HOST_EVENT_INSPECTOR_FIXTURE_OK` | `INTERACTION_HOST_EVENT_INSPECTOR_FIXTURE_OK`, `HOST_EVENT_SUBSCRIPTION_OK`, `EVENT_BATCHING_CADENCE_OK` | | `lifecycle-workspace-save-restore-route` / Lifecycle workspace save/restore route | DiagnosticsSupport | `src/AsterGraph.Editor/Runtime/IGraphEditorCommands.cs` (`SaveWorkspace`, `LoadWorkspace`); `src/AsterGraph.Editor/Runtime/Internal/GraphEditorCommandDescriptorCatalog.cs` (`workspace.save`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`workspace-save-restore`); `tests/AsterGraph.Editor.Tests/GraphEditorDiagnosticsInspectionTests.cs` (`workspace.save.succeeded`); `tests/AsterGraph.Editor.Tests/GraphEditorServiceSeamsTests.cs` (`workspace.load.succeeded`) | [Demo Cookbook](./demo-cookbook.md); catalog path: `docs/en/demo-cookbook.md`; evidence: `LIFECYCLE_WORKSPACE_SAVE_RESTORE_FIXTURE_OK` | `LIFECYCLE_WORKSPACE_SAVE_RESTORE_FIXTURE_OK`, `WORKSPACE_SAVE_LOAD_DIAGNOSTICS_OK` | @@ -80,7 +80,7 @@ Category-derived route posture comes from `DemoCookbookRecipeCategory` and `Reci - `interaction-selection-marquee-route`: Interaction selection marquee route: launch `selection-marquee-workbench` and inspect GetSelectionRectangleSnapshot plus marquee-selection proof evidence. Supported seams live in `AsterGraph.Editor` selection query/command contracts and `AsterGraph.Avalonia` overlay coordinator controls. Demo cookbook provides a rectangular fixture and screenshot-gate coverage only; Demo does not add another selection model or hit-test path. - `interaction-lasso-screenshot-proof-route`: Interaction lasso screenshot proof route: launch `selection-marquee-workbench`, set `NodeCanvasSelectionMode.Lasso`, and capture the active transient lasso overlay. Supported seams live in `AsterGraph.Avalonia` NodeCanvas lasso feedback and the existing `AsterGraph.Editor` selection contracts. Demo cookbook provides a screenshot proof fixture and manifest state only; Demo does not add toolbar UX, eraser behavior, drawing primitives, persistence, or a renderer rewrite. - `whiteboard-primitive-screenshot-proof-route`: Whiteboard primitive screenshot proof route: launch `selection-marquee-workbench` and capture `cookbook-whiteboard-primitive-screenshot-proof` plus `shell-cookbook-whiteboard-primitive-screenshot-proof` metadata. Supported seams remain internal `AsterGraph.Core` whiteboard primitive model, renderer adapter, and persistence decision contracts plus existing Demo screenshot gate manifests. Demo cookbook provides proof-route plumbing only; Demo does not add a public drawing API, pointer coordinator, toolbar, eraser, persisted whiteboard primitive state, GraphDocument schema change, renderer rewrite, UI redesign, or full whiteboard parity. -- `whiteboard-authoring-cookbook-route`: Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton and PART_WhiteboardDrawingFreehandButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench. Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, and `WhiteboardDrawingModeProperty`; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged. Demo cookbook supplies route metadata and shell part proof only; no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. +- `whiteboard-authoring-cookbook-route`: Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton, PART_WhiteboardDrawingFreehandButton, and PART_WhiteboardEraserButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench. Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, `WhiteboardDrawingModeProperty`, and the existing internal whiteboard primitive interaction path; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged. Demo cookbook supplies route metadata and shell part proof only; primitive erasing remains bounded to transient whiteboard primitives, with no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. - `interaction-keyboard-navigation-route`: Interaction keyboard navigation route: launch `keyboard-navigation-lab` and inspect NodeCanvas arrow-key, viewport shortcut, and automation peer evidence. Supported seams live in `AsterGraph.Avalonia` canvas controls and `AsterGraph.Editor` command descriptor/shortcut contracts. Demo cookbook provides a spatial fixture and screenshot-gate coverage only; Demo does not add a separate input model or accessibility framework. - `interaction-host-event-inspector-route`: Interaction host event inspector route: launch `host-event-inspector` and inspect IGraphEditorEvents plus mutation batching evidence. Supported seams live in `AsterGraph.Editor` session event contracts and mutation batching internals. Demo cookbook provides a host-observable fixture and screenshot-gate coverage only; Demo does not add telemetry, remote sync, or a new event broker. - `lifecycle-workspace-save-restore-route`: Lifecycle workspace save/restore route: launch `workspace-save-restore` and inspect SaveWorkspace, LoadWorkspace, and workspace diagnostics evidence. Supported seams live in `AsterGraph.Editor` workspace command contracts, command descriptors, and diagnostics surfaces. Demo cookbook provides a save/restore fixture and screenshot-gate coverage only; Demo does not add a persistence engine or storage policy. @@ -107,7 +107,7 @@ Category-derived route posture comes from `DemoCookbookRecipeCategory` and `Reci - `interaction-selection-marquee-route`: Selection marquee fixture coverage is limited to existing selection query, command, and overlay contracts; it does not add a spatial index, alternate selection model, or custom hit-test runtime. - `interaction-lasso-screenshot-proof-route`: Lasso screenshot proof coverage is limited to existing lasso selection activation, transient overlay feedback, Cookbook scene capture, and shell visual metadata; the explicit exclusions remain no toolbar UX, no eraser behavior, no drawing primitives, no persistence, no strict pixel baselines, no retained API removal, and no full whiteboard parity. - `whiteboard-primitive-screenshot-proof-route`: Whiteboard primitive screenshot proof coverage is limited to route metadata, shell state, non-overlap visual proof, and existing internal whiteboard decisions; it does not add public drawing APIs, pointer coordinators, toolbar activation, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, strict pixel baselines, retained API removal, or full whiteboard parity. -- `whiteboard-authoring-cookbook-route`: Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, and non-overlap proof; it adds no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. +- `whiteboard-authoring-cookbook-route`: Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, non-overlap proof, and bounded primitive erasing; it adds no new core model design, no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. - `interaction-keyboard-navigation-route`: Keyboard navigation fixture coverage is limited to existing Avalonia canvas controls, automation peers, and command shortcut contracts; it does not add a custom input framework or full accessibility provider suite. - `interaction-host-event-inspector-route`: Host event fixture coverage is bounded to existing session event contracts and mutation batching; it does not add telemetry, remote sync, time-based throttling, or a separate event broker. - `lifecycle-workspace-save-restore-route`: Workspace lifecycle fixture coverage is limited to existing save/load commands, command descriptors, and diagnostics; it does not add a persistence engine, cloud sync, storage policy, or migration runtime. @@ -150,7 +150,7 @@ Route boundary strings for the v0.79 catalog: - `GraphOperations`: interaction screenshot fixtures use `selection-marquee-workbench`, `keyboard-navigation-lab`, and `host-event-inspector` so selection, keyboard, and event routes capture distinct graph documents. - `GraphOperations`: Phase 536 / GitHub #195 / `avalonia-node-map-uvd` adds `cookbook-interaction-lasso-screenshot-proof` on `selection-marquee-workbench` as a bounded lasso screenshot proof route, not a new graph fixture family. - `GraphOperations`: Phase 550 / GitHub #223 / `avalonia-node-map-wjr` adds `cookbook-whiteboard-primitive-screenshot-proof` on `selection-marquee-workbench` as a bounded whiteboard primitive visual proof route, not a new drawing fixture family. -- `GraphOperations`: Phase 554 / GitHub #228 / `avalonia-node-map-kpy` adds `whiteboard-authoring-cookbook-route`, `cookbook-whiteboard-authoring-cookbook-route`, and `shell-cookbook-whiteboard-authoring-cookbook-route` on `selection-marquee-workbench`, tying `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` to `CreateWhiteboardDrawingToolActions`, `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`, `PART_WhiteboardDrawingRectangleButton`, and `PART_WhiteboardDrawingFreehandButton` with no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. +- `GraphOperations`: Phase 554 / GitHub #228 / `avalonia-node-map-kpy` adds `whiteboard-authoring-cookbook-route`, `cookbook-whiteboard-authoring-cookbook-route`, and `shell-cookbook-whiteboard-authoring-cookbook-route` on `selection-marquee-workbench`, tying `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` to `CreateWhiteboardDrawingToolActions`, `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`, `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, and `PART_WhiteboardEraserButton`; Phase 555 / GitHub #229 / `avalonia-node-map-71c` adds `NodeCanvasWhiteboardDrawingMode.Eraser` and `whiteboard-drawing.eraser` with no runtime command id, keeping eraser-on-transient-whiteboard-primitive behavior separate from graph `selection.delete`, with no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. - `GraphOperations`: lifecycle screenshot fixtures use `workspace-save-restore`, `clipboard-fragment-roundtrip`, and `validation-prevent-cycle` so save/load, clipboard, and validation helper routes capture distinct graph documents. - `GraphOperations`: `LAYOUT_PROVIDER_EVIDENCE_EXPANSION` keeps layout evidence synchronous and host-owned through `UseLayoutProvider(...)` / `IGraphLayoutProvider.CreateLayoutPlan(GraphLayoutRequest)`. `GraphLayoutRequest`, `GraphLayoutPlan`, `PreviewLayoutPlan`, `TryApplyLayoutPlan`, `TryApplyLayoutRequest`, `TrySnapSelectedNodesToGrid`, and `TrySnapAllNodesToGrid` stay on `IGraphEditorSession` commands and are verified through `GraphEditorLayoutProviderSeamTests`, `LAYOUT_PROVIDER_SEAM_OK`, `LAYOUT_PREVIEW_APPLY_CANCEL_OK`, and `LAYOUT_UNDO_TRANSACTION_OK`. This proof does not make layout execution asynchronous or cancellable. - `NodeMetadata`: metadata and trust evidence stay anchored to recipe code or proof markers. diff --git a/docs/en/phase-0-reactflow-parity-audit.md b/docs/en/phase-0-reactflow-parity-audit.md index 886e2c0d..f7fd7a11 100644 --- a/docs/en/phase-0-reactflow-parity-audit.md +++ b/docs/en/phase-0-reactflow-parity-audit.md @@ -262,6 +262,10 @@ Phase 553 is GitHub #227 / `avalonia-node-map-9f0`, the whiteboard primitive poi Phase 554 is GitHub #228 / `avalonia-node-map-kpy`, the whiteboard authoring toolbar and Cookbook UX route. This hosted Avalonia + Demo/Cookbook slice projects `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)` through the stock Authoring Tools row as `PART_WhiteboardDrawingRectangleButton` and `PART_WhiteboardDrawingFreehandButton`, backed by `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`. It also adds `whiteboard-authoring-cookbook-route`, the screenshot route `cookbook-whiteboard-authoring-cookbook-route`, the shell state `shell-cookbook-whiteboard-authoring-cookbook-route`, and proof marker `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` on the existing `selection-marquee-workbench` fixture. Phase 554 is stacked after PR #233 and must not merge before Phase 553. It adds no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, no retained API removal, and no full React Flow whiteboard parity. +## Phase 555 Update + +Phase 555 is GitHub #229 / `avalonia-node-map-71c`, the whiteboard primitive eraser behavior route. This hosted Avalonia slice extends `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)` with `NodeCanvasWhiteboardDrawingMode.Eraser`, `whiteboard-drawing.eraser`, and the stock hosted `PART_WhiteboardEraserButton`; the action remains a host-source activation with no runtime command id. The existing pointer coordinator consumes eraser mode on left press by hit-testing current transient whiteboard primitives through `TryEraseWhiteboardPrimitive(...)`, removing only the topmost hit primitive and keeping graph-selection delete separate from graph `selection.delete`. `TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers` and `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection` guard primitive hit-testing, no-hit behavior, active-gesture cleanup, and graph-deletion separation. Phase 555 is stacked on Phase 554 and must not merge before PR #234. It adds no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, no retained API removal, and no full React Flow 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. @@ -603,6 +607,8 @@ Phase 553 records the whiteboard primitive pointer gesture capture route through Phase 554 records the whiteboard authoring toolbar and Cookbook UX route through GitHub #228 / `avalonia-node-map-kpy`. It projects `CreateWhiteboardDrawingToolActions(...)` into the stock hosted Authoring Tools chrome as `PART_WhiteboardDrawingRectangleButton` and `PART_WhiteboardDrawingFreehandButton`, guards it with `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`, and records `whiteboard-authoring-cookbook-route`, `cookbook-whiteboard-authoring-cookbook-route`, `shell-cookbook-whiteboard-authoring-cookbook-route`, and `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` on `selection-marquee-workbench`. It adds no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, or full React Flow whiteboard parity. +Phase 555 records the whiteboard primitive eraser behavior route through GitHub #229 / `avalonia-node-map-71c`. It adds `NodeCanvasWhiteboardDrawingMode.Eraser`, `whiteboard-drawing.eraser`, and `PART_WhiteboardEraserButton`, then routes eraser-mode press handling through `TryEraseWhiteboardPrimitive(...)` so transient whiteboard primitives are hit-tested and removed without invoking graph `selection.delete`. It guards that graph-selection delete remains separate through `TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers` and `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection`, while leaving broad eraser cursor redesign, persisted whiteboard primitive state, GraphDocument schema changes, renderer rewrites, retained API removal, and full React Flow whiteboard parity out of scope. + | 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. | @@ -682,7 +688,7 @@ Phase 554 records the whiteboard authoring toolbar and Cookbook UX route through - `feature/phase-552-whiteboard-tool-activation`: owns #226 / `avalonia-node-map-718`; future activation-contract worktree after Phase 551. - `feature/phase-553-whiteboard-pointer-capture`: owns #227 / `avalonia-node-map-9f0`; future pointer gesture capture worktree after Phase 552. - `visual/phase-554-whiteboard-authoring-cookbook`: owns #228 / `avalonia-node-map-kpy`; future hosted authoring toolbar and Cookbook UX worktree after Phase 553. -- `feature/phase-555-whiteboard-eraser-behavior`: owns #229 / `avalonia-node-map-71c`; future eraser-on-primitive behavior worktree after Phase 554. +- `feature/phase-555-whiteboard-eraser-behavior`: owns #229 / `avalonia-node-map-71c`; current stacked implementation worktree for eraser-on-primitive behavior after Phase 554, with graph `selection.delete`, persistence/schema, renderer rewrite, and full whiteboard parity out of scope. - `feature/phase-556-whiteboard-persistence-decision`: owns #230 / `avalonia-node-map-bck`; future persistence implementation decision worktree after Phase 555. ## UI Verification Policy @@ -754,4 +760,5 @@ Current coverage includes scene-level route captures plus ten manifest-driven fu - Phase 552 is GitHub #226 / `avalonia-node-map-718`; it records the whiteboard drawing tool public activation contract through `NodeCanvas.WhiteboardDrawingMode`, `NodeCanvasWhiteboardDrawingMode.Rectangle`, `NodeCanvasWhiteboardDrawingMode.Freehand`, `CreateWhiteboardDrawingToolActions(...)`, `whiteboard-drawing.rectangle`, and `whiteboard-drawing.freehand`, with no runtime command id, pointer gesture capture, runtime drawing creation, toolbar UI implementation, eraser behavior, persistence/schema changes, renderer changes, screenshot manifest expansion, or full React Flow whiteboard parity. - Phase 553 is GitHub #227 / `avalonia-node-map-9f0`; it records the whiteboard primitive pointer gesture capture route through `NodeCanvasPointerInteractionCoordinator`, `NodeCanvasInteractionSession`, transient internal `GraphWhiteboardPrimitive` state, world-space rectangle/freehand geometry, release commit lifecycle, and capture-loss cancellation. Runtime command ids, toolbar UI implementation, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, renderer changes, screenshot manifest expansion, and full React Flow whiteboard parity remain out of scope. - Phase 554 is GitHub #228 / `avalonia-node-map-kpy`; it records the whiteboard authoring toolbar and Cookbook UX route through `whiteboard-authoring-cookbook-route`, `CreateWhiteboardDrawingToolActions(...)`, `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`, `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, `cookbook-whiteboard-authoring-cookbook-route`, `shell-cookbook-whiteboard-authoring-cookbook-route`, and `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`. New core model design, pointer coordinator redesign, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, renderer rewrites, and full React Flow whiteboard parity remain out of scope. +- Phase 555 is GitHub #229 / `avalonia-node-map-71c`; it records the whiteboard primitive eraser behavior route through `NodeCanvasWhiteboardDrawingMode.Eraser`, `whiteboard-drawing.eraser`, `PART_WhiteboardEraserButton`, `TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers`, and `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection`. Graph-selection delete remains separate through graph `selection.delete`; broad eraser cursor redesign, persisted whiteboard primitive state, GraphDocument schema changes, renderer rewrites, retained API removal, and full React Flow whiteboard parity remain out of scope. - Product code remains out of scope for Phase 478, Phase 484, Phase 490, Phase 491, Phase 492, Phase 493, Phase 494, Phase 495, Phase 497, Phase 498, Phase 499, Phase 500, Phase 501, Phase 502, Phase 503, Phase 504, Phase 505, Phase 506, Phase 507, Phase 508, Phase 509, Phase 510, Phase 511, Phase 512, Phase 513, Phase 520, Phase 521, Phase 522, Phase 523, Phase 524, Phase 525, Phase 526, Phase 527, Phase 528, Phase 529, Phase 535, Phase 539, Phase 540, Phase 541, Phase 546, Phase 550, and Phase 551 unless a focused test proves a specific missing contract. diff --git a/docs/en/public-api-inventory.md b/docs/en/public-api-inventory.md index 54651f48..8f7d787b 100644 --- a/docs/en/public-api-inventory.md +++ b/docs/en/public-api-inventory.md @@ -45,7 +45,7 @@ Use this page with [Host Integration](./host-integration.md) and [Extension Cont | Phase 530 lasso selection query route | Stable canonical | `IGraphEditorQueries.GetSelectionLassoSnapshot(...)`, `GraphEditorSelectionLassoSnapshot`, `GraphEditorSelectionLassoSnapshot.NodeIds`, `GraphEditorSelectionLassoSnapshot.ConnectionIds` | Backend/editor lasso query route for custom UIs that capture freeform polygon points themselves. The query stays on the session route, uses active-scope graph state, selects nodes by center-point polygon containment, and selects connections only when both endpoint nodes are selected. This does not add Avalonia gesture capture, pointer-mode state, drawing primitives, eraser behavior, persistence, renderer changes, screenshot rows, or full React Flow whiteboard parity. | | Phase 533 lasso pointer-mode route | Supported hosted helper | `NodeCanvas.SelectionMode`, `NodeCanvasSelectionMode.Marquee`, `NodeCanvasSelectionMode.Lasso` | Hosted Avalonia activation path for stock canvas lasso selection. Marquee remains the default; hosts can opt into lasso for empty-canvas selection drags. This reuses the existing backend lasso query and Avalonia lasso bridge, and does not add toolbar UX, visual gesture capture, screenshot rows, eraser behavior, drawing primitives, persistence, renderer changes, or full React Flow whiteboard parity. | | Phase 537 lasso toolbar ergonomics route | Supported hosted helper | `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(...)`, `pointer-mode.marquee-selection`, `pointer-mode.lasso-selection`, `NodeCanvas.SelectionMode`, `NodeCanvasSelectionMode.Lasso` | Hosted toolbar action projection for switching the stock canvas between marquee and lasso selection. The helper writes only the existing `NodeCanvas.SelectionMode` property, returns host-source actions with no runtime command id, and does not add a parallel selection model, eraser behavior, drawing primitives, persistence, renderer changes, strict pixel baselines, retained API removal, or full React Flow whiteboard parity. | -| Phase 552-554 whiteboard drawing activation, pointer gesture, and hosted toolbar route | Supported hosted helper | `NodeCanvas.WhiteboardDrawingMode`, `NodeCanvasWhiteboardDrawingMode.None`, `NodeCanvasWhiteboardDrawingMode.Rectangle`, `NodeCanvasWhiteboardDrawingMode.Freehand`, `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)`, `whiteboard-drawing.rectangle`, `whiteboard-drawing.freehand`, `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton` | Hosted activation contract plus stock-canvas internal pointer gesture capture for rectangle/freehand whiteboard primitives. The helper writes only the `NodeCanvas.WhiteboardDrawingMode` property and returns host-source actions with no runtime command id; the existing canvas pointer coordinator consumes the active mode on left-drag to create transient internal primitive state. Stock hosted `GraphEditorView` now projects those actions into the Authoring Tools toolbar as `PART_WhiteboardDrawingRectangleButton` and `PART_WhiteboardDrawingFreehandButton`. This does not add a runtime command route, eraser behavior, persistence/schema changes, renderer changes, retained API removal, or full React Flow whiteboard parity. | +| Phase 552-555 whiteboard drawing activation, pointer gesture, hosted toolbar, and primitive eraser route | Supported hosted helper | `NodeCanvas.WhiteboardDrawingMode`, `NodeCanvasWhiteboardDrawingMode.None`, `NodeCanvasWhiteboardDrawingMode.Rectangle`, `NodeCanvasWhiteboardDrawingMode.Freehand`, `NodeCanvasWhiteboardDrawingMode.Eraser`, `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)`, `whiteboard-drawing.rectangle`, `whiteboard-drawing.freehand`, `whiteboard-drawing.eraser`, `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, `PART_WhiteboardEraserButton` | Hosted activation contract plus stock-canvas internal pointer gesture capture for rectangle/freehand whiteboard primitives and eraser-on-transient-primitive behavior. The helper writes only the `NodeCanvas.WhiteboardDrawingMode` property and returns host-source actions with no runtime command id; the existing canvas pointer coordinator consumes rectangle/freehand modes on left-drag to create transient internal primitive state and consumes eraser mode to hit-test/remove whiteboard primitives without invoking graph `selection.delete`. Stock hosted `GraphEditorView` projects those actions into the Authoring Tools toolbar as `PART_WhiteboardDrawingRectangleButton`, `PART_WhiteboardDrawingFreehandButton`, and `PART_WhiteboardEraserButton`. This does not add a runtime command route, persisted whiteboard primitive state, persistence/schema changes, renderer changes, retained API removal, or full React Flow whiteboard parity. | | Shipped Avalonia UI | Supported hosted helper | `AsterGraphEditorFactory.Create(...)`, `AsterGraphAvaloniaViewFactory.Create(...)` | Uses the same runtime owner; not a second runtime model. | | Thin hosted builder | Supported hosted helper | `AsterGraphHostBuilder.Create(...).UseDefaultWorkbench().UseLayoutProvider(...).BuildAvaloniaView()`, plus `UseBehaviorOptions(...)`, `UseContextMenuAugmentor(...)`, `UseNodePresentationProvider(...)`, `UseToolProvider(...)`, `UseRuntimeOverlayProvider(...)`, and `UseLayoutProvider(...)` | Reduces common Avalonia setup boilerplate while delegating to canonical factories; the pass-throughs expose existing `AsterGraphEditorOptions` seams, including the host-owned synchronous layout provider seam, and do not create a new runtime model. `AsterGraphWorkbenchOptions` only controls stock hosted chrome. | | Built-in component catalog | Supported hosted helper | `AsterGraphBuiltInComponentCatalog.Components`, `AsterGraphBuiltInComponentCatalog.TryGet(...)`, `AsterGraphBuiltInComponentDescriptor`, `AsterGraphBuiltInComponentStatus`, `AsterGraphControls`, `NodeToolbar`, `EdgeToolbar`, `NodeResizer`, `AsterGraphPanel` | Discovery-only Phase 3 map for built-in component tracks. Public entries point to existing canvas, minimap, background-grid, inspector, controls-panel, `controls`, command-tool-projection, `node-toolbar`, `edge-toolbar`, `node-resizer`, and `panel` surfaces. `AsterGraphControls` is a thin Avalonia control over `IGraphEditorSession.Commands.TryExecuteCommand(...)` for viewport zoom, fit, and reset actions; `NodeToolbar` and `EdgeToolbar` are thin Avalonia controls over `AsterGraphAuthoringToolActionFactory.CreateNodeActions(...)` and `CreateConnectionActions(...)`; `NodeResizer` is a thin Avalonia control over `IGraphEditorSession.Commands.TrySetNodeSize(...)`; `AsterGraphPanel` is a host-owned content overlay primitive with stable positional placement. | diff --git a/docs/zh-CN/authoring-surface-recipe.md b/docs/zh-CN/authoring-surface-recipe.md index 0e16583d..ccb3a18c 100644 --- a/docs/zh-CN/authoring-surface-recipe.md +++ b/docs/zh-CN/authoring-surface-recipe.md @@ -81,7 +81,7 @@ 4. 写回时继续走 `TrySetSelectedNodeParameterValue(...)` 或 `TrySetNodeParameterValue(...)`,把 validation 保留在共享 session command 路线上,不再引入第二套 editor model。 5. 宿主命令继续从 `GetCommandDescriptors()` 投影,这样 toolbar、menu、shortcut 和 palette action 都停留在同一条共享 command route 上。 6. hosted pointer-mode 控件直接把 `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(canvas)` 投到同一行 authoring toolbar。它们只把 `NodeCanvas.SelectionMode` 设为 `NodeCanvasSelectionMode.Marquee` 或 `NodeCanvasSelectionMode.Lasso`,不新增 session command、第二套 selection model 或 whiteboard drawing state。 -7. hosted whiteboard drawing-tool activation 控件可以把 `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(canvas)` 放到 pointer-mode controls 旁边。这些 action 只把 `NodeCanvas.WhiteboardDrawingMode` 设为 `NodeCanvasWhiteboardDrawingMode.Rectangle` 或 `NodeCanvasWhiteboardDrawingMode.Freehand`;`whiteboard-drawing.rectangle` 和 `whiteboard-drawing.freehand` 没有 runtime command id。Stock canvas 会在后续 left-drag pointer gesture 中消费这个 activation,只创建 transient internal whiteboard primitive state。 +7. hosted whiteboard drawing-tool activation 控件可以把 `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(canvas)` 放到 pointer-mode controls 旁边。这些 action 只把 `NodeCanvas.WhiteboardDrawingMode` 设为 `NodeCanvasWhiteboardDrawingMode.Rectangle`、`NodeCanvasWhiteboardDrawingMode.Freehand` 或 `NodeCanvasWhiteboardDrawingMode.Eraser`;`whiteboard-drawing.rectangle`、`whiteboard-drawing.freehand` 和 `whiteboard-drawing.eraser` 没有 runtime command id。Stock canvas 会在后续 left-drag pointer gesture 中消费 rectangle/freehand activation,创建 transient internal whiteboard primitive state;在 eraser activation 下只通过 hit-test/remove 删除这些 transient primitives,不调用 graph `selection.delete`。 8. 最后用 `src/AsterGraph.Demo -- --proof` 收口,并期待看到 `PORT_HANDLE_ID_OK:True`、`PORT_GROUP_AUTHORING_OK:True`、`PORT_CONNECTION_HINT_OK:True`、`PORT_AUTHORING_SCOPE_BOUNDARY_OK:True`、`CUSTOM_EXTENSION_SURFACE_OK:True` 和 `AUTHORING_SURFACE_OK:True`。 ## 复制顺序 @@ -92,7 +92,7 @@ 4. 通过 `INodeParameterEditorRegistry` 替换 editor body。 5. 通过 `GetConnectionGeometrySnapshots()` 渲染宿主自管 edge overlay。 6. 宿主需要 toolbar affordance 时,用 `CreatePointerSelectionModeActions(...)` 接入 `NodeCanvasSelectionMode.Lasso`。 -7. 宿主需要 public activation affordance 时,用 `CreateWhiteboardDrawingToolActions(...)` 接入 `NodeCanvas.WhiteboardDrawingMode`、`NodeCanvasWhiteboardDrawingMode.Rectangle` 和 `NodeCanvasWhiteboardDrawingMode.Freehand`。Stock hosted Authoring Tools toolbar 现在会把这些 actions 投影成 `PART_WhiteboardDrawingRectangleButton` 和 `PART_WhiteboardDrawingFreehandButton`;自定义宿主也可以把同一批 descriptors 放到自己的 chrome 中。这仍然只包括 hosted activation 和 internal pointer capture:no runtime command id、no eraser behavior、no persistence/schema changes、no renderer changes,也不声明 full React Flow whiteboard parity。 +7. 宿主需要 public activation affordance 时,用 `CreateWhiteboardDrawingToolActions(...)` 接入 `NodeCanvas.WhiteboardDrawingMode`、`NodeCanvasWhiteboardDrawingMode.Rectangle`、`NodeCanvasWhiteboardDrawingMode.Freehand` 和 `NodeCanvasWhiteboardDrawingMode.Eraser`。Stock hosted Authoring Tools toolbar 现在会把这些 actions 投影成 `PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton` 和 `PART_WhiteboardEraserButton`;自定义宿主也可以把同一批 descriptors 放到自己的 chrome 中。这仍然只包括 hosted activation、internal pointer capture 和 primitive erasing:no runtime command id、no persistence/schema changes、no renderer changes,也不声明 full React Flow whiteboard parity。 8. runtime decoration 保持在 `IGraphRuntimeOverlayProvider` 和 inspector snapshots 上;不要把图执行搬进 editor。 ## 相关文档 diff --git a/docs/zh-CN/demo-cookbook.md b/docs/zh-CN/demo-cookbook.md index b3bbde49..a2e5efb9 100644 --- a/docs/zh-CN/demo-cookbook.md +++ b/docs/zh-CN/demo-cookbook.md @@ -37,7 +37,7 @@ Demo cookbook 是面向 AsterGraph 评估者的“代码 + 演示”索引。它 | `interaction-selection-marquee-route` / Interaction selection marquee route | Authoring | `src/AsterGraph.Editor/Runtime/IGraphEditorQueries.cs` (`GetSelectionRectangleSnapshot`);`src/AsterGraph.Avalonia/Controls/Internal/Overlay/NodeCanvasOverlayCoordinator.cs` (`UpdateMarqueeSelection`);`src/AsterGraph.Editor/Runtime/IGraphEditorCommands.cs` (`SelectAll`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`);`tests/AsterGraph.Editor.Tests/GraphEditorSelectionTransformContractsTests.cs` (`Queries_GetSelectionRectangleSnapshot_ReturnsNodesAndConnectionsInRectangle`);`tests/AsterGraph.Editor.Tests/NodeCanvasOverlayCoordinatorTests.cs` (`UpdateMarqueeSelection_WithFinalizeTrue_UsesBackendSelectionRectangleQuery`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `INTERACTION_SELECTION_MARQUEE_FIXTURE_OK` | `INTERACTION_SELECTION_MARQUEE_FIXTURE_OK`、`SELECTION_RECTANGLE_QUERY_OK`、`SELECTION_RECTANGLE_MARQUEE_OK` | | `interaction-lasso-screenshot-proof-route` / Interaction lasso screenshot proof route | Authoring | `src/AsterGraph.Avalonia/Controls/NodeCanvasSelectionMode.cs` (`Lasso`);`src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`UpdateLassoFeedback`、`ClearLassoFeedback`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`);`tests/AsterGraph.Editor.Tests/NodeCanvasStandaloneTests.cs` (`LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag`);`tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-lasso-screenshot-proof`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `LASSO_SCREENSHOT_PROOF_BOUNDARY_OK` | `LASSO_SCREENSHOT_PROOF_BOUNDARY_OK`、`NodeCanvasSelectionMode.Lasso`、`LassoSelectionMode_RendersTransientFeedbackPathOnlyDuringDrag` | | `whiteboard-primitive-screenshot-proof-route` / Whiteboard primitive screenshot proof route | Authoring | `src/AsterGraph.Core/Models/GraphWhiteboardPrimitive.cs` (`GraphWhiteboardPrimitive`);`src/AsterGraph.Core/Models/GraphWhiteboardPrimitiveRendererAdapter.cs` (`GraphWhiteboardPrimitiveRendererAdapter`);`src/AsterGraph.Core/Models/GraphWhiteboardPrimitivePersistenceDecision.cs` (`GraphWhiteboardPrimitivePersistenceDecision`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`);`tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-primitive-screenshot-proof`);`tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-primitive-screenshot-proof`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `WHITEBOARD_PRIMITIVE_SCREENSHOT_GATE_OK` | `WHITEBOARD_PRIMITIVE_SCREENSHOT_GATE_OK`、`GraphWhiteboardPrimitivePersistenceDecision`、`cookbook-whiteboard-primitive-screenshot-proof` | -| `whiteboard-authoring-cookbook-route` / Whiteboard authoring toolbar and Cookbook UX route | Authoring | `src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs` (`CreateWhiteboardDrawingToolActions`);`src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs` (`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton`);`src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`WhiteboardDrawingModeProperty`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`);`tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`);`tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-authoring-cookbook-route`);`tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-authoring-cookbook-route`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`;[Parity audit](./phase-0-reactflow-parity-audit.md);catalog path: `docs/en/phase-0-reactflow-parity-audit.md`;evidence: `Phase 554` | `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`、`CreateWhiteboardDrawingToolActions`、`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` | +| `whiteboard-authoring-cookbook-route` / Whiteboard authoring toolbar and Cookbook UX route | Authoring | `src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs` (`CreateWhiteboardDrawingToolActions`);`src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs` (`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton`、`PART_WhiteboardEraserButton`);`src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`WhiteboardDrawingModeProperty`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`selection-marquee-workbench`);`tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`);`tests/AsterGraph.Demo.Tests/CookbookScreenshotGateRoutes.json` (`cookbook-whiteboard-authoring-cookbook-route`);`tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json` (`shell-cookbook-whiteboard-authoring-cookbook-route`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`;[Parity audit](./phase-0-reactflow-parity-audit.md);catalog path: `docs/en/phase-0-reactflow-parity-audit.md`;evidence: `Phase 554` | `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`、`CreateWhiteboardDrawingToolActions`、`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` | | `interaction-keyboard-navigation-route` / Interaction keyboard navigation route | Authoring | `src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs` (`HandleCanvasKeyDown`、`TryHandleCanvasArrowKey`);`src/AsterGraph.Avalonia/Controls/Internal/Automation/NodeCanvasAutomationPeer.cs` (`NodeCanvasAutomationPeer`);`src/AsterGraph.Editor/Runtime/Internal/GraphEditorCommandDescriptorCatalog.cs` (`viewport.zoom-in`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`keyboard-navigation-lab`);`tests/AsterGraph.Editor.Tests/NodeCanvasStandaloneTests.cs` (`ArrowKey_Nudge_MovesSelectedNodesWhenNodesAreSelected`、`ArrowKey_Navigate_SelectsNearestNodeWhenNoSelection`);`tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs` (`DefaultChromeMode_ExposesCanvasAndNodeAutomationPeers`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `INTERACTION_KEYBOARD_NAVIGATION_FIXTURE_OK` | `INTERACTION_KEYBOARD_NAVIGATION_FIXTURE_OK`、`CANVAS_KEYBOARD_NAVIGATION_OK`、`ARROW_KEY_NEAREST_NODE_OK` | | `interaction-host-event-inspector-route` / Interaction host event inspector route | ReviewHelp | `src/AsterGraph.Editor/Runtime/IGraphEditorEvents.cs` (`IGraphEditorEvents`);`src/AsterGraph.Editor/Runtime/Mutation/GraphEditorSessionMutation.cs` (`BeginMutation`、`FlushPendingEvents`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`host-event-inspector`);`tests/AsterGraph.Editor.Tests/GraphEditorSessionTests.cs` (`SessionEvents_SubscribeAndUnsubscribe_DoNotLeakMemory`、`SessionEvents_SelectionChanges_AreThrottledToBoundedCadence`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `INTERACTION_HOST_EVENT_INSPECTOR_FIXTURE_OK` | `INTERACTION_HOST_EVENT_INSPECTOR_FIXTURE_OK`、`HOST_EVENT_SUBSCRIPTION_OK`、`EVENT_BATCHING_CADENCE_OK` | | `lifecycle-workspace-save-restore-route` / Lifecycle workspace save/restore route | DiagnosticsSupport | `src/AsterGraph.Editor/Runtime/IGraphEditorCommands.cs` (`SaveWorkspace`、`LoadWorkspace`);`src/AsterGraph.Editor/Runtime/Internal/GraphEditorCommandDescriptorCatalog.cs` (`workspace.save`) | `src/AsterGraph.Demo/DemoGraphFactory.cs` (`workspace-save-restore`);`tests/AsterGraph.Editor.Tests/GraphEditorDiagnosticsInspectionTests.cs` (`workspace.save.succeeded`);`tests/AsterGraph.Editor.Tests/GraphEditorServiceSeamsTests.cs` (`workspace.load.succeeded`) | [Demo Cookbook](./demo-cookbook.md);catalog path: `docs/en/demo-cookbook.md`;evidence: `LIFECYCLE_WORKSPACE_SAVE_RESTORE_FIXTURE_OK` | `LIFECYCLE_WORKSPACE_SAVE_RESTORE_FIXTURE_OK`、`WORKSPACE_SAVE_LOAD_DIAGNOSTICS_OK` | @@ -80,7 +80,7 @@ Category-derived route posture 来自 `DemoCookbookRecipeCategory` 和 `Recipe.I - `interaction-selection-marquee-route`: Interaction selection marquee route: launch `selection-marquee-workbench` and inspect GetSelectionRectangleSnapshot plus marquee-selection proof evidence. Supported seams live in `AsterGraph.Editor` selection query/command contracts and `AsterGraph.Avalonia` overlay coordinator controls. Demo cookbook provides a rectangular fixture and screenshot-gate coverage only; Demo does not add another selection model or hit-test path. - `interaction-lasso-screenshot-proof-route`: Interaction lasso screenshot proof route: launch `selection-marquee-workbench`, set `NodeCanvasSelectionMode.Lasso`, and capture the active transient lasso overlay. Supported seams live in `AsterGraph.Avalonia` NodeCanvas lasso feedback and the existing `AsterGraph.Editor` selection contracts. Demo cookbook provides a screenshot proof fixture and manifest state only; Demo does not add toolbar UX, eraser behavior, drawing primitives, persistence, or a renderer rewrite. - `whiteboard-primitive-screenshot-proof-route`: Whiteboard primitive screenshot proof route: launch `selection-marquee-workbench` and capture `cookbook-whiteboard-primitive-screenshot-proof` plus `shell-cookbook-whiteboard-primitive-screenshot-proof` metadata. Supported seams remain internal `AsterGraph.Core` whiteboard primitive model, renderer adapter, and persistence decision contracts plus existing Demo screenshot gate manifests. Demo cookbook provides proof-route plumbing only; Demo does not add a public drawing API, pointer coordinator, toolbar, eraser, persisted whiteboard primitive state, GraphDocument schema change, renderer rewrite, UI redesign, or full whiteboard parity. -- `whiteboard-authoring-cookbook-route`: Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton and PART_WhiteboardDrawingFreehandButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench. Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, and `WhiteboardDrawingModeProperty`; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged. Demo cookbook supplies route metadata and shell part proof only; no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. +- `whiteboard-authoring-cookbook-route`: Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton, PART_WhiteboardDrawingFreehandButton, and PART_WhiteboardEraserButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench. Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, `WhiteboardDrawingModeProperty`, and the existing internal whiteboard primitive interaction path; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged. Demo cookbook supplies route metadata and shell part proof only; primitive erasing remains bounded to transient whiteboard primitives, with no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. - `interaction-keyboard-navigation-route`: Interaction keyboard navigation route: launch `keyboard-navigation-lab` and inspect NodeCanvas arrow-key, viewport shortcut, and automation peer evidence. Supported seams live in `AsterGraph.Avalonia` canvas controls and `AsterGraph.Editor` command descriptor/shortcut contracts. Demo cookbook provides a spatial fixture and screenshot-gate coverage only; Demo does not add a separate input model or accessibility framework. - `interaction-host-event-inspector-route`: Interaction host event inspector route: launch `host-event-inspector` and inspect IGraphEditorEvents plus mutation batching evidence. Supported seams live in `AsterGraph.Editor` session event contracts and mutation batching internals. Demo cookbook provides a host-observable fixture and screenshot-gate coverage only; Demo does not add telemetry, remote sync, or a new event broker. - `lifecycle-workspace-save-restore-route`: Lifecycle workspace save/restore route: launch `workspace-save-restore` and inspect SaveWorkspace, LoadWorkspace, and workspace diagnostics evidence. Supported seams live in `AsterGraph.Editor` workspace command contracts, command descriptors, and diagnostics surfaces. Demo cookbook provides a save/restore fixture and screenshot-gate coverage only; Demo does not add a persistence engine or storage policy. @@ -107,7 +107,7 @@ Category-derived route posture 来自 `DemoCookbookRecipeCategory` 和 `Recipe.I - `interaction-selection-marquee-route`: Selection marquee fixture coverage is limited to existing selection query, command, and overlay contracts; it does not add a spatial index, alternate selection model, or custom hit-test runtime. - `interaction-lasso-screenshot-proof-route`: Lasso screenshot proof coverage is limited to existing lasso selection activation, transient overlay feedback, Cookbook scene capture, and shell visual metadata; the explicit exclusions remain no toolbar UX, no eraser behavior, no drawing primitives, no persistence, no strict pixel baselines, no retained API removal, and no full whiteboard parity. - `whiteboard-primitive-screenshot-proof-route`: Whiteboard primitive screenshot proof coverage is limited to route metadata, shell state, non-overlap visual proof, and existing internal whiteboard decisions; it does not add public drawing APIs, pointer coordinators, toolbar activation, eraser behavior, persisted whiteboard primitive state, GraphDocument schema changes, strict pixel baselines, retained API removal, or full whiteboard parity. -- `whiteboard-authoring-cookbook-route`: Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, and non-overlap proof; it adds no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. +- `whiteboard-authoring-cookbook-route`: Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, non-overlap proof, and bounded primitive erasing; it adds no new core model design, no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity. - `interaction-keyboard-navigation-route`: Keyboard navigation fixture coverage is limited to existing Avalonia canvas controls, automation peers, and command shortcut contracts; it does not add a custom input framework or full accessibility provider suite. - `interaction-host-event-inspector-route`: Host event fixture coverage is bounded to existing session event contracts and mutation batching; it does not add telemetry, remote sync, time-based throttling, or a separate event broker. - `lifecycle-workspace-save-restore-route`: Workspace lifecycle fixture coverage is limited to existing save/load commands, command descriptors, and diagnostics; it does not add a persistence engine, cloud sync, storage policy, or migration runtime. @@ -150,7 +150,7 @@ v0.79 catalog 的 route boundary 字符串: - `GraphOperations`: interaction screenshot fixtures 使用 `selection-marquee-workbench`、`keyboard-navigation-lab` 和 `host-event-inspector`,确保 selection、keyboard 和 event 路线捕获不同 graph document。 - `GraphOperations`: Phase 536 / GitHub #195 / `avalonia-node-map-uvd` 在 `selection-marquee-workbench` 上增加 `cookbook-interaction-lasso-screenshot-proof`,作为有界 lasso screenshot proof route,而不是新的 graph fixture family。 - `GraphOperations`: Phase 550 / GitHub #223 / `avalonia-node-map-wjr` 在 `selection-marquee-workbench` 上增加 `cookbook-whiteboard-primitive-screenshot-proof`,作为有界 whiteboard primitive visual proof route,而不是新的 drawing fixture family。 -- `GraphOperations`: Phase 554 / GitHub #228 / `avalonia-node-map-kpy` 在 `selection-marquee-workbench` 上增加 `whiteboard-authoring-cookbook-route`、`cookbook-whiteboard-authoring-cookbook-route` 和 `shell-cookbook-whiteboard-authoring-cookbook-route`,把 `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` 绑定到 `CreateWhiteboardDrawingToolActions`、`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`、`PART_WhiteboardDrawingRectangleButton` 和 `PART_WhiteboardDrawingFreehandButton`;no new core model design、no pointer coordinator redesign、no eraser behavior、no persisted whiteboard primitive state、no GraphDocument schema changes、no renderer rewrite,也不声明 no full whiteboard parity。 +- `GraphOperations`: Phase 554 / GitHub #228 / `avalonia-node-map-kpy` 在 `selection-marquee-workbench` 上增加 `whiteboard-authoring-cookbook-route`、`cookbook-whiteboard-authoring-cookbook-route` 和 `shell-cookbook-whiteboard-authoring-cookbook-route`,把 `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` 绑定到 `CreateWhiteboardDrawingToolActions`、`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`、`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton` 和 `PART_WhiteboardEraserButton`;Phase 555 / GitHub #229 / `avalonia-node-map-71c` 添加 `NodeCanvasWhiteboardDrawingMode.Eraser` 和 `whiteboard-drawing.eraser`,保持 no runtime command id,并让 eraser-on-transient-whiteboard-primitive behavior separate from graph `selection.delete`,且不声明 persisted whiteboard primitive state、GraphDocument schema changes、renderer rewrite 或 full whiteboard parity。 - `GraphOperations`: lifecycle screenshot fixtures 使用 `workspace-save-restore`、`clipboard-fragment-roundtrip` 和 `validation-prevent-cycle`,确保 save/load、clipboard 和 validation helper 路线捕获不同 graph document。 - `GraphOperations`: `LAYOUT_PROVIDER_EVIDENCE_EXPANSION` 表示 layout evidence 同步且由宿主拥有,入口是 `UseLayoutProvider(...)` / `IGraphLayoutProvider.CreateLayoutPlan(GraphLayoutRequest)`。`GraphLayoutRequest`、`GraphLayoutPlan`、`PreviewLayoutPlan`、`TryApplyLayoutPlan`、`TryApplyLayoutRequest`、`TrySnapSelectedNodesToGrid` 和 `TrySnapAllNodesToGrid` 继续走 `IGraphEditorSession` commands,并由 `GraphEditorLayoutProviderSeamTests`、`LAYOUT_PROVIDER_SEAM_OK`、`LAYOUT_PREVIEW_APPLY_CANCEL_OK` 和 `LAYOUT_UNDO_TRANSACTION_OK` 验证。这个 proof 不表示 layout execution 已变成异步或可取消。 - `NodeMetadata`: metadata 与 trust evidence 只锚定到 recipe 代码或 proof marker。 diff --git a/docs/zh-CN/phase-0-reactflow-parity-audit.md b/docs/zh-CN/phase-0-reactflow-parity-audit.md index 6cbe6e0b..ec3bd1c3 100644 --- a/docs/zh-CN/phase-0-reactflow-parity-audit.md +++ b/docs/zh-CN/phase-0-reactflow-parity-audit.md @@ -262,6 +262,10 @@ Phase 553 是 GitHub #227 / `avalonia-node-map-9f0`,记录 whiteboard primitiv Phase 554 是 GitHub #228 / `avalonia-node-map-kpy`,记录 whiteboard authoring toolbar and Cookbook UX route。本 hosted Avalonia + Demo/Cookbook slice 把 `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)` 投影到 stock Authoring Tools 行,形成 `PART_WhiteboardDrawingRectangleButton` 和 `PART_WhiteboardDrawingFreehandButton`,并由 `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` 守住。它还新增 `whiteboard-authoring-cookbook-route`、screenshot route `cookbook-whiteboard-authoring-cookbook-route`、shell state `shell-cookbook-whiteboard-authoring-cookbook-route`,并在现有 `selection-marquee-workbench` fixture 上记录 proof marker `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`。Phase 554 stacked after PR #233,不能早于 Phase 553 合并。它不新增 no new core model design、no pointer coordinator redesign、no eraser behavior、no persisted whiteboard primitive state、no GraphDocument schema changes、no renderer rewrite、no retained API removal 或 no full React Flow whiteboard parity。 +## Phase 555 更新 + +Phase 555 是 GitHub #229 / `avalonia-node-map-71c`,记录 whiteboard primitive eraser behavior route。本 hosted Avalonia slice 在 `AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)` 中加入 `NodeCanvasWhiteboardDrawingMode.Eraser`、`whiteboard-drawing.eraser` 和 stock hosted `PART_WhiteboardEraserButton`;该 action 仍是无 runtime command id 的 host-source activation。现有 pointer coordinator 会在 eraser mode 的 left press 中通过 `TryEraseWhiteboardPrimitive(...)` 对当前 transient whiteboard primitives 做 hit-test,只删除 topmost hit primitive,并让 graph-selection delete 与 graph `selection.delete` 保持分离。`TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers` 和 `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection` 守住 primitive hit-testing、no-hit behavior、active-gesture cleanup 与 graph-deletion separation。Phase 555 stacked on Phase 554,不能早于 PR #234 合并。它保持 no broad eraser cursor redesign、no persisted whiteboard primitive state、no GraphDocument schema changes、no renderer rewrite、no retained API removal 和 no full React Flow 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。 @@ -603,6 +607,8 @@ Phase 553 记录 whiteboard primitive pointer gesture capture route,通过 Git Phase 554 记录 whiteboard authoring toolbar and Cookbook UX route,通过 GitHub #228 / `avalonia-node-map-kpy`。它把 `CreateWhiteboardDrawingToolActions(...)` 投影进 stock hosted Authoring Tools chrome,形成 `PART_WhiteboardDrawingRectangleButton` 和 `PART_WhiteboardDrawingFreehandButton`,由 `AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode` 守住,并在 `selection-marquee-workbench` 上记录 `whiteboard-authoring-cookbook-route`、`cookbook-whiteboard-authoring-cookbook-route`、`shell-cookbook-whiteboard-authoring-cookbook-route` 和 `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK`。它不新增 no new core model design、no pointer coordinator redesign、no eraser behavior、no persisted whiteboard primitive state、no GraphDocument schema changes、no renderer rewrite 或 full React Flow whiteboard parity。 +Phase 555 记录 whiteboard primitive eraser behavior route,通过 GitHub #229 / `avalonia-node-map-71c`。它添加 `NodeCanvasWhiteboardDrawingMode.Eraser`、`whiteboard-drawing.eraser` 和 `PART_WhiteboardEraserButton`,并把 eraser-mode press handling 路由到 `TryEraseWhiteboardPrimitive(...)`,让 transient whiteboard primitives 通过 hit-test 被删除,同时不调用 graph `selection.delete`。`TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers` 和 `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection` 守住 graph-selection delete remains separate;broad eraser cursor redesign、persisted whiteboard primitive state、GraphDocument schema changes、renderer rewrites、retained API removal 和 full React Flow whiteboard parity 都保持 out of scope。 + | 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。 | @@ -682,7 +688,7 @@ Phase 554 记录 whiteboard authoring toolbar and Cookbook UX route,通过 Git - `feature/phase-552-whiteboard-tool-activation`:负责 #226 / `avalonia-node-map-718`;Phase 551 之后的 future activation-contract worktree。 - `feature/phase-553-whiteboard-pointer-capture`:负责 #227 / `avalonia-node-map-9f0`;Phase 552 之后的 future pointer gesture capture worktree。 - `visual/phase-554-whiteboard-authoring-cookbook`:负责 #228 / `avalonia-node-map-kpy`;Phase 553 之后的 future hosted authoring toolbar and Cookbook UX worktree。 -- `feature/phase-555-whiteboard-eraser-behavior`:负责 #229 / `avalonia-node-map-71c`;Phase 554 之后的 future eraser-on-primitive behavior worktree。 +- `feature/phase-555-whiteboard-eraser-behavior`:负责 #229 / `avalonia-node-map-71c`;Phase 554 之后的 current stacked implementation worktree,用于 eraser-on-primitive behavior,graph `selection.delete`、persistence/schema、renderer rewrite 和 full whiteboard parity 都保持 out of scope。 - `feature/phase-556-whiteboard-persistence-decision`:负责 #230 / `avalonia-node-map-bck`;Phase 555 之后的 future persistence implementation decision worktree。 ## UI 验证策略 @@ -754,4 +760,5 @@ Phase 554 记录 whiteboard authoring toolbar and Cookbook UX route,通过 Git - Phase 552 是 GitHub #226 / `avalonia-node-map-718`;它通过 `NodeCanvas.WhiteboardDrawingMode`、`NodeCanvasWhiteboardDrawingMode.Rectangle`、`NodeCanvasWhiteboardDrawingMode.Freehand`、`CreateWhiteboardDrawingToolActions(...)`、`whiteboard-drawing.rectangle` 和 `whiteboard-drawing.freehand` 记录 whiteboard drawing tool public activation contract,不新增 runtime command id、pointer gesture capture、runtime drawing creation、toolbar UI implementation、eraser behavior、persistence/schema changes、renderer changes、screenshot manifest expansion 或 full React Flow whiteboard parity。 - Phase 553 是 GitHub #227 / `avalonia-node-map-9f0`;它通过 `NodeCanvasPointerInteractionCoordinator`、`NodeCanvasInteractionSession`、transient internal `GraphWhiteboardPrimitive` state、world-space rectangle/freehand geometry、release commit lifecycle 和 capture-loss cancellation 记录 whiteboard primitive pointer gesture capture route。Runtime command ids、toolbar UI implementation、eraser behavior、persisted whiteboard primitive state、GraphDocument schema changes、renderer changes、screenshot manifest expansion 和 full React Flow whiteboard parity 都保持 out of scope。 - Phase 554 是 GitHub #228 / `avalonia-node-map-kpy`;它通过 `whiteboard-authoring-cookbook-route`、`CreateWhiteboardDrawingToolActions(...)`、`AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode`、`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton`、`cookbook-whiteboard-authoring-cookbook-route`、`shell-cookbook-whiteboard-authoring-cookbook-route` 和 `WHITEBOARD_AUTHORING_COOKBOOK_UX_OK` 记录 whiteboard authoring toolbar and Cookbook UX route。New core model design、pointer coordinator redesign、eraser behavior、persisted whiteboard primitive state、GraphDocument schema changes、renderer rewrites 和 full React Flow whiteboard parity 都保持 out of scope。 +- Phase 555 是 GitHub #229 / `avalonia-node-map-71c`;它通过 `NodeCanvasWhiteboardDrawingMode.Eraser`、`whiteboard-drawing.eraser`、`PART_WhiteboardEraserButton`、`TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers` 和 `HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection` 记录 whiteboard primitive eraser behavior route。Graph-selection delete 仍通过 graph `selection.delete` 分离;broad eraser cursor redesign、persisted whiteboard primitive state、GraphDocument schema changes、renderer rewrites、retained API removal 和 full React Flow whiteboard parity 都保持 out of scope。 - Phase 478、Phase 484、Phase 490、Phase 491、Phase 492、Phase 493、Phase 494、Phase 495、Phase 497、Phase 498、Phase 499、Phase 500、Phase 501、Phase 502、Phase 503、Phase 504、Phase 505、Phase 506、Phase 507、Phase 508、Phase 509、Phase 510、Phase 511、Phase 512、Phase 513、Phase 520、Phase 521、Phase 522、Phase 523、Phase 524、Phase 525、Phase 526、Phase 527、Phase 528、Phase 529、Phase 535、Phase 539、Phase 540、Phase 541、Phase 546、Phase 550 和 Phase 551 都不修改产品代码;除非 focused test 证明存在具体 missing contract。 diff --git a/docs/zh-CN/public-api-inventory.md b/docs/zh-CN/public-api-inventory.md index 89afa36f..0cd5d53d 100644 --- a/docs/zh-CN/public-api-inventory.md +++ b/docs/zh-CN/public-api-inventory.md @@ -45,7 +45,7 @@ | Phase 530 lasso selection query route | Stable canonical | `IGraphEditorQueries.GetSelectionLassoSnapshot(...)`、`GraphEditorSelectionLassoSnapshot`、`GraphEditorSelectionLassoSnapshot.NodeIds`、`GraphEditorSelectionLassoSnapshot.ConnectionIds` | 面向自定义 UI 的 backend/editor lasso query route;宿主自行捕获 freeform polygon points 后调用。该 query 仍走 session route,读取 active-scope graph state,用 center-point polygon containment 选择 node,并且只在 connection 两端 node 都被选中时选择 connection。不新增 Avalonia gesture capture、pointer-mode state、drawing primitives、eraser behavior、persistence、renderer changes、screenshot rows 或 full React Flow whiteboard parity。 | | Phase 533 lasso pointer-mode route | Supported hosted helper | `NodeCanvas.SelectionMode`、`NodeCanvasSelectionMode.Marquee`、`NodeCanvasSelectionMode.Lasso` | stock canvas lasso selection 的 hosted Avalonia activation path。Marquee 仍是默认;宿主可为 empty-canvas selection drag 选择 lasso。它复用现有 backend lasso query 与 Avalonia lasso bridge,不新增 toolbar UX、visual gesture capture、screenshot rows、eraser behavior、drawing primitives、persistence、renderer changes 或 full React Flow whiteboard parity。 | | Phase 537 lasso toolbar ergonomics route | Supported hosted helper | `AsterGraphAuthoringToolActionFactory.CreatePointerSelectionModeActions(...)`、`pointer-mode.marquee-selection`、`pointer-mode.lasso-selection`、`NodeCanvas.SelectionMode`、`NodeCanvasSelectionMode.Lasso` | 用 hosted toolbar action projection 在 stock canvas 的 marquee 与 lasso selection 之间切换。这个 helper 只写现有 `NodeCanvas.SelectionMode` property,返回无 runtime command id 的 host-source actions,不新增第二套 selection model、eraser behavior、drawing primitives、persistence、renderer changes、strict pixel baselines、retained API removal 或 full React Flow whiteboard parity。 | -| Phase 552-554 whiteboard drawing activation, pointer gesture, and hosted toolbar route | Supported hosted helper | `NodeCanvas.WhiteboardDrawingMode`、`NodeCanvasWhiteboardDrawingMode.None`、`NodeCanvasWhiteboardDrawingMode.Rectangle`、`NodeCanvasWhiteboardDrawingMode.Freehand`、`AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)`、`whiteboard-drawing.rectangle`、`whiteboard-drawing.freehand`、`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton` | rectangle/freehand whiteboard primitives 的 hosted activation contract 和 stock-canvas internal pointer gesture capture。这个 helper 只写 `NodeCanvas.WhiteboardDrawingMode` property,返回 no runtime command id 的 host-source actions;现有 canvas pointer coordinator 会在 left-drag 时消费 active mode,创建 transient internal primitive state。Stock hosted `GraphEditorView` 现在会把这些 actions 投影到 Authoring Tools toolbar,形成 `PART_WhiteboardDrawingRectangleButton` 和 `PART_WhiteboardDrawingFreehandButton`。不新增 runtime command route、eraser behavior、persistence/schema changes、renderer changes、retained API removal 或 full React Flow whiteboard parity。 | +| Phase 552-555 whiteboard drawing activation, pointer gesture, hosted toolbar, and primitive eraser route | Supported hosted helper | `NodeCanvas.WhiteboardDrawingMode`、`NodeCanvasWhiteboardDrawingMode.None`、`NodeCanvasWhiteboardDrawingMode.Rectangle`、`NodeCanvasWhiteboardDrawingMode.Freehand`、`NodeCanvasWhiteboardDrawingMode.Eraser`、`AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(...)`、`whiteboard-drawing.rectangle`、`whiteboard-drawing.freehand`、`whiteboard-drawing.eraser`、`PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton`、`PART_WhiteboardEraserButton` | rectangle/freehand whiteboard primitives 的 hosted activation contract、stock-canvas internal pointer gesture capture,以及 eraser-on-transient-primitive behavior。这个 helper 只写 `NodeCanvas.WhiteboardDrawingMode` property,返回 no runtime command id 的 host-source actions;现有 canvas pointer coordinator 会在 left-drag 时消费 rectangle/freehand mode,创建 transient internal primitive state,并在 eraser mode 下通过 hit-test/remove 处理 whiteboard primitives,而不调用 graph `selection.delete`。Stock hosted `GraphEditorView` 会把这些 actions 投影到 Authoring Tools toolbar,形成 `PART_WhiteboardDrawingRectangleButton`、`PART_WhiteboardDrawingFreehandButton` 和 `PART_WhiteboardEraserButton`。不新增 runtime command route、persisted whiteboard primitive state、persistence/schema changes、renderer changes、retained API removal 或 full React Flow whiteboard parity。 | | Shipped Avalonia UI | Supported hosted helper | `AsterGraphEditorFactory.Create(...)`、`AsterGraphAvaloniaViewFactory.Create(...)` | 使用同一个 runtime owner,不是第二套 runtime model。 | | Thin hosted builder | Supported hosted helper | `AsterGraphHostBuilder.Create(...).UseDefaultWorkbench().UseLayoutProvider(...).BuildAvaloniaView()` | 减少常见 Avalonia 组合样板,并委托给 canonical factories;这些 pass-through 暴露现有 `AsterGraphEditorOptions` seam,包括 host-owned synchronous layout provider seam;`AsterGraphWorkbenchOptions` 只控制 stock hosted chrome。 | | Built-in component catalog | Supported hosted helper | `AsterGraphBuiltInComponentCatalog.Components`、`AsterGraphBuiltInComponentCatalog.TryGet(...)`、`AsterGraphBuiltInComponentDescriptor`、`AsterGraphBuiltInComponentStatus`、`AsterGraphControls`、`NodeToolbar`、`EdgeToolbar`、`NodeResizer`、`AsterGraphPanel` | Phase 3 的内置 component track discovery map。Public 条目指向现有 canvas、minimap、background-grid、inspector、controls-panel、`controls`、command-tool-projection、`node-toolbar`、`edge-toolbar`、`node-resizer` 和 `panel` surface。`AsterGraphControls` 是基于 `IGraphEditorSession.Commands.TryExecuteCommand(...)` 的薄 Avalonia viewport 控件,覆盖 zoom、fit 和 reset action;`NodeToolbar` 与 `EdgeToolbar` 是基于 `AsterGraphAuthoringToolActionFactory.CreateNodeActions(...)` 和 `CreateConnectionActions(...)` 的薄 Avalonia 控件;`NodeResizer` 是基于 `IGraphEditorSession.Commands.TrySetNodeSize(...)` 的薄 Avalonia 控件;`AsterGraphPanel` 是宿主自管内容的定位 overlay primitive。 | diff --git a/eng/public-api-baseline.txt b/eng/public-api-baseline.txt index 6cebd570..8af3a173 100644 --- a/eng/public-api-baseline.txt +++ b/eng/public-api-baseline.txt @@ -349,6 +349,7 @@ F:AsterGraph.Avalonia.Controls.NodeCanvas.ViewModelProperty:Avalonia.StyledPrope F:AsterGraph.Avalonia.Controls.NodeCanvas.WhiteboardDrawingModeProperty:Avalonia.StyledProperty F:AsterGraph.Avalonia.Controls.NodeCanvasSelectionMode.Lasso:AsterGraph.Avalonia.Controls.NodeCanvasSelectionMode F:AsterGraph.Avalonia.Controls.NodeCanvasSelectionMode.Marquee:AsterGraph.Avalonia.Controls.NodeCanvasSelectionMode +F:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode.Eraser:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode F:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode.Freehand:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode F:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode.None:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode F:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode.Rectangle:AsterGraph.Avalonia.Controls.NodeCanvasWhiteboardDrawingMode diff --git a/src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs b/src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs index 211e7462..b61cd890 100644 --- a/src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs +++ b/src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs @@ -606,6 +606,7 @@ private static string ResolveWhiteboardDrawingToolButtonName(AsterGraphHostedAct { "whiteboard-drawing.rectangle" => "PART_WhiteboardDrawingRectangleButton", "whiteboard-drawing.freehand" => "PART_WhiteboardDrawingFreehandButton", + "whiteboard-drawing.eraser" => "PART_WhiteboardEraserButton", _ => $"PART_WhiteboardDrawing_{action.Id}", }; diff --git a/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasInteractionSession.cs b/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasInteractionSession.cs index 1b1cb8eb..53f4d53c 100644 --- a/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasInteractionSession.cs +++ b/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasInteractionSession.cs @@ -382,6 +382,20 @@ public void UpdateWhiteboardPrimitiveDrawing(Point currentScreenPosition, GraphP return committed; } + public bool TryEraseWhiteboardPrimitive(GraphPoint worldPosition) + { + var scene = GraphWhiteboardPrimitiveRendererAdapter.Project(_whiteboardPrimitives); + var hit = GraphWhiteboardPrimitiveRendererAdapter.HitTest(scene, worldPosition); + if (hit is null) + { + return false; + } + + ClearActiveWhiteboardPrimitive(); + return _whiteboardPrimitives.RemoveAll( + primitive => string.Equals(primitive.Id, hit.PrimitiveId, StringComparison.Ordinal)) > 0; + } + public void UpdatePointerPosition(Point currentScreenPosition) => PointerScreenPosition = currentScreenPosition; diff --git a/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasPointerInteractionCoordinator.cs b/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasPointerInteractionCoordinator.cs index b96b01fc..add518b4 100644 --- a/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasPointerInteractionCoordinator.cs +++ b/src/AsterGraph.Avalonia/Controls/Internal/Interaction/NodeCanvasPointerInteractionCoordinator.cs @@ -463,6 +463,12 @@ private bool HandleNodeResizeMove(NodeCanvasNodeResizeSession resizeSession, Poi private bool TryBeginWhiteboardPrimitiveDrawing(Point currentScreenPosition) { + if (_host.WhiteboardDrawingMode is NodeCanvasWhiteboardDrawingMode.Eraser) + { + _host.InteractionSession.TryEraseWhiteboardPrimitive(ScreenToWorld(currentScreenPosition)); + return true; + } + var kind = _host.WhiteboardDrawingMode switch { NodeCanvasWhiteboardDrawingMode.Rectangle => GraphWhiteboardPrimitiveKind.Rectangle, diff --git a/src/AsterGraph.Avalonia/Controls/NodeCanvasWhiteboardDrawingMode.cs b/src/AsterGraph.Avalonia/Controls/NodeCanvasWhiteboardDrawingMode.cs index 2b6fdd36..8000b6c5 100644 --- a/src/AsterGraph.Avalonia/Controls/NodeCanvasWhiteboardDrawingMode.cs +++ b/src/AsterGraph.Avalonia/Controls/NodeCanvasWhiteboardDrawingMode.cs @@ -19,4 +19,9 @@ public enum NodeCanvasWhiteboardDrawingMode /// Freehand whiteboard drawing is selected for the canvas pointer capture route. /// Freehand, + + /// + /// Whiteboard primitive erasing is selected for the canvas pointer capture route. + /// + Eraser, } diff --git a/src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs b/src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs index cf761d01..eecfc810 100644 --- a/src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs +++ b/src/AsterGraph.Avalonia/Hosting/AsterGraphAuthoringToolActionFactory.cs @@ -44,6 +44,12 @@ public static IReadOnlyList CreateWhiteboardDr "Freehand Drawing Tool", "Activate freehand whiteboard drawing for canvas pointer capture.", NodeCanvasWhiteboardDrawingMode.Freehand), + CreateWhiteboardDrawingToolAction( + canvas, + "whiteboard-drawing.eraser", + "Whiteboard Eraser Tool", + "Activate whiteboard primitive erasing without using graph selection deletion.", + NodeCanvasWhiteboardDrawingMode.Eraser), ]; } diff --git a/src/AsterGraph.Demo/Cookbook/DemoCookbookCatalog.Recipes.cs b/src/AsterGraph.Demo/Cookbook/DemoCookbookCatalog.Recipes.cs index 814d7408..8feabf57 100644 --- a/src/AsterGraph.Demo/Cookbook/DemoCookbookCatalog.Recipes.cs +++ b/src/AsterGraph.Demo/Cookbook/DemoCookbookCatalog.Recipes.cs @@ -1451,7 +1451,7 @@ public static partial class DemoCookbookCatalog "whiteboard-authoring-cookbook-route", DemoCookbookRecipeCategory.Authoring, "Whiteboard authoring toolbar and Cookbook UX route", - "Expose rectangle/freehand whiteboard drawing actions in the hosted authoring toolbar and capture the bounded Cookbook UX route.", + "Expose rectangle/freehand whiteboard drawing actions and the bounded primitive eraser in the hosted authoring toolbar.", [ new DemoCookbookAnchor( "Whiteboard drawing action factory", @@ -1465,6 +1465,10 @@ public static partial class DemoCookbookCatalog "Hosted freehand drawing button", "src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs", "PART_WhiteboardDrawingFreehandButton"), + new DemoCookbookAnchor( + "Hosted whiteboard eraser button", + "src/AsterGraph.Avalonia/Controls/GraphEditorView.AuthoringTools.cs", + "PART_WhiteboardEraserButton"), new DemoCookbookAnchor( "Canvas drawing activation property", "src/AsterGraph.Avalonia/Controls/NodeCanvas.axaml.cs", @@ -1501,7 +1505,7 @@ public static partial class DemoCookbookCatalog [ new DemoCookbookScenarioPoint( DemoCookbookScenarioKind.HostCodeExample, - "Hosts use CreateWhiteboardDrawingToolActions to surface rectangle/freehand activation without runtime command ids.", + "Hosts use CreateWhiteboardDrawingToolActions to surface rectangle/freehand/eraser activation without runtime command ids.", "CreateWhiteboardDrawingToolActions"), new DemoCookbookScenarioPoint( DemoCookbookScenarioKind.GraphOperations, @@ -1509,17 +1513,17 @@ public static partial class DemoCookbookCatalog "selection-marquee-workbench"), new DemoCookbookScenarioPoint( DemoCookbookScenarioKind.ValidationRuntimeOverlay, - "The shell visual gate keeps the node canvas, Cookbook route panel, and whiteboard drawing buttons visible together.", + "The shell visual gate keeps the node canvas, Cookbook route panel, and whiteboard drawing/eraser buttons visible together.", "shell-cookbook-whiteboard-authoring-cookbook-route"), new DemoCookbookScenarioPoint( DemoCookbookScenarioKind.SupportEvidence, - "The proof marker binds hosted toolbar projection, route metadata, and non-overlap evidence to Phase 554.", + "The proof marker binds hosted toolbar projection, route metadata, and non-overlap evidence to the Phase 554/555 whiteboard authoring route.", "WHITEBOARD_AUTHORING_COOKBOOK_UX_OK"), ], [ new DemoCookbookInteractionFacet( DemoCookbookInteractionKind.Selection, - "Whiteboard activation stays beside existing pointer-mode controls and writes only the canvas whiteboard drawing mode property.", + "Whiteboard activation stays beside existing pointer-mode controls, writes only the canvas whiteboard drawing mode property, and keeps erasing separate from graph selection deletion.", "WhiteboardDrawingModeProperty"), new DemoCookbookInteractionFacet( DemoCookbookInteractionKind.LayoutReadability, @@ -1531,7 +1535,7 @@ public static partial class DemoCookbookCatalog "cookbook-whiteboard-authoring-cookbook-route"), new DemoCookbookInteractionFacet( DemoCookbookInteractionKind.ValidationRuntimeFeedback, - "The editor proof clicks rectangle/freehand buttons and verifies the canvas drawing mode transition.", + "The editor proof clicks rectangle/freehand/eraser buttons and verifies the canvas drawing mode transition.", "AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode"), ], [ @@ -1540,10 +1544,10 @@ public static partial class DemoCookbookCatalog "AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanvasDrawingMode", ], new DemoCookbookRouteClarity( - "Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton and PART_WhiteboardDrawingFreehandButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench.", - "Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, and `WhiteboardDrawingModeProperty`; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged.", - "Demo cookbook supplies route metadata and shell part proof only; no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity."), - "Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, and non-overlap proof; it adds no new core model design, no pointer coordinator redesign, no eraser behavior, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity.", + "Whiteboard authoring toolbar and Cookbook UX route: hosted Authoring Tools projects CreateWhiteboardDrawingToolActions into PART_WhiteboardDrawingRectangleButton, PART_WhiteboardDrawingFreehandButton, and PART_WhiteboardEraserButton, then captures cookbook-whiteboard-authoring-cookbook-route on selection-marquee-workbench.", + "Supported seams live in `AsterGraph.Avalonia` action factory, `GraphEditorView` hosted chrome, `WhiteboardDrawingModeProperty`, and the existing internal whiteboard primitive interaction path; `AsterGraph.Editor` and `AsterGraph.Core` ownership stays unchanged.", + "Demo cookbook supplies route metadata and shell part proof only; primitive erasing remains bounded to transient whiteboard primitives, with no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity."), + "Whiteboard authoring UX coverage is limited to hosted action projection, visible toolbar parts, route/shell metadata, non-overlap proof, and bounded primitive erasing; it adds no new core model design, no pointer coordinator redesign, no broad eraser cursor redesign, no persisted whiteboard primitive state, no GraphDocument schema changes, no renderer rewrite, and no full whiteboard parity.", CodeSample: """ // Project the hosted drawing actions beside the pointer-mode controls. var actions = AsterGraphAuthoringToolActionFactory.CreateWhiteboardDrawingToolActions(canvas); @@ -1551,8 +1555,9 @@ public static partial class DemoCookbookCatalog // The stock hosted toolbar exposes these as visible proof parts. const string rectangleButton = "PART_WhiteboardDrawingRectangleButton"; const string freehandButton = "PART_WhiteboardDrawingFreehandButton"; + const string eraserButton = "PART_WhiteboardEraserButton"; - // Cookbook proof uses selection-marquee-workbench and shell metadata only. + // Eraser mode removes transient whiteboard primitives without invoking selection.delete. const string routeId = "cookbook-whiteboard-authoring-cookbook-route"; const string shellStateId = "shell-cookbook-whiteboard-authoring-cookbook-route"; """ diff --git a/tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json b/tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json index 6d1a0c29..2668de40 100644 --- a/tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json +++ b/tests/AsterGraph.Demo.Tests/CookbookShellVisualGateStates.json @@ -151,6 +151,7 @@ "PART_NodeCanvas", "PART_WhiteboardDrawingRectangleButton", "PART_WhiteboardDrawingFreehandButton", + "PART_WhiteboardEraserButton", "PART_MainGraphEditorHost", "PART_CookbookWorkspaceRecipeContentPanel" ], diff --git a/tests/AsterGraph.Demo.Tests/DemoCookbookBuiltInBatchTests.cs b/tests/AsterGraph.Demo.Tests/DemoCookbookBuiltInBatchTests.cs index 1e61df6d..2c0bcbca 100644 --- a/tests/AsterGraph.Demo.Tests/DemoCookbookBuiltInBatchTests.cs +++ b/tests/AsterGraph.Demo.Tests/DemoCookbookBuiltInBatchTests.cs @@ -76,6 +76,7 @@ public void CookbookCatalog_AddsWhiteboardAuthoringCookbookRoute() Assert.Contains("WHITEBOARD_AUTHORING_COOKBOOK_UX_OK", recipe.ProofMarkers); Assert.Contains("PART_WhiteboardDrawingRectangleButton", recipe.RouteClarity.SupportedRoute, StringComparison.Ordinal); Assert.Contains("PART_WhiteboardDrawingFreehandButton", recipe.RouteClarity.SupportedRoute, StringComparison.Ordinal); + Assert.Contains("PART_WhiteboardEraserButton", recipe.RouteClarity.SupportedRoute, StringComparison.Ordinal); Assert.DoesNotContain("GraphDocument schema", recipe.Summary, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("full React Flow whiteboard parity", recipe.RouteClarity.SupportedRoute, StringComparison.OrdinalIgnoreCase); } diff --git a/tests/AsterGraph.Demo.Tests/DemoCookbookScreenshotGateTests.cs b/tests/AsterGraph.Demo.Tests/DemoCookbookScreenshotGateTests.cs index 394c4212..1e7968fc 100644 --- a/tests/AsterGraph.Demo.Tests/DemoCookbookScreenshotGateTests.cs +++ b/tests/AsterGraph.Demo.Tests/DemoCookbookScreenshotGateTests.cs @@ -347,6 +347,7 @@ public void CookbookScreenshotGate_IncludesPhase554WhiteboardAuthoringCookbookRo Assert.Contains("PART_CookbookWorkspaceRecipeContentPanel", shellState.RequiredShellParts, StringComparer.Ordinal); Assert.Contains("PART_WhiteboardDrawingRectangleButton", shellState.RequiredShellParts, StringComparer.Ordinal); Assert.Contains("PART_WhiteboardDrawingFreehandButton", shellState.RequiredShellParts, StringComparer.Ordinal); + Assert.Contains("PART_WhiteboardEraserButton", shellState.RequiredShellParts, StringComparer.Ordinal); Assert.Equal("shell-cookbook-whiteboard-authoring-cookbook-route.png", shellState.OutputFileName); } diff --git a/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs b/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs index 210e3849..bdd5c5f8 100644 --- a/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs +++ b/tests/AsterGraph.Demo.Tests/ReactFlowParityRoadmapDocsTests.cs @@ -1677,7 +1677,6 @@ public void ParityRoadmapDocs_RecordPhase554WhiteboardAuthoringCookbookUxRouteIn Assert.Contains("shell-cookbook-whiteboard-authoring-cookbook-route", contents, StringComparison.Ordinal); Assert.Contains("no new core model design", contents, StringComparison.OrdinalIgnoreCase); Assert.Contains("no pointer coordinator redesign", contents, StringComparison.OrdinalIgnoreCase); - Assert.Contains("no eraser behavior", contents, StringComparison.OrdinalIgnoreCase); Assert.Contains("no persisted whiteboard primitive", contents, StringComparison.OrdinalIgnoreCase); Assert.Contains("no GraphDocument schema", contents, StringComparison.OrdinalIgnoreCase); Assert.Contains("no renderer rewrite", contents, StringComparison.OrdinalIgnoreCase); @@ -1700,6 +1699,53 @@ public void ParityRoadmapDocs_RecordPhase554WhiteboardAuthoringCookbookUxRouteIn Assert.Contains("Phase 554 记录 whiteboard authoring toolbar and Cookbook UX route", chineseParity, StringComparison.Ordinal); } + [Fact] + public void ParityRoadmapDocs_RecordPhase555WhiteboardPrimitiveEraserBehaviorRouteInBothLocales() + { + var englishParity = ReadRepoFile("docs/en/phase-0-reactflow-parity-audit.md"); + var chineseParity = ReadRepoFile("docs/zh-CN/phase-0-reactflow-parity-audit.md"); + var englishCookbook = ReadRepoFile("docs/en/demo-cookbook.md"); + var chineseCookbook = ReadRepoFile("docs/zh-CN/demo-cookbook.md"); + var englishInventory = ReadRepoFile("docs/en/public-api-inventory.md"); + var chineseInventory = ReadRepoFile("docs/zh-CN/public-api-inventory.md"); + var englishRecipe = ReadRepoFile("docs/en/authoring-surface-recipe.md"); + var chineseRecipe = ReadRepoFile("docs/zh-CN/authoring-surface-recipe.md"); + + foreach (var contents in new[] { englishParity, chineseParity }) + { + Assert.Contains("Phase 555", contents, StringComparison.Ordinal); + Assert.Contains("GitHub #229", contents, StringComparison.Ordinal); + Assert.Contains("avalonia-node-map-71c", contents, StringComparison.Ordinal); + Assert.Contains("whiteboard primitive eraser behavior route", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("NodeCanvasWhiteboardDrawingMode.Eraser", contents, StringComparison.Ordinal); + Assert.Contains("whiteboard-drawing.eraser", contents, StringComparison.Ordinal); + Assert.Contains("PART_WhiteboardEraserButton", contents, StringComparison.Ordinal); + Assert.Contains("TryEraseWhiteboardPrimitive_RemovesTopmostHitPrimitiveWithoutClearingOthers", contents, StringComparison.Ordinal); + Assert.Contains("HandlePressed_WithWhiteboardEraserMode_RemovesHitPrimitiveWithoutDeletingGraphSelection", contents, StringComparison.Ordinal); + Assert.Contains("selection.delete", contents, StringComparison.Ordinal); + Assert.Contains("graph-selection delete remains separate", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no broad eraser cursor redesign", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no persisted whiteboard primitive state", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no GraphDocument schema", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no renderer rewrite", contents, StringComparison.OrdinalIgnoreCase); + Assert.Contains("no full React Flow whiteboard parity", contents, StringComparison.OrdinalIgnoreCase); + } + + foreach (var contents in new[] { englishCookbook, chineseCookbook, englishInventory, chineseInventory, englishRecipe, chineseRecipe }) + { + Assert.Contains("NodeCanvasWhiteboardDrawingMode.Eraser", contents, StringComparison.Ordinal); + Assert.Contains("whiteboard-drawing.eraser", contents, StringComparison.Ordinal); + Assert.Contains("PART_WhiteboardEraserButton", contents, StringComparison.Ordinal); + Assert.Contains("selection.delete", contents, StringComparison.Ordinal); + Assert.Contains("no runtime command id", contents, StringComparison.OrdinalIgnoreCase); + } + + AssertPostPhase551Queue(ExtractIssueWaveTable(englishParity)); + AssertPostPhase551Queue(ExtractIssueWaveTable(chineseParity)); + Assert.Contains("Phase 555 records the whiteboard primitive eraser behavior route", englishParity, StringComparison.Ordinal); + Assert.Contains("Phase 555 记录 whiteboard primitive eraser behavior route", chineseParity, StringComparison.Ordinal); + } + [Fact] public void ParityRoadmapDocs_RecordPhase501PostPhase500QueueRefreshInBothLocales() { diff --git a/tests/AsterGraph.Editor.Tests/GraphEditorActionContributionContractTests.cs b/tests/AsterGraph.Editor.Tests/GraphEditorActionContributionContractTests.cs index b8dd702e..59dadd39 100644 --- a/tests/AsterGraph.Editor.Tests/GraphEditorActionContributionContractTests.cs +++ b/tests/AsterGraph.Editor.Tests/GraphEditorActionContributionContractTests.cs @@ -134,7 +134,7 @@ public void HostedActions_PointerModeActionsSwitchNodeCanvasSelectionModeWithout Assert.Equal(NodeCanvasSelectionMode.Lasso, canvas.SelectionMode); Assert.Equal(NodeCanvasWhiteboardDrawingMode.None, canvas.WhiteboardDrawingMode); - canvas.WhiteboardDrawingMode = NodeCanvasWhiteboardDrawingMode.Freehand; + canvas.WhiteboardDrawingMode = NodeCanvasWhiteboardDrawingMode.Eraser; Assert.True(lassoAction.TryExecute()); @@ -156,13 +156,17 @@ public void HostedActions_WhiteboardDrawingToolActionsSwitchNodeCanvasDrawingMod var rectangleAction = Assert.Single(actions, action => action.Id == "whiteboard-drawing.rectangle"); var freehandAction = Assert.Single(actions, action => action.Id == "whiteboard-drawing.freehand"); + var eraserAction = Assert.Single(actions, action => action.Id == "whiteboard-drawing.eraser"); Assert.Equal("Rectangle Drawing Tool", rectangleAction.Title); Assert.Equal("Freehand Drawing Tool", freehandAction.Title); + Assert.Equal("Whiteboard Eraser Tool", eraserAction.Title); Assert.Equal(GraphEditorCommandSourceKind.Host, rectangleAction.CommandSource); Assert.Equal(GraphEditorCommandSourceKind.Host, freehandAction.CommandSource); + Assert.Equal(GraphEditorCommandSourceKind.Host, eraserAction.CommandSource); Assert.Null(rectangleAction.CommandId); Assert.Null(freehandAction.CommandId); + Assert.Null(eraserAction.CommandId); Assert.Equal(NodeCanvasSelectionMode.Marquee, canvas.SelectionMode); Assert.Equal(NodeCanvasWhiteboardDrawingMode.None, canvas.WhiteboardDrawingMode); @@ -177,6 +181,13 @@ public void HostedActions_WhiteboardDrawingToolActionsSwitchNodeCanvasDrawingMod Assert.Equal(NodeCanvasSelectionMode.Marquee, canvas.SelectionMode); Assert.Equal(NodeCanvasWhiteboardDrawingMode.Rectangle, canvas.WhiteboardDrawingMode); + + canvas.SelectionMode = NodeCanvasSelectionMode.Lasso; + + Assert.True(eraserAction.TryExecute()); + + Assert.Equal(NodeCanvasSelectionMode.Marquee, canvas.SelectionMode); + Assert.Equal(NodeCanvasWhiteboardDrawingMode.Eraser, canvas.WhiteboardDrawingMode); } [Fact] @@ -190,6 +201,7 @@ public void CommandRegistry_DoesNotExposeWhiteboardDrawingToolActivationAsRuntim Assert.DoesNotContain("whiteboard-drawing.rectangle", commandIds); Assert.DoesNotContain("whiteboard-drawing.freehand", commandIds); + Assert.DoesNotContain("whiteboard-drawing.eraser", commandIds); } private static void AssertPlacement( diff --git a/tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs b/tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs index 8ecfaca1..ff1b7d8e 100644 --- a/tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs +++ b/tests/AsterGraph.Editor.Tests/GraphEditorViewTests.cs @@ -1195,6 +1195,7 @@ public void AuthoringToolsChrome_ProjectsWhiteboardDrawingActionsThroughNodeCanv var canvas = FindRequiredControl(view, "PART_NodeCanvas"); var rectangleButton = FindRequiredDescendant