Refine canvas features and fix agent neighbourhood issues - #149
Conversation
There was a problem hiding this comment.
Pull request overview
This PR tightens and clarifies how Huabu derives “neighbourhood” context for agents on the canvas (more bounded spatial selection but never missing explicitly connected context), while also consolidating Markdown math normalization + provenance block fingerprinting so server and Milkdown stay in parity. It also improves several UX mechanics around note preview search/highlighting, copy shortcuts, drag previews, and question-node lifecycle persistence, with corresponding tests and architecture doc updates.
Changes:
- Refines server-side canvas neighbourhood selection (400px radius for spatial neighbours, always include directly connected nodes, always include containing frame + direct siblings) and adds targeted tests/docs.
- Moves/exports math delimiter normalization into
@huabu/shared/canvas-engineand updates provenance fingerprinting + parity tests (including reference link/image canonicalization). - Improves web UX plumbing: preview search boundaries/highlighting consistency, Cmd/Ctrl+C native-copy preservation only when text is actually selected, drag preview compensation for detached nodes, and question status persistence behavior.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/shared/src/canvas-engine/provenance/normalizeMathDelimiters.ts | New shared math-delimiter normalization utility (fence/inline-code aware). |
| packages/shared/src/canvas-engine/provenance/blockFingerprint.ts | Normalizes math before parsing; canonicalizes reference link/image nodes; excludes definition blocks from fingerprinting. |
| packages/shared/src/canvas-engine/index.ts | Re-exports normalizeMathDelimiters for shared consumption. |
| packages/shared/src/canvas-engine/tests/noteProvenance.executor.test.ts | Adds provenance tests for reference links/images and LaTeX-style math canonicalization. |
| docs/architecture/web-architecture.md | Documents copy behavior when selection exists vs collapsed caret/focus. |
| docs/architecture/question-node.md | Updates neighbourhood contract documentation (priority tiers + 400px radius). |
| docs/architecture/note-node.md | Documents preview search boundary behavior + provenance fingerprint normalization details. |
| docs/architecture/canvas-zoom-rendering.md | Updates documented minimum zoom to 0.05. |
| docs/architecture/canvas-command-architecture.md | Documents compensated drag-preview positioning behavior for detached nodes. |
| docs/architecture/agent-context.md | Documents bounded neighbourhood behavior and unconditional inclusions. |
| apps/web/src/store/conversationOwner.ts | Adjusts compose gating to consider authored content; persists lifecycle patches via canonical executor; optimistic local reflection. |
| apps/web/src/store/conversationOwner.test.ts | Updates expectations to reflect persistence; adds compose gating coverage for content. |
| apps/web/src/store/canvasStore/load/reconcileQuestionStatus.ts | Stops inferring done from thread/content; only strips legacy runAt. |
| apps/web/src/store/canvasStore/load/reconcileQuestionStatus.test.ts | Adds coverage for “don’t infer success” + terminal preservation + runAt removal. |
| apps/web/src/store/canvasStore.ts | Uses compensated geometry previews for dragged nodes when preview detaches from a frame. |
| apps/web/src/hooks/useTextHighlight.ts | Switches to shared DOM-search implementation; updates MutationObserver to watch attribute changes affecting visibility/search roots. |
| apps/web/src/hooks/useCanvasGestures.test.ts | Updates zoom clamp tests for new MIN_ZOOM. |
| apps/web/src/hooks/shortcuts/useCanvasShortcuts.ts | Preserves native copy only when there’s an actual selection; otherwise copies selected nodes. |
| apps/web/src/hooks/shortcuts/useCanvasShortcuts.lockKeys.test.ts | Adds shortcut tests for “focused editor with caret vs selection” copy behavior. |
| apps/web/src/hooks/searchDom.ts | Centralizes search root selection + visibility exclusion rules; exports findRanges for reuse. |
| apps/web/src/hooks/searchDom.test.ts | Adds coverage for preview search roots and navigation. |
| apps/web/src/handler/liveDragGeometry.ts | Adds compensateDetachedDragPosition to keep world position stable during frame-detach previews. |
| apps/web/src/handler/liveDragGeometry.test.ts | Adds tests for detached-drag compensation behavior. |
| apps/web/src/config/canvas.ts | Lowers MIN_ZOOM to 0.05 (shared clamp source of truth). |
| apps/web/src/components/Nodes/question/QuestionNode.tsx | Allows reopening chat when there’s conversation evidence beyond explicit terminal status. |
| apps/web/src/components/Nodes/note/NotePreview.tsx | Wraps editors in div.contents[data-preview-search-content] to define searchable DOM boundary. |
| apps/web/src/components/Milkdown/markdownUtils.ts | Re-exports shared normalizeMathDelimiters and removes local implementation. |
| apps/web/src/components/Milkdown/tests/blockFingerprintParity.test.ts | Normalizes math in harness; adds many agent-style markdown parity cases. |
| apps/server/src/modules/canvas/node-neighbourhood.ts | Implements bounded radius + unconditional connected/frame/sibling inclusions; updates relevant edge selection accordingly. |
| apps/server/src/modules/canvas/node-neighbourhood.test.ts | Adds coverage for new neighbourhood inclusion rules. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This pull request introduces several improvements and refactorings related to neighbourhood context calculation in the canvas module, markdown math normalization, and UI structure for note previews. The most significant changes include stricter spatial neighbourhood selection, improved handling of explicit node connections, refactoring math delimiter normalization for better testability and code reuse, and enhanced test coverage for markdown round-tripping.
Canvas neighbourhood calculation improvements:
buildNodeNeighbourhoodContextwas reduced from 2000 to 400, making spatial neighbour selection stricter and more focused. [1] [2]Markdown math normalization and testing:
normalizeMathDelimitersfunction was moved to@huabu/shared/canvas-engineand re-exported for consistent use and easier testing; its local implementation was removed. [1] [2]UI structure improvements:
div.contentswith adata-preview-search-contentattribute, improving searchability and DOM structure. [1] [2] [3] [4]Testing and coverage:
buildNodeNeighbourhoodContext, covering spatial neighbours, frame and sibling retention, and explicit connection inclusion.