first
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# Graph Interaction Risk Audit
|
||||
|
||||
日期:2026-06-16
|
||||
|
||||
适用计划:`docs/plans/2026-06-16-graph-six-layer-architecture-phased-plan.md`
|
||||
|
||||
## 审计目标
|
||||
|
||||
这份审计把本轮图谱重构要覆盖的交互风险集中记录下来。它不是普通 bug list,而是后续每个阶段的验收清单:每个风险都要明确期望行为、owner layer、验证方法和目标阶段。
|
||||
|
||||
核心原则:
|
||||
|
||||
- 图谱拥有自己的交互空间。节点、边、社区色块、空白画布上的滚轮、拖拽、hover、点击、键盘取消都先进入图谱交互链路。
|
||||
- 浏览器默认行为只在明确允许的文本、输入、阅读区域发生。
|
||||
- 命中、坐标、状态、渲染不能各算各的。
|
||||
- 工作台和离线 HTML 是同等目标,不能只修其中一个。
|
||||
|
||||
## Owner Layer 约定
|
||||
|
||||
| Owner layer | 负责范围 |
|
||||
|---|---|
|
||||
| GraphGestures | 原始 pointer、wheel、keyboard、touch 事件;点击/拖拽/缩放意图;阻止浏览器默认行为 |
|
||||
| SpatialIndex / GraphLayout | 节点、边、社区色块、空白图谱区域命中;布局边界;社区色块软边界 |
|
||||
| GraphViewport | 世界坐标、屏幕坐标、小地图坐标转换;相机缩放、平移、fit、resize anchor |
|
||||
| GraphState | hover、selection、active drag、pins、positions、viewport 等图谱运行状态 |
|
||||
| GraphRenderer | 节点、边、社区色块、小地图、hover 卡片、工具栏、离线 reader 的绘制 |
|
||||
| GraphFacade | workbench/offline 公开 API、宿主回调、持久化 pin、抽屉/选择语义协调 |
|
||||
|
||||
## 风险矩阵
|
||||
|
||||
| 风险 | 期望行为 | Owner layer | 验证方法 | 目标阶段 |
|
||||
|---|---|---|---|---|
|
||||
| Trackpad wheel 在图谱内被页面滚动或页面缩放抢走 | 鼠标或触控板停在节点、边、社区色块、空白画布上时,wheel 都只改变图谱相机;页面尺寸、页面滚动位置和浏览器缩放不变 | GraphGestures + GraphViewport | Node test 覆盖 wheel target policy;workbench/offline browser 脚本记录 transform 变化、root scroll、页面 viewport 指标 | Phase 2 |
|
||||
| `ctrl/meta + wheel` 触发浏览器页面缩放 | 图谱拥有的 surface 内,pinch-like wheel 被图谱接管;输入框、阅读正文等 blocker 内不接管 | GraphGestures | Browser 脚本 dispatch cancelable wheel,记录 `visualViewport.scale`、`devicePixelRatio`、clientWidth 和 graph transform | Phase 2 |
|
||||
| 鼠标在节点上滚轮不能缩放 | 节点命中优先,但节点上的 wheel 仍走 graph zoom,不因为节点可点击/可拖拽而阻断缩放 | GraphGestures + SpatialIndex | `gestures.test.ts` 覆盖 node target wheel;workbench/offline 真实节点上滚轮验证 transform 改变 | Phase 2 |
|
||||
| 鼠标在社区色块上滚轮不能缩放 | 社区色块可点击选择整个社区,但 wheel 仍走 graph zoom;点击和滚轮互不抢语义 | GraphGestures + SpatialIndex | `gestures.test.ts` 覆盖 community target wheel;community wash browser regression | Phase 2 |
|
||||
| 空白拖动画布时选中工具栏或页面文字 | active pan/drag 期间禁止 native selection;结束或取消后清理锁定状态 | GraphGestures + GraphRenderer | Browser 脚本拖动画布后断言 `window.getSelection().toString()` 为空、toolbar/search 文本未被选中、root dataset 无 stuck active | Phase 2 |
|
||||
| 原生 drag selection 或页面 scroll 泄漏进图谱 | 图谱 owned surface 在 active gesture 期间阻止默认拖选、滚动和 scroll chaining;root scroll 被复位 | GraphGestures | Browser 脚本拖拽空白、拖节点、拖社区色块,检查 root scroll、document selection、body scroll | Phase 2 |
|
||||
| 快速松开节点后节点回到原位 | drag end intent 必须带最终 pointer 坐标;即使最后一帧 move 没来得及提交,release 坐标也会提交成 pin | GraphGestures + GraphViewport + GraphState + GraphFacade | State machine test 覆盖 final screen point;browser 脚本快速 mouse down/move/up,检查节点位置和 pinned 状态 | Phase 2 |
|
||||
| 节点拖拽不跟手或跳到别处 | 拖拽以 grabbed offset 为基准,屏幕点经 GraphViewport 反投影;节点中心不突然吸到鼠标中心,也不使用旧坐标公式 | GraphViewport + GraphState + GraphFacade | `simulation-bridge.test.ts` 覆盖 offset;browser 脚本记录 pointer 与节点中心距离上限 | Phase 3 |
|
||||
| 节点被社区色块或固定世界尺寸锁住 | 社区色块是软视觉区域;节点可拖出色块;世界 bounds 由布局和 pin/outlier 推导,不用 `1000x680` 当硬笼子 | GraphLayout + GraphViewport | render model/community wash tests;community wash browser regression 拖出初始 wash 并检查 pin | Phase 3 / Phase 6 |
|
||||
| 社区色块无限追随远处离群节点 | 色块可受拖出节点影响,但有上限;不会变成覆盖全屏的巨大色块;社区成员关系不因拖拽改变 | GraphLayout + GraphRenderer | `community-wash.test.ts` 覆盖 outlier cap;browser 脚本检查 wash 大小上限和成员稳定 | Phase 6 |
|
||||
| 点击社区和拖动社区阈值冲突 | 小位移点击选中社区并打开选区语义;超过阈值不触发社区点击,也不误启动节点拖拽 | GraphGestures + SpatialIndex | `gestures.test.ts` 覆盖 community move cancel;browser 脚本 move past threshold 后 visible nodes 不变 | Phase 2 / Phase 6 |
|
||||
| DOM stacking order 改变后命中不同 | 节点命中优先于边和社区;社区优先于空白;命中来源是 SpatialIndex,不是 `elementFromPoint` 或 DOM 层级 | SpatialIndex / GraphLayout + GraphGestures | 新增 `spatial-index.test.ts`,构造重叠节点/边/社区并打乱 DOM 顺序;renderer boundary test 禁止旧 DOM hit owner | Phase 1 / Phase 7 |
|
||||
| Hover 简介位置漂移 | hover anchor 来自节点/边的世界坐标,经 GraphViewport 投影;zoom、pan、drag、resize、drawer open 后重新计算 | GraphViewport + GraphState + GraphRenderer | `overlays.test.ts` 扩展投影;workbench/offline browser 测 preview 和 anchor gap、viewport 内不溢出 | Phase 3 |
|
||||
| Hover 卡片与节点不同步 | hover 状态存于 GraphState,Renderer 只绘制;节点位置更新后卡片 anchor 跟随同一状态快照 | GraphState + GraphRenderer | Browser 脚本在拖拽后 hover,记录卡片相对节点距离;state test 覆盖 hover snapshot | Phase 3 |
|
||||
| Search 输入框边界误接管 | search 内 wheel、pointer、keyboard 不触发图谱 zoom/pan/shortcut;离开 search 后恢复图谱控制 | GraphGestures + GraphFacade | `gestures.test.ts` blocker 覆盖 search;browser 脚本打开 search 后滚轮不改变图谱 transform | Phase 2 |
|
||||
| Toolbar/legend 边界误接管 | 工具栏和图例作为图谱控件:点击按控件语义走;wheel/pointer 不误触发画布 pan;空白点击可关闭 popover | GraphGestures + GraphRenderer | toolbar state tests;browser 脚本覆盖 toolbar panel、legend row、blank close | Phase 2 |
|
||||
| Minimap 边界误接管 | minimap 有自己的点击/导航语义;不被 blank pan 或 graph wheel 错认;minimap 投影只走 GraphViewport | GraphGestures + GraphViewport + GraphRenderer | viewport minimap tests;browser 脚本 wheel over minimap 不 zoom graph,minimap click/viewport rect 稳定 | Phase 3 |
|
||||
| Drawer/reader 边界误接管 | workbench drawer 和 offline reader 内允许文本阅读/滚动/按钮;不触发 graph drag/zoom;图谱 anchor 不因 drawer resize 漂移 | GraphGestures + GraphFacade + GraphViewport | Browser 脚本 drawer wheel 不 zoom graph,drawer resize 后选中节点保持可见且 hover 不溢出 | Phase 2 / Phase 3 |
|
||||
| 数据刷新时正在拖拽 | active drag 期间 diff queue 暂存或合并;释放后以最终 pin/position 重建 layout 和 SpatialIndex,不用旧 snapshot 覆盖用户拖拽 | GraphState + GraphFacade + GraphLayout | GraphDiffQueue tests 已有基础,扩展 active drag release 后 replay;browser 可用 mock refresh 验证无回弹 | Phase 3 |
|
||||
| Pointer cancel / lost pointer capture 后状态卡住 | 取消事件只清理 active gesture,不误提交 click/pin;root dataset、cursor、selection lock 都恢复 | GraphGestures + GraphState | `gestures.test.ts` 已覆盖基础,扩展 DOM cleanup;browser 脚本 dispatch pointercancel/lostpointercapture 后继续可操作 | Phase 2 |
|
||||
| Escape 行为混乱 | active drag/pan 优先取消当前手势;无 active gesture 时清理 hover/selection/drawer/search,具体语义由 GraphFacade 统一 | GraphGestures + GraphFacade + GraphState | State machine test;workbench/offline browser 脚本覆盖 drawer、selection、search、active drag | Phase 2 / Phase 4 |
|
||||
| 键盘快捷键抢输入框 | search、drawer、text-control 内的 Tab/Enter/Space/Arrow/plus/minus/zero 不触发图谱快捷键;图谱 focus 内才响应 | GraphGestures + GraphFacade | gestures blocker tests;browser 脚本聚焦 search/drawer 按键验证不改变 graph transform/selection | Phase 2 |
|
||||
| Graph focus 不明确 | 点击/Tab 进入图谱后键盘归图谱;离开图谱或进入文本控件后键盘归宿主/浏览器 | GraphGestures + GraphFacade | Browser 脚本检查 focus ring、keyboard commands only under graph focus | Phase 4 |
|
||||
| Touch 一指拖动画布和拖节点不稳定 | 支持 pointer events 的触摸:一指空白 pan、一指节点 drag;pointercancel 清理;没有复杂多指编辑时提供按钮 fallback | GraphGestures + GraphViewport | Browser 脚本模拟 pointerType touch;Node state machine test 覆盖 touch-like pointer sequence | Phase 2 |
|
||||
| 双击或连续点击语义散落 | 双击 fit/reset 或其他图谱命令必须由 GraphGestures 发 intent,Renderer 不直接绑定 root dblclick | GraphGestures + GraphFacade | Final cleanup `rg` 检查 static-renderer 不再绑定 root dblclick;browser 脚本覆盖 reset/fit | Phase 5 / Phase 7 |
|
||||
| 旧 renderer 继续偷偷拥有交互 | `static-renderer.ts` 终态只能是 composition/compat shell;不能保留 root wheel/pointer/dblclick/keydown/hit-test/coordinate owner | GraphFacade + GraphRenderer | Final cleanup `rg` 检查;renderer-boundary test 用 runtime contract 防止换文件名复发 | Phase 5 / Phase 7 |
|
||||
| Workbench 与离线 HTML 行为分叉 | graph-engine 内的行为同源;workbench 只负责宿主抽屉和能力,offline 只负责离线 reader;核心交互测试两端都跑 | GraphFacade | `tests/graph-workbench-interactions.regression-1.sh` 和 `tests/graph-offline-phase-6.regression-1.sh` 同时通过 | Phase 7 |
|
||||
|
||||
## 当前覆盖与缺口
|
||||
|
||||
已有覆盖:
|
||||
|
||||
- `packages/graph-engine/test/gestures.test.ts` 已覆盖基础 target 分类、节点拖拽、社区点击取消、空白 pan、pointer cancel、Escape。
|
||||
- `packages/graph-engine/test/viewport.test.ts` 已覆盖 zoom/pan/fit/minimap/resize anchor。
|
||||
- `packages/graph-engine/test/simulation-bridge.test.ts` 已覆盖 dragged point under pointer 和 off-world drag 不被投影层 clamp。
|
||||
- `packages/graph-engine/test/community-wash.test.ts` 与 `render-model.test.ts` 已覆盖社区色块 outlier cap、拖出后成员稳定。
|
||||
- `tests/browser/graph-workbench-interactions.mjs`、`graph-offline-phase-6.mjs`、`graph-community-wash-interactions.mjs` 已有真实浏览器检查基础。
|
||||
|
||||
必须补齐:
|
||||
|
||||
- SpatialIndex 作为真实命中来源,而不是 DOM target 的接口包装。
|
||||
- 图谱内 `ctrl/meta + wheel` 和 trackpad pinch-like wheel 不改变浏览器页面 zoom 的浏览器证据。
|
||||
- 空白 pan、节点 drag 后无 native text selection 的浏览器证据。
|
||||
- 快速 release 用最终 pointer 坐标提交 pin 的浏览器证据。
|
||||
- hover preview 在 drag、zoom、pan、drawer resize 后仍锚定节点/边的浏览器证据。
|
||||
- renderer boundary 检查,防止旧 `static-renderer.ts` 或新 renderer 文件重新接管交互。
|
||||
|
||||
## 阶段入口条件
|
||||
|
||||
Phase 1 之前必须满足:
|
||||
|
||||
- 本审计文档已提交。
|
||||
- 进度账本记录 Phase 0 task 0.2 的验证和提交号。
|
||||
- 不开始行为改动,直到 task 0.3 把现有测试与缺口映射到目标阶段。
|
||||
|
||||
后续每阶段完成时,progress 文件必须把本审计中的相关风险标成已有验证证据,不能只写“实现完成”。
|
||||
@@ -0,0 +1,212 @@
|
||||
# Graph Interaction Test Coverage Map
|
||||
|
||||
日期:2026-06-16
|
||||
|
||||
适用计划:`docs/plans/2026-06-16-graph-six-layer-architecture-phased-plan.md`
|
||||
|
||||
前置审计:`docs/graph/2026-06-16-interaction-risk-audit.md`
|
||||
|
||||
## 目标
|
||||
|
||||
这份文档把交互风险映射到现有测试、缺口测试和后续阶段。它用于防止后续重构只移动代码、不建立保护网。
|
||||
|
||||
判定规则:
|
||||
|
||||
- `Covered`:已有单元测试或浏览器脚本能直接防住该风险。
|
||||
- `Partial`:已有测试覆盖了核心数学或状态,但没有覆盖真实浏览器行为或最终架构边界。
|
||||
- `Missing`:当前没有明确测试,必须在目标阶段新增。
|
||||
|
||||
## 覆盖总览
|
||||
|
||||
| 风险组 | 当前状态 | 已有保护 | 必补保护 | 目标阶段 |
|
||||
|---|---|---|---|---|
|
||||
| 节点/边/社区/空白 wheel zoom | Partial | `gestures.test.ts` target policy;`graph-workbench-interactions.mjs` 和 `graph-offline-phase-6.mjs` 覆盖部分 wheel target | trackpad-like wheel、`ctrl/meta + wheel` 不触发页面 zoom 的浏览器证据 | Phase 2 |
|
||||
| 浏览器默认行为隔离 | Missing | root scroll reset 有部分浏览器检查 | native selection、body scroll、root scroll、browser zoom 指标统一记录 | Phase 2 |
|
||||
| 点击/拖拽状态机 | Partial | `gestures.test.ts` 覆盖阈值、cancel、Escape;`simulation-bridge.test.ts` 覆盖 grabbed offset | 快速 release 用 final pointer 坐标提交 pin 的浏览器证据 | Phase 2 |
|
||||
| SpatialIndex 命中 | Missing | 现有 target classifier 不依赖 DOM mock,但仍不是真实空间命中 | 新增 `spatial-index.test.ts`,覆盖节点、边、社区、空白、重叠优先级、旧世界外命中 | Phase 1 |
|
||||
| 坐标和相机 | Partial | `geometry.test.ts`、`viewport.test.ts`、`simulation-bridge.test.ts`、`overlays.test.ts` | layout-driven world bounds、drawer resize 后 hover/selection anchor 的浏览器证据 | Phase 3 |
|
||||
| 图谱运行状态 | Partial | `runtime-state.test.ts`、`queue.test.ts` 覆盖基础状态和 diff queue | 数据刷新期间 active drag 的最终 pin 不被 stale snapshot 覆盖 | Phase 3 |
|
||||
| 社区色块软边界 | Partial | `community-wash.test.ts`、`render-model.test.ts`、`graph-community-wash-interactions.mjs` | SpatialIndex priority 接管社区命中;expanded bounds 下 cap 不无限放大 | Phase 6 |
|
||||
| 工具栏/search/legend/minimap/drawer 边界 | Partial | `gestures.test.ts` blocker policy;toolbar tests;workbench/offline browser 覆盖部分 UI | keyboard focus、wheel blocker、pointer blocker、drawer resize anchor 的一组统一回归 | Phase 2 / Phase 3 |
|
||||
| hover preview anchor | Partial | `overlays.test.ts` 和 browser hover checks | zoom、pan、drag、drawer resize、community focus 后统一 anchor gap 证据 | Phase 3 |
|
||||
| keyboard/touch | Missing | Escape 基础 state machine 覆盖 | graph focus 内快捷键、text-control blocker、touch-like pointer sequence | Phase 2 / Phase 4 |
|
||||
| renderer 旧责任清理 | Missing | 计划内 `rg` 命令尚未转成阶段测试 | renderer boundary test + final cleanup `rg`,禁止 root interaction 和 coordinate owner 回到 renderer | Phase 5 / Phase 7 |
|
||||
| workbench/offline parity | Partial | `graph-workbench-interactions.mjs`、`graph-offline-phase-6.mjs`、`graph-community-wash-interactions.mjs` | 每个核心交互在两端都留下证据 artifact | Phase 7 |
|
||||
|
||||
## 现有测试归位
|
||||
|
||||
### GraphGestures
|
||||
|
||||
已有:
|
||||
|
||||
- `packages/graph-engine/test/gestures.test.ts`
|
||||
- graph target 分类:blank、node、community wash、edge、minimap、toolbar、search、legend、drawer、text-control。
|
||||
- wheel target policy:blank/node/community/edge 可 zoom;controls/drawer/minimap/text-control 阻断。
|
||||
- pointerdown target policy:node drag、community click、blank pan、controls blocker。
|
||||
- gesture state machine:node click、node drag、community click cancel、blank pan、pointercancel、lostpointercapture、Escape。
|
||||
|
||||
缺口:
|
||||
|
||||
- 当前 `ctrl/meta + wheel` 在单元测试里是 blocked,但本轮设计要求 graph-owned surface 内必须阻止浏览器页面 zoom 并转为图谱意图;Phase 2 必须重做该策略并补浏览器证据。
|
||||
- 缺 touch-like pointer sequence。
|
||||
- 缺 keyboard focus 和 text-control blocker 的真实浏览器证据。
|
||||
- 缺 active gesture 期间 native selection 清理证据。
|
||||
|
||||
### GraphViewport / Geometry
|
||||
|
||||
已有:
|
||||
|
||||
- `packages/graph-engine/test/geometry.test.ts`
|
||||
- world/screen round trip。
|
||||
- drawer-style resize 后 layer point round trip。
|
||||
- minimap projection。
|
||||
- 不在投影 helper 内静默 clamp。
|
||||
- `packages/graph-engine/test/viewport.test.ts`
|
||||
- wheel zoom around pointer。
|
||||
- pan、fit、center、resize anchor、minimap rect、frame commit coalescing。
|
||||
- `packages/graph-engine/test/simulation-bridge.test.ts`
|
||||
- grabbed point stays under pointer。
|
||||
- drag start 不跳到 pointer center。
|
||||
- off-world drag 不在 projection/bridge 层 clamp。
|
||||
- `packages/graph-engine/test/overlays.test.ts`
|
||||
- node/edge hover anchor 使用投影点。
|
||||
- preview card stay inside viewport。
|
||||
|
||||
缺口:
|
||||
|
||||
- GraphViewport 还需要接入 layout-driven world bounds,不再让固定世界尺寸决定拖拽范围。
|
||||
- Browser 需要证明 zoom、pan、drag、drawer resize 后 hover preview 仍与节点/边锚定。
|
||||
- Minimap 点击和当前 viewport rect 需要在新 world bounds 下验证。
|
||||
|
||||
### GraphState / Diff Queue
|
||||
|
||||
已有:
|
||||
|
||||
- `packages/graph-engine/test/runtime-state.test.ts`
|
||||
- viewport、hover、selection、focus、pins、positions、active gesture 一处更新。
|
||||
- simulation proposal 不直接变成 committed positions。
|
||||
- snapshot clone 防止外部改 hidden state。
|
||||
- `packages/graph-engine/test/queue.test.ts`
|
||||
- graph hidden 时 diff queue 合并。
|
||||
- drag 期间 hold diff,释放后 consume。
|
||||
|
||||
缺口:
|
||||
|
||||
- active drag release 同时遇到 data refresh 时,最终 release position 必须优先于 stale replay。
|
||||
- GraphState 与 GraphFacade 之间需要一个明确的 commit path 测试,证明 fast release 不回弹。
|
||||
|
||||
### GraphLayout / Community Wash
|
||||
|
||||
已有:
|
||||
|
||||
- `packages/graph-engine/test/community-wash.test.ts`
|
||||
- small communities remain selectable。
|
||||
- dragged outlier influences wash but does not chase it without cap。
|
||||
- multi-direction outlier cap。
|
||||
- `packages/graph-engine/test/render-model.test.ts`
|
||||
- pinned member outside wash cap 时 community membership 稳定。
|
||||
- member dragged beyond cap 后 community focus 稳定。
|
||||
- `tests/browser/graph-community-wash-interactions.mjs`
|
||||
- community wash 上 wheel zoom。
|
||||
- 点击 community wash 进入社区。
|
||||
- 超过阈值移动取消 community click。
|
||||
- 节点可以拖出初始 wash 并提交 pin。
|
||||
|
||||
缺口:
|
||||
|
||||
- SpatialIndex 接管后,community hit 不能再依赖 DOM stacking。
|
||||
- expanded layout bounds 下,wash cap 仍然不能无限扩张。
|
||||
- 节点拖出 wash 后,wash soft-boundary 更新要和 membership 稳定同时验证。
|
||||
|
||||
### GraphRenderer / Boundary
|
||||
|
||||
已有:
|
||||
|
||||
- `packages/graph-engine/test/render-model.test.ts`
|
||||
- renderable graph、selected state、density、community focus、pinned positions。
|
||||
- `packages/graph-engine/test/toolbar.test.ts`
|
||||
- toolbar panel state 和 blank click close。
|
||||
- `packages/graph-engine/test/search-and-legend.test.ts`
|
||||
- search helpers 和 legend selection。
|
||||
- `tests/browser/graph-stage-4-5.mjs`
|
||||
- 旧阶段的 wheel、selection、drawer、hover、edge preview、responsive checks。
|
||||
|
||||
缺口:
|
||||
|
||||
- 缺 renderer boundary test:Renderer 不能直接拥有 root wheel/pointer/dblclick/keydown。
|
||||
- 缺 final `rg` 检查转成可重复的测试证据。
|
||||
- 缺 DOM order 改变但 SpatialIndex 命中不变的测试。
|
||||
|
||||
### Workbench / Offline
|
||||
|
||||
已有:
|
||||
|
||||
- `tests/browser/graph-workbench-interactions.mjs`
|
||||
- workbench desktop/narrow、wheel targets、blocker targets、hover、drawer resize、community drag、pan/minimap reset。
|
||||
- `tests/browser/graph-offline-phase-6.mjs`
|
||||
- offline hover、drag under pointer、selection panel、reader boundary、root scroll 等。
|
||||
- `tests/browser/graph-community-wash-interactions.mjs`
|
||||
- offline community wash 专项。
|
||||
|
||||
缺口:
|
||||
|
||||
- 两端都需要记录页面 zoom 没有变化。
|
||||
- 两端都需要记录 native selection 没有泄漏。
|
||||
- 两端都需要记录快速 release 后 pin 位置稳定。
|
||||
- 两端都需要记录 pointercancel/lostpointercapture 后不留下 stuck state。
|
||||
|
||||
## 必须新增或扩展的测试
|
||||
|
||||
| 测试文件 | 类型 | 覆盖内容 | 目标阶段 |
|
||||
|---|---|---|---|
|
||||
| `packages/graph-engine/test/spatial-index.test.ts` | Node unit | node/edge/community/blank hit;overlap priority;out-of-old-world hit;DOM order independent fixtures | Phase 1 |
|
||||
| `packages/graph-engine/test/gestures.test.ts` | Node unit | graph-owned `ctrl/meta + wheel` policy;touch-like pointer sequence;keyboard focus blocker contract | Phase 2 |
|
||||
| `tests/browser/graph-workbench-interactions.mjs` | Browser | graph-owned wheel does not zoom page;native selection stays empty;fast release pin persists;pointercancel cleanup | Phase 2 |
|
||||
| `tests/browser/graph-offline-phase-6.mjs` | Browser | same as workbench for offline HTML | Phase 2 / Phase 7 |
|
||||
| `packages/graph-engine/test/runtime-state.test.ts` | Node unit | data refresh while dragging keeps final release position | Phase 3 |
|
||||
| `packages/graph-engine/test/viewport.test.ts` | Node unit | layout-driven world bounds; minimap and fit under expanded bounds | Phase 3 |
|
||||
| `packages/graph-engine/test/overlays.test.ts` | Node unit | hover anchor after viewport resize, zoom, pan, and dragged node update | Phase 3 |
|
||||
| `packages/graph-engine/test/facade.test.ts` | Node unit | facade is the only host callback owner; workbench/offline capability contract remains compatible | Phase 4 |
|
||||
| `packages/graph-engine/test/renderer-boundary.test.ts` | Node unit / static check | renderer modules do not bind root graph events or perform graph hit testing | Phase 5 / Phase 7 |
|
||||
| `tests/browser/graph-community-wash-interactions.mjs` | Browser | SpatialIndex node > community > blank priority; wash cap under expanded bounds | Phase 6 |
|
||||
|
||||
## Phase Gate Mapping
|
||||
|
||||
Phase 1 can pass only when:
|
||||
|
||||
- SpatialIndex exists as a real hit-testing source.
|
||||
- `spatial-index.test.ts` covers nodes, edges, communities, blank, overlap priority, old-world outliers.
|
||||
|
||||
Phase 2 can pass only when:
|
||||
|
||||
- Node tests cover graph-owned wheel/pointer/key policy.
|
||||
- Workbench and offline browser tests prove graph-owned wheel does not change page zoom.
|
||||
- Workbench and offline browser tests prove native selection does not leak during graph gestures.
|
||||
- Fast release drag persists the final position.
|
||||
|
||||
Phase 3 can pass only when:
|
||||
|
||||
- GraphViewport owns all coordinate conversion under drag, hover, resize, minimap, fit.
|
||||
- Layout-driven bounds replace fixed world-size drag cage.
|
||||
- Data refresh while dragging cannot overwrite final user intent.
|
||||
|
||||
Phase 4 can pass only when:
|
||||
|
||||
- GraphFacade owns host coordination.
|
||||
- Workbench and offline use the same graph-engine capability contract.
|
||||
|
||||
Phase 5 can pass only when:
|
||||
|
||||
- Renderer modules draw from snapshots and do not decide interaction meaning.
|
||||
- `static-renderer.ts` is reduced to compatibility/composition responsibilities.
|
||||
|
||||
Phase 6 can pass only when:
|
||||
|
||||
- Community wash remains soft, capped, and non-blocking.
|
||||
- SpatialIndex priority drives node/community/blank behavior.
|
||||
|
||||
Phase 7 can pass only when:
|
||||
|
||||
- Full command set passes.
|
||||
- Browser artifacts exist for workbench, narrow, and offline paths.
|
||||
- Static cleanup checks show old renderer-owned interaction paths are gone.
|
||||
@@ -0,0 +1,86 @@
|
||||
# Phase 0.2 Existing Graph Baseline
|
||||
|
||||
Date: 2026-06-18
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `0.2`
|
||||
|
||||
## Scope
|
||||
|
||||
This report captures the current graph behavior and performance baseline before changing graph behavior for the large-graph performance plan.
|
||||
|
||||
## Verification
|
||||
|
||||
| Check | Result | Evidence |
|
||||
|---|---:|---|
|
||||
| Graph engine test | Pass | `npm run test --workspace=@llm-wiki/graph-engine`: 274 tests, 58 suites, 0 failures |
|
||||
| Graph engine typecheck | Pass | `npm run typecheck --workspace=@llm-wiki/graph-engine` |
|
||||
| Graph engine build | Pass | `npm run build --workspace=@llm-wiki/graph-engine` |
|
||||
| Workbench web test | Pass | `npm run test --workspace=@llm-wiki-agent/web`: 29 tests, 12 suites, 0 failures |
|
||||
| Workbench web typecheck | Pass | `npm run typecheck --workspace=@llm-wiki-agent/web` |
|
||||
| Stage 4.5 offline browser regression | Pass | `GRAPH_STAGE_4_5_CHROME_EXECUTABLE=<Playwright Chromium> bash tests/graph-browser-stage-4-5.regression-1.sh --target offline` |
|
||||
|
||||
## Browser Artifact
|
||||
|
||||
Dense wheel artifact:
|
||||
|
||||
- JSON: `docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.json`
|
||||
- Screenshot: `docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-dense-wheel.png`
|
||||
- Navigation screenshot: `docs/graph/performance/artifacts/2026-06-18-phase-0-2/stage-4.5-offline-navigation.png`
|
||||
|
||||
Recorded sample:
|
||||
|
||||
| Viewport | Duration | Frames | Idle FPS | Wheel FPS | Minimum FPS | Transform changed |
|
||||
|---|---:|---:|---:|---:|---:|---|
|
||||
| 1440x960 | 3004 ms | 157 | 13.6 | 52.3 | 12.0 | true |
|
||||
|
||||
Important limitation: the current dense fixture has 200 nodes and 231 edges. This is useful as a regression baseline, but it does not prove 1000, 5000, or 10000 node smoothness.
|
||||
|
||||
## Current Rendering Behavior
|
||||
|
||||
- The current graph renderer is DOM/SVG.
|
||||
- Nodes are DOM `button` elements in a node layer.
|
||||
- Edges are SVG `path` elements in an edge layer.
|
||||
- Community washes are SVG ellipses.
|
||||
- Pan and zoom are applied through one content-layer transform.
|
||||
- Motion frames update node positions, edge paths, community wash geometry, and minimap points.
|
||||
- Search, type filters, community hover, node selection, reader state, and selection panels are all currently coupled to the same DOM/SVG renderer path.
|
||||
|
||||
## Current Interaction Semantics
|
||||
|
||||
The current behavior remains the pre-new-design behavior:
|
||||
|
||||
- Plain node click opens the reader-style node detail state.
|
||||
- Shift-click builds a multi-node selection.
|
||||
- Community legend click selects/focuses community nodes.
|
||||
- Blank double-click fits the graph.
|
||||
- Escape closes reader/selection state and clears graph highlights.
|
||||
- Offline graph uses an in-graph reader panel; workbench graph opens the right drawer.
|
||||
|
||||
This is intentionally recorded as baseline behavior, not as the desired final interaction model.
|
||||
|
||||
## Baseline Bottleneck Class
|
||||
|
||||
The obvious large-graph risk is DOM/SVG update volume.
|
||||
|
||||
Reasons:
|
||||
|
||||
- Every visible node is a live DOM element.
|
||||
- Every visible edge is a live SVG path.
|
||||
- Rebuild/paint replaces the graph root and remounts controls.
|
||||
- Motion frames recompute renderable graph state and update many DOM/SVG attributes.
|
||||
- Hover, search, filter, community emphasis, and selection use DOM state/class updates across visible graph elements.
|
||||
|
||||
For small and medium scoped views, this is still appropriate. For 5000+ or 10000+ global views, the likely bottleneck is not one single function; it is the total cost of DOM node count, SVG path count, repeated attribute/class writes, and full repaint/remount paths.
|
||||
|
||||
## Test Harness Note
|
||||
|
||||
The first run of `tests/graph-browser-stage-4-5.regression-1.sh --target offline` exposed two harness issues:
|
||||
|
||||
- Playwright's normal click waited indefinitely for the offline theme button to become stable even though the button was visible, stationary, and not covered.
|
||||
- The script's default system Chrome path failed in this environment during launch/cleanup. Installing Playwright Chromium and setting `GRAPH_STAGE_4_5_CHROME_EXECUTABLE` to the Playwright browser path produced a passing run.
|
||||
|
||||
The theme-button step was adjusted in the test harness to use forced click for this specific control. Product behavior was not changed.
|
||||
|
||||
## Next Baseline Gap
|
||||
|
||||
Phase 1 must add deterministic 1000, 5000, 10000, oversized-community, many-small-communities, many-search-hits, and many-Pin fixtures. Until those measurements exist, this report should be treated as the current small/dense-fixture baseline only.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Phase 1.3 DOM/SVG Large Graph Baseline
|
||||
|
||||
Date: 2026-06-18
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `1.3`
|
||||
Renderer: current DOM/SVG
|
||||
|
||||
## Scope
|
||||
|
||||
This report summarizes the current DOM/SVG renderer against the generated large-graph performance fixtures. It does not choose the final renderer route. It turns the raw runner output into provisional thresholds for the next phases.
|
||||
|
||||
## Commands
|
||||
|
||||
- `git log --oneline -15`
|
||||
- `npm run test --workspace=@llm-wiki/graph-engine`
|
||||
- `GRAPH_LARGE_PERF_ARTIFACT_DIR=/tmp/llm-wiki-graph-large-perf-task-1-3 bash tests/graph-browser-large-performance.regression-1.sh`
|
||||
|
||||
## Artifact
|
||||
|
||||
Machine-readable result:
|
||||
|
||||
- `/tmp/llm-wiki-graph-large-perf-task-1-3/large-graph-performance-results.json`
|
||||
|
||||
The artifact contains 47 fixed-schema records across 5 graph shapes.
|
||||
|
||||
## Result Table
|
||||
|
||||
| Shape | Nodes | Edges | DOM nodes | Initial | Wheel | Pan | Hover | Search | Click | Drawer | Community | Return | Cycle |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 1000 | 1400 | 7249 | pass (900.4 ms) | pass (1016.8 ms, 60 FPS) | pass (130.5 ms) | pass (65.1 ms) | pass (189.2 ms) | pass (452.8 ms) | pass (857.1 ms) | pass (3122.9 ms) | pass (1389.1 ms) |
|
||||
| nodes-1000-dense | 1000 | 12000 | 7249 | pass (1008.4 ms) | pass (1007.2 ms, 59.6 FPS) | pass (129.2 ms) | pass (57.2 ms) | pass (205.2 ms) | pass (519.8 ms) | pass (867.9 ms) | pass (3279.1 ms) | pass (1432 ms) |
|
||||
| nodes-5000-sparse | 5000 | 6500 | 27399 | pass (4615.6 ms) | pass (1013.5 ms, 51.3 FPS) | pass (142.5 ms) | pass (145 ms) | pass (942.2 ms) | pass (2488.8 ms) | pass (5229.1 ms) | pass (4022.2 ms) | not run |
|
||||
| nodes-10000-aggregation | 10000 | 14000 | 52649 | pass (8836 ms) | pass (1004.9 ms, 36.8 FPS) | fail:timeout (-) | pass (3784.6 ms) | fail:timeout (-) | pass (4390.7 ms) | pass (13895.1 ms) | pass (4387 ms) | not run |
|
||||
| oversized-community | 3000 | 7000 | 17224 | pass (15788.6 ms) | pass (1005 ms, 12.9 FPS) | pass (247 ms) | pass (131.5 ms) | pass (3342.5 ms) | pass (8498.3 ms) | pass (27055.3 ms) | pass (9611.6 ms) | not run |
|
||||
|
||||
|
||||
## Recorded Failures
|
||||
|
||||
- nodes-10000-aggregation / pan: timeout
|
||||
- nodes-10000-aggregation / node_click: timeout
|
||||
|
||||
## Bottleneck Class
|
||||
|
||||
The primary bottleneck class is DOM/SVG update volume. The evidence is structural and measured:
|
||||
|
||||
- 1000-node global view creates about 7,249 DOM nodes and remains mostly responsive.
|
||||
- 5000-node global view creates about 27,399 DOM nodes; it still completes the key actions, but initial render and community entry move into multi-second territory.
|
||||
- 10000-node global view creates about 52,649 DOM nodes. In this run, pan and node click timed out, while drawer open and community entry were already multi-second actions in the prior 1.2 run.
|
||||
- Oversized community keeps 3000 nodes present and creates about 17,224 DOM nodes; community entry exposes 1800 nodes, which is too large for a card-heavy reading surface.
|
||||
|
||||
Secondary bottlenecks are interaction-state churn and community focus expansion. Search itself is still comparatively cheap, but click-to-reader, drawer open, enter-community, and return-global become slow because they update many DOM/SVG elements and remount or restyle large visible sets.
|
||||
|
||||
## Provisional Thresholds
|
||||
|
||||
These thresholds are intentionally provisional. They are gates for Phase 4/6 comparison, not final product promises.
|
||||
|
||||
| Metric | Provisional pass threshold | Notes |
|
||||
|---|---:|---|
|
||||
| Initial render, 1000 nodes | <= 1500 ms | Current 1000 sparse/dense passed. |
|
||||
| Initial render, 5000 nodes | <= 5000 ms | Current 5000 sparse passed but is close enough to watch. |
|
||||
| Initial render, 10000 nodes | <= 8000 ms | Current 10000 exceeded this; global path needs degradation or another renderer. |
|
||||
| Wheel zoom | >= 30 FPS and p95 <= 35 ms | 1000 and 5000 passed; low FPS is a failure class. |
|
||||
| Pan | <= 300 ms or explicit failure class | 10000 timed out in this run. |
|
||||
| Hover | <= 500 ms | All measured shapes passed here. |
|
||||
| Search highlight | <= 500 ms | Current search is not the first bottleneck. |
|
||||
| Node click | <= 800 ms for 1000, <= 1500 ms for 5000, <= 2000 ms for 10000 | 10000 timed out in this run. |
|
||||
| Drawer open | <= 1000 ms for 1000, <= 2500 ms for 5000, <= 3000 ms for 10000 | Prior 1.2 result showed 10000 drawer open can reach 7600 ms. |
|
||||
| Enter community | <= 1500 ms for normal community, <= 3000 ms for large/oversized community | 10000 and oversized community exceed the target. |
|
||||
| Return global | <= 3500 ms for 1000, <= 5000 ms for 5000, <= 5000 ms for 10000 | Current 1000 is already near the limit. |
|
||||
| Repeated cycle memory growth | <= 10 MB for 1000-node cycle | Current 1000 cycle showed no growth in available memory field. |
|
||||
|
||||
## Interpretation
|
||||
|
||||
The current renderer is acceptable for small graph and community reading, but it is not a proven 10000+ global renderer. The next implementation phases should keep DOM/SVG for community/detail views while treating 5000/10000 global browsing as requiring budget enforcement, aggregation, or a different global rendering route.
|
||||
|
||||
## Phase 4.1 Render Budgets
|
||||
|
||||
These budgets are the first shared graph-layer caps derived from the DOM/SVG bottleneck class above. They are not the final large-graph renderer decision; they prevent the current renderer from producing card-heavy or edge-heavy global output while Phase 6 evaluates the global route.
|
||||
|
||||
| View | Max visible nodes | Max visible edges | Max labels | Max full cards | Max interaction-time updates |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| Global | 10000 | 1000 | 40 | 0 | 1200 |
|
||||
| Community focus | 2500 | 1500 | 120 | 60 | 1800 |
|
||||
|
||||
Overflow is reported by the shared render model for nodes, edges, labels, cards, and interaction updates so drawer/list states can expose omitted detail without forcing it onto the canvas. Selection, search results, and Pin hints may promote priority, but they do not raise these caps.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Phase 1.4 Disposable Validation Gate
|
||||
|
||||
Date: 2026-06-18
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `1.4`
|
||||
|
||||
## Purpose
|
||||
|
||||
This note closes the Phase 1 validation gate before product behavior changes. It records how generated large graphs are measured, how real graph snapshots should be handled, which browser environment is usable, what stress limits are realistic, and which assumptions must stay portable for a future desktop app.
|
||||
|
||||
## Validation Result
|
||||
|
||||
The current offline graph entry can load generated large graph shapes without new product-code integration. The dedicated runner builds temporary offline HTML from generated graph data, opens it in Playwright Chromium, records fixed-schema measurements, and writes artifacts outside git.
|
||||
|
||||
Evidence:
|
||||
|
||||
- `tests/browser/graph-large-performance.ts`
|
||||
- `tests/graph-browser-large-performance.regression-1.sh`
|
||||
- `/tmp/llm-wiki-graph-large-perf-task-1-2/large-graph-performance-results.json`
|
||||
- `/tmp/llm-wiki-graph-large-perf-task-1-3/large-graph-performance-results.json`
|
||||
- `docs/graph/performance/2026-06-18-phase-1-3-dom-svg-large-baseline.md`
|
||||
|
||||
## Real Graph Source And Privacy Policy
|
||||
|
||||
Generated fixtures are the default reproducible source for Phase 1 and should remain committed only as generator code, not as large JSON outputs.
|
||||
|
||||
A real graph snapshot may be added later only as an uncommitted or sanitized artifact:
|
||||
|
||||
- Owner: the developer running the benchmark exports it from a local knowledge base.
|
||||
- Location: `/tmp/llm-wiki-real-graph-snapshot-<date>/graph-data.json` or another ignored local path.
|
||||
- Git policy: real snapshots are excluded from git unless explicitly anonymized and reviewed.
|
||||
- Privacy handling: remove source paths, personal names, private project names, raw content, and unique file-system paths before sharing or committing.
|
||||
- Reproduction: record node/edge/community counts, largest community size, search-hit count, Pin count, export command, hash of sanitized data, and benchmark artifact path.
|
||||
- If the real graph contains private data and cannot be anonymized, use the generated `real-snapshot-proxy` shape instead.
|
||||
|
||||
## Edge Count Caps
|
||||
|
||||
The stress goal is to measure product-like behavior, not arbitrary impossible graphs. Current caps for this plan:
|
||||
|
||||
| Shape | Node cap | Edge cap | Reason |
|
||||
|---|---:|---:|---|
|
||||
| 1000 sparse | 1000 | 1400 | Baseline navigation and interaction. |
|
||||
| 1000 dense | 1000 | 12000 | Dense local relation pressure while still fitting current visible edge budget. |
|
||||
| 5000 sparse | 5000 | 6500 | Large global map with realistic sparse connectivity. |
|
||||
| 5000 dense | 5000 | 60000 | Stress candidate, not default runner path. |
|
||||
| 10000 aggregation | 10000 | 14000 | Target global browsing shape. |
|
||||
| 10000 high-edge | 10000 | 90000 | Stress candidate for renderer trials, not required for every smoke run. |
|
||||
| oversized-community | 3000 | 7000 | Tests one oversized community without pretending all cards can stay visible. |
|
||||
|
||||
The current DOM/SVG renderer visibly caps rendered edges at 1000 in the measured global view. That is useful evidence, but it is not a final large-graph solution.
|
||||
|
||||
## Browser Environment
|
||||
|
||||
Measured browser environment is available. Performance phases are not blocked.
|
||||
|
||||
- Runner command: `GRAPH_LARGE_PERF_ARTIFACT_DIR=/tmp/llm-wiki-graph-large-perf-task-1-3 bash tests/graph-browser-large-performance.regression-1.sh`
|
||||
- Browser package path: resolved through `npx --yes -p playwright`.
|
||||
- Executable path: `/Users/kangjiaqi/Library/Caches/ms-playwright/chromium-1228/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing`.
|
||||
- Local ports: not required for the offline generated graph runner. Workbench browser checks may still need local ports in later phases.
|
||||
- Browser plugin fallback: allowed only for functional visual checks when scriptable checks fail; it cannot replace performance artifacts.
|
||||
|
||||
## Trial Dependency Path
|
||||
|
||||
No production dependency was added in Phase 1. Playwright was used through temporary `npx --yes -p playwright` resolution and local browser cache for measurement.
|
||||
|
||||
For Phase 6:
|
||||
|
||||
- Sigma/Graphology and vis-network may be installed only for isolated renderer trials when the current task requires them.
|
||||
- Any package change must be recorded in the progress decision log before it lands.
|
||||
- Production adoption remains blocked until the Phase 6 route decision.
|
||||
- At most one production global graph route may survive. Aggregation-first may be a staged chosen route, but it must not become a second parallel global graph product.
|
||||
|
||||
## Oversized Community Semantics
|
||||
|
||||
For Phase 4 tests, "complete community presence" must not mean rendering every internal item as a full card at once. It may mean:
|
||||
|
||||
- A visible community container or outline.
|
||||
- Representative core nodes as cards.
|
||||
- Remaining members as points, count badges, or an internal list in the drawer.
|
||||
- Search hits, selected objects, and pinned objects remain visible or explicitly represented.
|
||||
- A clear action to drill into a bounded community reading surface.
|
||||
|
||||
The oversized-community fixture has 3000 nodes, 7000 edges, 15 communities, and one 1800-node community. Current DOM/SVG behavior exposes too many card-like nodes for this shape and recorded slow entry/return behavior in Phase 1.3.
|
||||
|
||||
## Desktop-App Compatibility Guardrails
|
||||
|
||||
Graph semantics must remain reusable if the product later moves into a desktop shell. Avoid binding product logic to browser-only assumptions:
|
||||
|
||||
- Do not store graph semantics only in DOM attributes. DOM attributes may mirror state for rendering/tests, but graph identity, selection, search, Pin, filter, and community rules belong in shared graph-engine data structures.
|
||||
- Do not make `window`, `document`, `localStorage`, URL routing, or CSS selectors the source of truth for graph behavior.
|
||||
- Keep file-system paths and workspace paths behind host adapters; shared graph semantics should use object ids, community ids, and wiki-relative ids.
|
||||
- Renderer candidates may use Canvas/WebGL/browser APIs, but semantic contracts must stay independent enough to run behind a desktop webview or native shell bridge.
|
||||
- Persisted Pin/layout state should stay serializable and portable, not tied to one browser storage implementation.
|
||||
|
||||
## Throwaway Code Policy
|
||||
|
||||
Phase 1 did not leave throwaway validation code in product paths. The generated graph runner became a deliberate test harness under `tests/browser/`; temporary graph HTML and JSON artifacts remain under `/tmp` and are not committed.
|
||||
@@ -0,0 +1,168 @@
|
||||
# Phase 2.4 Global Renderer Trial Matrix
|
||||
|
||||
Date: 2026-06-18
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `2.4`
|
||||
|
||||
## Purpose
|
||||
|
||||
This note defines the trial boundary before any global large-graph renderer candidate is installed, measured, or wired into the product. The project will compare WebGL, Canvas, and no-new-dependency aggregation with the same data, semantics, graph shapes, and performance records. It will ship at most one production global graph route.
|
||||
|
||||
Current DOM/SVG remains the known route for small graphs, community reading, offline detail, and UI-rich cards. It is not assumed to be the final 10000+ global route.
|
||||
|
||||
## Non-Negotiable Route Rule
|
||||
|
||||
Only one production global large-graph route may survive the decision phase.
|
||||
|
||||
- Candidate trials may coexist only in isolated harness code and measurement artifacts.
|
||||
- The workbench must not expose multiple global graph experiences as parallel product modes.
|
||||
- Aggregation-first may be selected as a staged production route if it wins the decision, but it must not become a permanent second route next to a WebGL or Canvas global renderer.
|
||||
- DOM/SVG can remain for community/detail surfaces even if a different route wins for the global map.
|
||||
|
||||
## Shared Trial Inputs
|
||||
|
||||
Every candidate must consume the Phase 2 shared renderer adapter contract before product-specific behavior is evaluated.
|
||||
|
||||
Required semantic inputs:
|
||||
|
||||
- Object ids: node id, community id, aggregation id.
|
||||
- State: selected object, search hits, Pin hints, focused community, filters.
|
||||
- Aggregation metadata: contained node ids, selected internal node ids, search-hit ids, pinned ids, total count.
|
||||
- Drawer targets: node summary, community summary, excluded aggregation object.
|
||||
- Commands: enter community, show object, clear temporary object, open detail/read, set fixed position.
|
||||
|
||||
Required graph shapes:
|
||||
|
||||
| Shape | Nodes | Edge cap | Required in Phase 6? | Purpose |
|
||||
|---|---:|---:|---|---|
|
||||
| real-snapshot-proxy | 1000 | 1600 | yes | Proxy for a realistic medium wiki graph. |
|
||||
| nodes-1000-sparse | 1000 | 1400 | yes | Baseline interaction and correctness. |
|
||||
| nodes-1000-dense | 1000 | 12000 | yes | Dense local relation pressure. |
|
||||
| nodes-5000-sparse | 5000 | 6500 | yes | First large global target. |
|
||||
| nodes-5000-dense | 5000 | 60000 | yes | Edge-heavy 5000-node pressure. |
|
||||
| nodes-10000-aggregation | 10000 | 14000 | yes | Primary 10000+ global target. |
|
||||
| nodes-10000-high-edge | 10000 | 90000 | yes | Extreme edge pressure for the renderer decision. |
|
||||
| oversized-community | 3000 | 7000 | yes | One huge community without full-card rendering. |
|
||||
| many-small-communities | 5000 | 6000 | yes | Many tiny communities and legend/container pressure. |
|
||||
| many-search-hits | 5000 | 7000 | yes | Search highlight pressure. |
|
||||
| many-pin-nodes | 5000 | 7000 | yes | Pin/selected preservation pressure. |
|
||||
|
||||
## Candidate Matrix
|
||||
|
||||
| Candidate | Technology | Trial role | Strength to prove | Main rejection reasons | Dependency status |
|
||||
|---|---|---|---|---|---|
|
||||
| Sigma/Graphology | WebGL + graph model | First global renderer candidate | 5000/10000 point map remains smooth while preserving llm-wiki selection/search/Pin/drawer semantics | Semantic contract cannot be preserved, desktop webview risk is too high, memory grows across cycles, integration forces a second product logic path, performance does not beat aggregation enough | Requires explicit trial dependency approval before package changes. |
|
||||
| vis-network | Canvas | Strong comparison candidate | Canvas path handles large global interactions with less integration cost than WebGL | Built-in interaction model fights llm-wiki drawer/community/search semantics, layout ownership becomes opaque, Pin/fixed-position behavior is unstable, performance or memory falls below WebGL/aggregation | Requires explicit trial dependency approval before package changes. |
|
||||
| Aggregation fallback | Current stack, no new dependency | No-new-dependency fallback or staged route | 10000+ global map is useful by showing communities, skeleton edges, selected/search/Pin markers, and overflow lists without full node detail | Users lose too much spatial context, search/Pin/selected objects are not discoverable, container interactions feel like a separate product, oversized communities remain slow | No dependency approval required. |
|
||||
|
||||
## Required Metrics
|
||||
|
||||
Every measured candidate must produce fixed-schema artifacts comparable to the Phase 1 DOM/SVG baseline.
|
||||
|
||||
Required action records:
|
||||
|
||||
- initial render
|
||||
- wheel zoom FPS and p95 frame time
|
||||
- pan
|
||||
- hover or nearest-object inspect
|
||||
- search highlight
|
||||
- point select
|
||||
- container select
|
||||
- drawer open
|
||||
- enter community
|
||||
- return global
|
||||
- repeated cycle memory growth for every required shape
|
||||
|
||||
Required metadata fields:
|
||||
|
||||
- renderer id
|
||||
- candidate version and package versions, if any
|
||||
- graph shape
|
||||
- node count
|
||||
- edge count
|
||||
- community count
|
||||
- largest community size
|
||||
- search hit count
|
||||
- Pin count
|
||||
- visible object count
|
||||
- browser environment
|
||||
- artifact path
|
||||
- pass/fail
|
||||
- failure class and detail
|
||||
|
||||
## Provisional Acceptance Table
|
||||
|
||||
These thresholds are comparison gates, not final product promises.
|
||||
|
||||
| Metric | 1000 nodes | 5000 nodes | 10000 nodes | Notes |
|
||||
|---|---:|---:|---:|---|
|
||||
| Initial render | <= 1500 ms | <= 5000 ms | <= 8000 ms | Current DOM/SVG exceeded the 10000 target. |
|
||||
| Wheel zoom | >= 30 FPS | >= 30 FPS | >= 30 FPS | Lower result must record `fps_below_floor`. |
|
||||
| Pan | <= 300 ms | <= 500 ms | <= 800 ms | Timeout is a blocking failure for a candidate route. |
|
||||
| Search highlight | <= 500 ms | <= 800 ms | <= 1200 ms | Search must update highlight/markers without full graph relayout. |
|
||||
| Point select | <= 800 ms | <= 1500 ms | <= 2000 ms | Must open lightweight summary target, not full reading by default. |
|
||||
| Container select | <= 1000 ms | <= 2000 ms | <= 2500 ms | Community/aggregation selection must keep global context. |
|
||||
| Drawer open | <= 1000 ms | <= 2500 ms | <= 3000 ms | Long content rendering is not part of global lightweight drawer. |
|
||||
| Return global | <= 3500 ms | <= 5000 ms | <= 5000 ms | Route must not rebuild unnecessary detail. |
|
||||
| Repeated cycle memory growth | <= 50 MB | <= 75 MB | <= 100 MB | If the browser cannot expose memory, record that explicitly instead of silently passing. |
|
||||
|
||||
## Browser Verification Boundary
|
||||
|
||||
Scripted browser trials remain the route-decision evidence because they generate repeatable JSON artifacts across all graph shapes and actions.
|
||||
|
||||
The Codex Browser plugin is an approved fallback for human-like visual and interaction checks when a local Playwright package or Chrome path is unavailable. It can validate that a page opens, visible graph controls respond, and the lightweight drawer flow matches user expectations. It must not replace the fixed-schema performance artifacts for renderer selection, because route decisions need comparable records across WebGL, Canvas, and aggregation fallback candidates.
|
||||
|
||||
## Desktop-App Compatibility Checks
|
||||
|
||||
The later desktop app direction means a candidate cannot win by hiding product logic in browser-only surfaces.
|
||||
|
||||
Required checks:
|
||||
|
||||
- Graph meaning remains in graph-engine data, not DOM attributes or renderer internals.
|
||||
- Host integration can be driven by ids, serializable state, and commands.
|
||||
- Pin/layout state remains portable and wiki-relative.
|
||||
- Candidate-specific event handling does not own product decisions such as open detail, enter community, or selected object policy.
|
||||
- The route can run inside a desktop webview or be wrapped behind a native shell bridge without rewriting graph semantics.
|
||||
|
||||
## Trial Harness Boundary
|
||||
|
||||
Allowed in Phase 6:
|
||||
|
||||
- Isolated candidate harness modules.
|
||||
- Temporary renderer pages or browser fixtures under `tests/browser/`.
|
||||
- Measurement reports under `docs/graph/performance/`.
|
||||
- Trial dependencies after explicit approval is recorded.
|
||||
|
||||
Not allowed before the route decision:
|
||||
|
||||
- Switching the workbench production global view to a candidate renderer.
|
||||
- Adding a production dependency for the final app route.
|
||||
- Leaving multiple candidate renderers active as user-facing modes.
|
||||
- Recomputing graph product semantics inside candidate-specific code.
|
||||
|
||||
## Dependency Approval Record Needed
|
||||
|
||||
If Phase 6 needs trial packages, the progress decision log must record exact approval before package changes land.
|
||||
|
||||
Expected approval entry format:
|
||||
|
||||
```text
|
||||
Task 6.x dependency approval: install <package names and versions> only for isolated renderer trial harness; no production adoption until Phase 6.4 route decision.
|
||||
```
|
||||
|
||||
Expected package classes:
|
||||
|
||||
- Sigma/Graphology trial: `sigma`, `graphology`, and any narrowly required layout/helper package.
|
||||
- vis-network trial: `vis-network` or the maintained package name selected at trial time.
|
||||
- Aggregation fallback: no package expected.
|
||||
|
||||
## Decision Output
|
||||
|
||||
Phase 6.4 must produce one of these outcomes:
|
||||
|
||||
- Integrate Sigma/Graphology as the single global large-graph route in a future implementation plan.
|
||||
- Integrate vis-network as the single global large-graph route in a future implementation plan.
|
||||
- Ship aggregation-first as the single staged global route, with explicit limits and follow-up research.
|
||||
- Reject all candidates and continue renderer research with recorded failure reasons.
|
||||
|
||||
The decision report must include accepted route, rejected alternatives, evidence artifact paths, unresolved risks, and whether community/detail DOM/SVG remains unchanged.
|
||||
@@ -0,0 +1,71 @@
|
||||
# Phase 6.1 Sigma/Graphology WebGL Trial
|
||||
|
||||
Date: 2026-06-19
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `6.1`
|
||||
Renderer: isolated Sigma/Graphology WebGL trial
|
||||
|
||||
## Scope
|
||||
|
||||
This report evaluates Sigma/Graphology as the first global large-graph renderer candidate. It does not switch the production workbench graph path. Current DOM/SVG remains the rich small-graph and community-reading path until the Phase 6.4 route decision.
|
||||
|
||||
The trial uses the shared graph adapter contract so object ids, community ids, search hits, Pin hints, selected objects, and aggregation markers remain portable across later browser or desktop shells.
|
||||
|
||||
## Commands
|
||||
|
||||
- `git log --oneline -15`
|
||||
- `npm run test --workspace=@llm-wiki/graph-engine`
|
||||
- `npm install -w @llm-wiki/graph-engine -D sigma@3.0.3 graphology@0.26.0`
|
||||
- `node --import tsx --check tests/browser/graph-sigma-graphology-trial.ts`
|
||||
- `node --import tsx --test packages/graph-engine/test/sigma-trial-adapter.test.ts`
|
||||
- `GRAPH_SIGMA_TRIAL_ARTIFACT_DIR=/tmp/llm-wiki-graph-sigma-trial-task-6-1 bash tests/graph-sigma-graphology-trial.regression-1.sh`
|
||||
|
||||
## Artifacts
|
||||
|
||||
Machine-readable result:
|
||||
|
||||
- `/tmp/llm-wiki-graph-sigma-trial-task-6-1/sigma-graphology-trial-results.json`
|
||||
|
||||
The artifact contains 47 fixed-schema records across 5 graph shapes.
|
||||
|
||||
## Post-Review Harness Hardening
|
||||
|
||||
The original result table below is now treated as a historical isolation baseline. After review, the Sigma trial harness was hardened so a run fails when any action record fails, any failure class is present, any required action is missing, any requested shape is missing, or the wrapper only produced a JSON file without valid contents.
|
||||
|
||||
The default shape set was expanded from 5 shapes to the full 11-shape stress matrix: realistic proxy, 1000 sparse/dense, 5000 sparse/dense, 10000 aggregation/high-edge, oversized community, many small communities, many search hits, and many Pin nodes. Repeated interaction/memory cycles now run on every requested shape instead of only 1000-node shapes.
|
||||
|
||||
Interaction timing now waits for visible render completion after scripted actions. Sigma uses animation-frame completion checks after search, selection, drawer, community, and return-global actions. A hardened rerun is required before using these numbers as final production-integration evidence.
|
||||
|
||||
## Result Table
|
||||
|
||||
| Shape | Nodes | Edges | DOM nodes | Initial | Wheel | Pan | Search | Point | Container | Drawer | Community | Return | Cycle |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 1000 | 1400 | 18 | pass (146.2 ms) | pass (60.2 FPS) | pass (274.0 ms) | pass (9.4 ms) | pass (2.9 ms) | pass (4.5 ms) | pass (0.7 ms) | pass (7.6 ms) | pass (2.1 ms) | pass (0 MB growth) |
|
||||
| nodes-1000-dense | 1000 | 12000 | 18 | pass (116.7 ms) | pass (60.6 FPS) | pass (268.1 ms) | pass (11.5 ms) | pass (8.3 ms) | pass (6.7 ms) | pass (0.5 ms) | pass (9.0 ms) | pass (7.1 ms) | pass (0 MB growth) |
|
||||
| nodes-5000-sparse | 5000 | 6500 | 18 | pass (175.3 ms) | pass (60.5 FPS) | pass (269.3 ms) | pass (23.4 ms) | pass (13.0 ms) | pass (8.5 ms) | pass (0.6 ms) | pass (11.8 ms) | pass (12.0 ms) | not run |
|
||||
| nodes-10000-aggregation | 10000 | 14000 | 18 | pass (289.1 ms) | pass (60.9 FPS) | pass (272.5 ms) | pass (40.9 ms) | pass (14.6 ms) | pass (18.5 ms) | pass (0.5 ms) | pass (19.0 ms) | pass (13.0 ms) | not run |
|
||||
| oversized-community | 3000 | 7000 | 18 | pass (140.6 ms) | pass (60.7 FPS) | pass (268.2 ms) | pass (14.7 ms) | pass (6.9 ms) | pass (6.9 ms) | pass (0.5 ms) | pass (8.7 ms) | pass (6.0 ms) | not run |
|
||||
|
||||
## Comparison To Current DOM/SVG Baseline
|
||||
|
||||
| Shape | DOM/SVG initial | Sigma initial | DOM/SVG wheel | Sigma wheel | DOM/SVG notable failure |
|
||||
|---|---:|---:|---:|---:|---|
|
||||
| nodes-1000-sparse | 900.4 ms | 146.2 ms | 60.0 FPS | 60.2 FPS | none |
|
||||
| nodes-1000-dense | 1008.4 ms | 116.7 ms | 59.6 FPS | 60.6 FPS | none |
|
||||
| nodes-5000-sparse | 4615.6 ms | 175.3 ms | 51.3 FPS | 60.5 FPS | none |
|
||||
| nodes-10000-aggregation | 8836.0 ms | 289.1 ms | 36.8 FPS | 60.9 FPS | pan and node click timeout |
|
||||
| oversized-community | 15788.6 ms | 140.6 ms | 12.9 FPS | 60.7 FPS | near unusable wheel FPS |
|
||||
|
||||
## Interpretation
|
||||
|
||||
Sigma/Graphology is a strong candidate for the global browsing route. The trial keeps DOM output constant, handles 10000 nodes without the DOM/SVG timeout classes, and preserves the shared semantic contract.
|
||||
|
||||
This is still not the final route decision. Phase 6 must also compare vis-network Canvas and the no-new-dependency aggregation fallback before selecting one production global renderer path. The trial also uses a minimal drawer and simple visual update model; production integration still needs design-fit, input semantics, theming, accessibility, and desktop packaging checks.
|
||||
|
||||
## Acceptance Evidence
|
||||
|
||||
- Historical shapes measured: 1000 sparse, 1000 dense, 5000 sparse, 10000 aggregation, and oversized-community.
|
||||
- Hardened default shapes now include the full 11-shape stress matrix.
|
||||
- Required actions are now enforced for every requested shape: initial render, pan, zoom, search highlight, point select, container select, drawer open, enter community, return global, and repeated memory cycle.
|
||||
- Behavior parity test passed: `node --import tsx --test packages/graph-engine/test/sigma-trial-adapter.test.ts`.
|
||||
- No production workbench renderer path was switched.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Phase 6.2 vis-network Canvas Trial
|
||||
|
||||
Date: 2026-06-19
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `6.2`
|
||||
Renderer: isolated vis-network Canvas trial
|
||||
|
||||
## Scope
|
||||
|
||||
This report evaluates vis-network as the Canvas comparison candidate. It does not switch the production workbench graph path. Current DOM/SVG remains the rich small-graph and community-reading path until the Phase 6.4 route decision.
|
||||
|
||||
The trial uses the same graph shapes and interaction actions as the Sigma/Graphology trial. It also uses a shared graph-engine adapter contract so object ids, community ids, search hits, Pin hints, selected objects, and aggregation markers remain portable.
|
||||
|
||||
## Commands
|
||||
|
||||
- `git log --oneline -15`
|
||||
- `npm run test --workspace=@llm-wiki/graph-engine`
|
||||
- `npm install -w @llm-wiki/graph-engine -D vis-network`
|
||||
- `node --import tsx --check tests/browser/graph-vis-network-trial.ts`
|
||||
- `node --import tsx --test packages/graph-engine/test/vis-network-trial-adapter.test.ts`
|
||||
- `GRAPH_VIS_TRIAL_ARTIFACT_DIR=/tmp/llm-wiki-graph-vis-trial-task-6-2 bash tests/graph-vis-network-trial.regression-1.sh`
|
||||
|
||||
## Artifacts
|
||||
|
||||
Machine-readable result:
|
||||
|
||||
- `/tmp/llm-wiki-graph-vis-trial-task-6-2/vis-network-trial-results.json`
|
||||
|
||||
The artifact contains 47 fixed-schema records across 5 graph shapes.
|
||||
|
||||
## Post-Review Harness Hardening
|
||||
|
||||
The original result table below is now treated as a historical isolation baseline. After review, the vis-network trial harness was hardened so a run fails when any action record fails, any failure class is present, any required action is missing, any requested shape is missing, or the wrapper only produced a JSON file without valid contents.
|
||||
|
||||
The default shape set was expanded from 5 shapes to the full 11-shape stress matrix: realistic proxy, 1000 sparse/dense, 5000 sparse/dense, 10000 aggregation/high-edge, oversized community, many small communities, many search hits, and many Pin nodes. Repeated interaction/memory cycles now run on every requested shape instead of only 1000-node shapes.
|
||||
|
||||
Interaction timing now waits for visible render completion after scripted actions. vis-network uses `afterDrawing` completion checks for render-affecting actions; the earlier timeout-based ready fallback was removed so a page cannot be marked ready without a completed draw. A hardened rerun is required before using these numbers as final production-integration evidence.
|
||||
|
||||
## Result Table
|
||||
|
||||
| Shape | Nodes | Edges | DOM nodes | Initial | Wheel | Pan | Search | Point | Container | Drawer | Community | Return | Cycle |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 1000 | 1400 | 20 | pass (117.6 ms) | pass (60.4 FPS) | pass (266.4 ms) | pass (28.0 ms) | pass (18.1 ms) | pass (9.3 ms) | pass (0.6 ms) | pass (7.3 ms) | pass (2.4 ms) | pass (0 MB growth) |
|
||||
| nodes-1000-dense | 1000 | 12000 | 20 | pass (215.2 ms) | pass (60.4 FPS) | pass (292.0 ms) | pass (40.8 ms) | pass (49.4 ms) | pass (24.7 ms) | pass (0.6 ms) | pass (24.5 ms) | pass (8.4 ms) | pass (0 MB growth) |
|
||||
| nodes-5000-sparse | 5000 | 6500 | 20 | pass (263.0 ms) | pass (60.2 FPS) | pass (274.3 ms) | pass (81.7 ms) | pass (66.3 ms) | pass (33.3 ms) | pass (0.4 ms) | pass (32.5 ms) | pass (9.8 ms) | not run |
|
||||
| nodes-10000-aggregation | 10000 | 14000 | 20 | pass (456.5 ms) | pass (60.9 FPS) | pass (331.6 ms) | pass (148.0 ms) | pass (138.3 ms) | pass (91.0 ms) | pass (5.2 ms) | pass (94.6 ms) | pass (19.3 ms) | not run |
|
||||
| oversized-community | 3000 | 7000 | 20 | pass (216.5 ms) | pass (60.5 FPS) | pass (270.5 ms) | pass (63.1 ms) | pass (46.4 ms) | pass (27.1 ms) | pass (0.5 ms) | pass (25.8 ms) | pass (7.0 ms) | not run |
|
||||
|
||||
## Comparison To Sigma And DOM/SVG
|
||||
|
||||
| Shape | DOM/SVG initial | Sigma initial | vis-network initial | Sigma search | vis-network search | Sigma point | vis-network point |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 900.4 ms | 146.2 ms | 117.6 ms | 9.4 ms | 28.0 ms | 2.9 ms | 18.1 ms |
|
||||
| nodes-1000-dense | 1008.4 ms | 116.7 ms | 215.2 ms | 11.5 ms | 40.8 ms | 8.3 ms | 49.4 ms |
|
||||
| nodes-5000-sparse | 4615.6 ms | 175.3 ms | 263.0 ms | 23.4 ms | 81.7 ms | 13.0 ms | 66.3 ms |
|
||||
| nodes-10000-aggregation | 8836.0 ms | 289.1 ms | 456.5 ms | 40.9 ms | 148.0 ms | 14.6 ms | 138.3 ms |
|
||||
| oversized-community | 15788.6 ms | 140.6 ms | 216.5 ms | 14.7 ms | 63.1 ms | 6.9 ms | 46.4 ms |
|
||||
|
||||
Both candidate renderers remove the current DOM/SVG bottleneck class for global browsing. vis-network keeps wheel zoom near 60 FPS on all required shapes, but it is slower than Sigma/Graphology for search, point selection, and container/community updates in this isolated harness.
|
||||
|
||||
## Integration Risks
|
||||
|
||||
- vis-network owns more of the interaction and selection model by default. The trial disables physics and routes selection through explicit shared commands to avoid fighting llm-wiki drawer/community/search semantics.
|
||||
- Layout ownership can become opaque if production integration enables vis-network physics or stabilization. Pin and fixed-position behavior should remain owned by graph-engine, not by vis-network runtime state.
|
||||
- The Canvas route depends on DataSet mutation patterns. Search and selection are still acceptable in this trial, but they scale worse than the Sigma candidate on the same data.
|
||||
- Desktop packaging is plausible because the semantic layer remains outside the renderer, but production integration would need a strict adapter boundary to prevent product logic from moving into vis-network callbacks.
|
||||
|
||||
## Interpretation
|
||||
|
||||
vis-network is a viable Canvas comparison candidate, but this trial does not currently beat Sigma/Graphology on the important semantic-update actions. It remains in the Phase 6 comparison set until the aggregation fallback and final route decision are recorded.
|
||||
|
||||
## Acceptance Evidence
|
||||
|
||||
- Historical shapes measured: 1000 sparse, 1000 dense, 5000 sparse, 10000 aggregation, and oversized-community.
|
||||
- Hardened default shapes now include the full 11-shape stress matrix.
|
||||
- Required actions are now enforced for every requested shape: initial render, pan, zoom, search highlight, point select, container select, drawer open, enter community, return global, and repeated memory cycle.
|
||||
- Behavior parity test passed: `node --import tsx --test packages/graph-engine/test/vis-network-trial-adapter.test.ts`.
|
||||
- No production workbench renderer path was switched.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Phase 6.3 Aggregation Fallback Trial
|
||||
|
||||
Date: 2026-06-19
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `6.3`
|
||||
Renderer: no-new-dependency aggregation fallback trial
|
||||
|
||||
## Scope
|
||||
|
||||
This report evaluates the no-new-dependency fallback route using the current graph-engine budget and aggregation semantics. It does not switch the production workbench graph path.
|
||||
|
||||
The trial renders lightweight global points, capped skeleton edges, capped labels, aggregation containers, and a lightweight drawer. It intentionally does not render global cards. This tests whether the current stack can provide a fast structural overview without pretending it is a full 10000+ detailed renderer.
|
||||
|
||||
## Commands
|
||||
|
||||
- `git log --oneline -15`
|
||||
- `npm run test --workspace=@llm-wiki/graph-engine`
|
||||
- `node --import tsx --check tests/browser/graph-aggregation-fallback-trial.ts`
|
||||
- `node --import tsx --test packages/graph-engine/test/aggregation-fallback-trial-adapter.test.ts`
|
||||
- `GRAPH_AGGREGATION_TRIAL_ARTIFACT_DIR=/tmp/llm-wiki-graph-aggregation-trial-task-6-3 bash tests/graph-aggregation-fallback-trial.regression-1.sh`
|
||||
|
||||
## Artifacts
|
||||
|
||||
Machine-readable result:
|
||||
|
||||
- `/tmp/llm-wiki-graph-aggregation-trial-task-6-3/aggregation-fallback-trial-results.json`
|
||||
|
||||
The artifact contains 47 fixed-schema records across 5 graph shapes.
|
||||
|
||||
## Post-Review Harness Hardening
|
||||
|
||||
The original result table below is now treated as a historical isolation baseline. After review, the aggregation fallback trial harness was hardened so a run fails when any action record fails, any failure class is present, any required action is missing, any requested shape is missing, or the wrapper only produced a JSON file without valid contents.
|
||||
|
||||
The default shape set was expanded from 5 shapes to the full 11-shape stress matrix: realistic proxy, 1000 sparse/dense, 5000 sparse/dense, 10000 aggregation/high-edge, oversized community, many small communities, many search hits, and many Pin nodes. Repeated interaction/memory cycles now run on every requested shape instead of only 1000-node shapes.
|
||||
|
||||
Interaction timing now waits for animation-frame completion after scripted actions. The aggregation fallback still uses internal `zoomBy` and `panBy` helpers for zoom and pan, so its zoom/pan numbers are useful for current-stack fallback pressure but are not directly equivalent to the real mouse-input measurements in the Sigma and vis-network trials.
|
||||
|
||||
## Result Table
|
||||
|
||||
| Shape | Nodes | Edges | DOM nodes | Visible nodes | Visible edges | Labels | Cards | Initial | Wheel | Search | Hidden interaction objects |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 1000 | 1400 | 2053 | 1000 | 1000 | 40 | 0 | pass (71.7 ms) | pass (60.2 FPS) | pass (12.0 ms) | 34 |
|
||||
| nodes-1000-dense | 1000 | 12000 | 2053 | 1000 | 1000 | 40 | 0 | pass (66.1 ms) | pass (60.1 FPS) | pass (11.4 ms) | 34 |
|
||||
| nodes-5000-sparse | 5000 | 6500 | 6103 | 5000 | 1000 | 40 | 0 | pass (136.4 ms) | pass (60.7 FPS) | pass (64.2 ms) | 4034 |
|
||||
| nodes-10000-aggregation | 10000 | 14000 | 11153 | 10000 | 1000 | 40 | 0 | pass (185.9 ms) | pass (60.6 FPS) | pass (184.6 ms) | 9034 |
|
||||
| oversized-community | 3000 | 7000 | 4068 | 3000 | 1000 | 40 | 0 | pass (92.2 ms) | pass (60.2 FPS) | pass (40.6 ms) | 2034 |
|
||||
|
||||
## Comparison To Renderer Candidates
|
||||
|
||||
| Shape | Sigma initial | vis-network initial | Aggregation initial | Sigma search | vis-network search | Aggregation search |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 146.2 ms | 117.6 ms | 71.7 ms | 9.4 ms | 28.0 ms | 12.0 ms |
|
||||
| nodes-1000-dense | 116.7 ms | 215.2 ms | 66.1 ms | 11.5 ms | 40.8 ms | 11.4 ms |
|
||||
| nodes-5000-sparse | 175.3 ms | 263.0 ms | 136.4 ms | 23.4 ms | 81.7 ms | 64.2 ms |
|
||||
| nodes-10000-aggregation | 289.1 ms | 456.5 ms | 185.9 ms | 40.9 ms | 148.0 ms | 184.6 ms |
|
||||
| oversized-community | 140.6 ms | 216.5 ms | 92.2 ms | 14.7 ms | 63.1 ms | 40.6 ms |
|
||||
|
||||
## Product Interpretation
|
||||
|
||||
Aggregation fallback is fast enough for a structural global overview. It keeps global cards at zero, caps labels at 40, caps visible edges at 1000, and preserves selected/search/Pin/container semantics through the shared adapter.
|
||||
|
||||
It is not equivalent to a full global renderer. At 10000 nodes it hides 9034 interaction-time objects and depends on the drawer/list layer to expose omitted detail. That is acceptable as a fallback or staged route, but not enough by itself for rich 10000+ exploration if the product wants direct large-map inspection with full relation density.
|
||||
|
||||
## Acceptance Evidence
|
||||
|
||||
- Historical shapes measured: 1000 sparse, 1000 dense, 5000 sparse, 10000 aggregation, and oversized-community.
|
||||
- Hardened default shapes now include the full 11-shape stress matrix.
|
||||
- Required actions are now enforced for every requested shape: initial render, pan, zoom, search highlight, point select, container select, drawer open, enter community, return global, and repeated memory cycle.
|
||||
- Required fallback elements present: aggregation containers, skeleton edges, selected/search/Pin markers, and lightweight drawer overflow path.
|
||||
- Behavior parity test passed: `node --import tsx --test packages/graph-engine/test/aggregation-fallback-trial-adapter.test.ts`.
|
||||
- No new dependency was added for this task.
|
||||
- No production workbench renderer path was switched.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Phase 6.4 Global Renderer Route Decision
|
||||
|
||||
Date: 2026-06-19
|
||||
Branch: `codex/large-graph-performance-experience`
|
||||
Task: `6.4`
|
||||
|
||||
## Decision
|
||||
|
||||
Select Sigma/Graphology WebGL as the future single global large-graph renderer integration route.
|
||||
|
||||
This task records the route decision only. It does not switch the production workbench renderer, add a production renderer path, or remove the current DOM/SVG renderer. Current DOM/SVG remains the rich small-graph and community-reading path.
|
||||
|
||||
Post-review status: this remains the current route preference, not a final production integration proof. The original Phase 6 tables were produced by the first isolated harness. The hardened harness now requires the full 11-shape matrix, complete action coverage, failed-record detection, large-shape repeated cycles, and render-completion waits. The next production integration plan must rerun the hardened trials before treating the Sigma choice as locked.
|
||||
|
||||
## Why Sigma/Graphology Wins
|
||||
|
||||
Sigma/Graphology is the best fit for the product goal: smooth 5000+ / 10000+ global browsing while preserving llm-wiki graph semantics outside the renderer.
|
||||
|
||||
Measured evidence:
|
||||
|
||||
| Shape | Sigma initial | Sigma wheel | Sigma search | Sigma point select | Sigma container select |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| nodes-1000-sparse | 146.2 ms | 60.2 FPS | 9.4 ms | 2.9 ms | 4.5 ms |
|
||||
| nodes-1000-dense | 116.7 ms | 60.6 FPS | 11.5 ms | 8.3 ms | 6.7 ms |
|
||||
| nodes-5000-sparse | 175.3 ms | 60.5 FPS | 23.4 ms | 13.0 ms | 8.5 ms |
|
||||
| nodes-10000-aggregation | 289.1 ms | 60.9 FPS | 40.9 ms | 14.6 ms | 18.5 ms |
|
||||
| oversized-community | 140.6 ms | 60.7 FPS | 14.7 ms | 6.9 ms | 6.9 ms |
|
||||
|
||||
The historical trial also kept DOM output constant at 18 nodes, passed behavior parity for object ids, community ids, search hits, Pin hints, selected objects, and aggregation markers, and did not switch the production renderer path.
|
||||
|
||||
## Rejected Alternatives
|
||||
|
||||
### vis-network Canvas
|
||||
|
||||
vis-network is viable, but it is not the chosen route.
|
||||
|
||||
Reasons:
|
||||
|
||||
- It was slower than Sigma/Graphology on semantic updates that matter to llm-wiki: search, point select, and container/community updates.
|
||||
- On the 10000-node shape, vis-network search took 148.0 ms versus Sigma/Graphology at 40.9 ms.
|
||||
- On the 10000-node shape, vis-network point select took 138.3 ms versus Sigma/Graphology at 14.6 ms.
|
||||
- vis-network owns more built-in selection, physics, stabilization, and interaction behavior. That creates higher risk that product semantics drift into renderer callbacks instead of staying in `packages/graph-engine/`.
|
||||
|
||||
vis-network remains a measured fallback candidate if a future Sigma integration hits a hard blocker, but it should not be integrated in parallel.
|
||||
|
||||
### Aggregation-Only Fallback
|
||||
|
||||
Aggregation-only is not enough to become the full global large-graph route.
|
||||
|
||||
Reasons:
|
||||
|
||||
- It is very fast for a structural overview, including 185.9 ms initial render and 60.6 FPS wheel zoom on the 10000-node shape.
|
||||
- It intentionally caps visible edges at 1000, labels at 40, cards at 0, and hides thousands of interaction-time objects at large sizes.
|
||||
- On the 10000-node shape it hid 9034 interaction-time objects, so it depends on drawer/list overflow to expose omitted detail.
|
||||
|
||||
Aggregation remains a required degradation strategy inside the future global route: keep global cards at zero, cap labels and edges, preserve selected/search/Pin objects, and use drawer overflow for omitted detail. It must not become a second permanent global graph product beside Sigma/Graphology.
|
||||
|
||||
### Current DOM/SVG As Global Renderer
|
||||
|
||||
Current DOM/SVG is rejected as the final 5000+ / 10000+ global renderer.
|
||||
|
||||
Reasons:
|
||||
|
||||
- The Phase 1 baseline showed 10000-node initial render at 8836.0 ms, wheel zoom at 36.8 FPS, and pan/node-click timeout classes.
|
||||
- Oversized-community DOM/SVG wheel zoom was 12.9 FPS.
|
||||
- DOM/SVG remains appropriate for small graphs, scoped community reading, offline detail, and UI-rich card surfaces.
|
||||
|
||||
## Integration Boundary For The Next Plan
|
||||
|
||||
The next implementation plan should integrate Sigma/Graphology only for global large-graph browsing, behind the shared renderer adapter boundary.
|
||||
|
||||
Required boundaries:
|
||||
|
||||
- `packages/graph-engine/` remains the owner of object ids, community ids, search, filters, Pin, selection, aggregation, budgets, and drawer command semantics.
|
||||
- Sigma/Graphology owns only global drawing, viewport interaction, and renderer-level hit projection through a shared adapter.
|
||||
- Workbench receives the same lightweight node summary, community summary, open-detail, enter-community, return-global, and unavailable/excluded payloads it receives today.
|
||||
- Community reading continues to use the current DOM/SVG rich path unless a later plan proves a different scoped renderer.
|
||||
- Desktop compatibility remains a guardrail: renderer integration may use browser/WebGL APIs internally, but graph semantics must stay serializable and portable across a desktop webview or shell bridge.
|
||||
- Aggregation budgets remain active in the global route so 10000+ views do not reintroduce full-card or unlimited-edge rendering.
|
||||
|
||||
## Next Plan Direction
|
||||
|
||||
The next plan should integrate Sigma/Graphology as the single production global renderer route only after a hardened rerun confirms the full 11-shape matrix. DOM/SVG should remain the community-reading renderer.
|
||||
|
||||
It should not integrate vis-network or ship a separate aggregation-only global product in parallel. If Sigma/Graphology integration fails on a hard blocker, the plan should stop and record the blocker before considering vis-network or aggregation-first as a replacement route.
|
||||
|
||||
## Acceptance Evidence
|
||||
|
||||
- Sigma/Graphology historically measured the first 5 graph shapes with 47 fixed-schema records and 0 errors.
|
||||
- vis-network historically measured the same first 5 shapes and was rejected with semantic update and ownership-risk evidence.
|
||||
- Aggregation fallback historically measured the same first 5 shapes and was retained only as degradation strategy and fallback evidence, not as a full global renderer.
|
||||
- Post-review harness now requires the full 11-shape matrix and blocks failed records instead of accepting result-file existence.
|
||||
- No production renderer path was added or switched.
|
||||
- No unapproved production dependency was adopted by this task.
|
||||
@@ -0,0 +1,102 @@
|
||||
# Sigma Global Renderer Production Integration Result
|
||||
|
||||
Date: 2026-06-19
|
||||
Branch: `codex/sigma-global-renderer-integration`
|
||||
Plan: `docs/plans/2026-06-19-sigma-global-renderer-integration-phased-plan.md`
|
||||
|
||||
## Result
|
||||
|
||||
Sigma/Graphology is now the production global graph renderer route for the graph-engine facade.
|
||||
|
||||
The final route boundary is:
|
||||
|
||||
- Global route: Sigma/Graphology through `sigma-global`.
|
||||
- Community reading and rich detail route: DOM/SVG through `dom-svg-community`.
|
||||
- Small abnormal fallback: DOM/SVG through `dom-svg-small-fallback`, only after Sigma is unavailable and the graph is below the safety threshold.
|
||||
- Large abnormal fallback: aggregation safety view through `aggregation-safety-fallback`.
|
||||
|
||||
There is no user-visible old/new renderer switch. The old DOM/SVG global path is not a normal global main path.
|
||||
|
||||
## Phase 0 Gate
|
||||
|
||||
The implementation started only after the plan review gate cleared:
|
||||
|
||||
- The plan review report ended with `NO UNRESOLVED DECISIONS`.
|
||||
- The implementation branch was `codex/sigma-global-renderer-integration`.
|
||||
- Baseline graph-engine tests passed before production renderer work started.
|
||||
|
||||
## Production Evidence
|
||||
|
||||
The strongest production-path artifact so far is:
|
||||
|
||||
- `/tmp/llm-wiki-sigma-global-production-task-6-2/sigma-global-production-results.json`
|
||||
|
||||
Summary:
|
||||
|
||||
- Renderer: `sigma-global-production`.
|
||||
- Production path: `true`.
|
||||
- Browser: `148.0.7778.96`.
|
||||
- Build commit recorded in artifact: `d2e857f`.
|
||||
- Shapes: 11.
|
||||
- Records: 110.
|
||||
- Failed records: 0.
|
||||
- Artifact schema: `1.0.0`.
|
||||
- Required schema, thresholds, browser, build, run timestamp, loading-state, and production-path fields are present on every record.
|
||||
|
||||
Covered shapes:
|
||||
|
||||
- `real-snapshot-proxy`
|
||||
- `nodes-1000-sparse`
|
||||
- `nodes-1000-dense`
|
||||
- `nodes-5000-sparse`
|
||||
- `nodes-5000-dense`
|
||||
- `nodes-10000-aggregation`
|
||||
- `nodes-10000-high-edge`
|
||||
- `oversized-community`
|
||||
- `many-small-communities`
|
||||
- `many-search-hits`
|
||||
- `many-pin-nodes`
|
||||
|
||||
## Hard Gate Summary
|
||||
|
||||
| Gate | Production result |
|
||||
|---|---:|
|
||||
| Failed records | 0 |
|
||||
| Wheel FPS floor | min 60.2, required >= 45 |
|
||||
| Drag FPS floor | min 60.3, required >= 45 |
|
||||
| Wheel frame p95 | max 17.6 ms, required <= 22.3 ms |
|
||||
| Drag frame p95 | max 17.6 ms, required <= 22.3 ms |
|
||||
| Initial render duration | max 0.2 ms, threshold recorded per action |
|
||||
| Search duration | max 37.7 ms, threshold recorded per action |
|
||||
| Drawer duration | max 82.0 ms, threshold recorded per action |
|
||||
| Return global duration | max 70.5 ms, threshold recorded per action |
|
||||
| Repeated-cycle memory growth | max 6.4 MB, threshold recorded per action |
|
||||
| Loading state | `sigma-global-ready` on global records |
|
||||
|
||||
`enter_community` intentionally moves through the community route, so its loading-state set includes the non-global transition state as well as `sigma-global-ready`. Return-global records prove the production route returns to Sigma successfully.
|
||||
|
||||
## Route And Fallback Boundary
|
||||
|
||||
The facade owns renderer route switching. Workbench and offline callers continue to use `createGraphEngine` and do not receive a renderer selector.
|
||||
|
||||
Fallback policy:
|
||||
|
||||
- If Sigma is available, global graph browsing uses Sigma.
|
||||
- If Sigma is unavailable for a small graph, DOM/SVG is allowed only as the emergency small fallback.
|
||||
- If Sigma is unavailable for a graph above 2000 nodes, 4000 edges, or 500 nodes in one community, the route uses aggregation safety fallback instead of DOM/SVG.
|
||||
- The aggregation safety view is a minimum usable failure state, not a second global graph product.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Earlier comparison documents remain valid as historical evidence:
|
||||
|
||||
- `2026-06-19-phase-6-1-sigma-graphology-trial.md` measured the isolated Sigma candidate.
|
||||
- `2026-06-19-phase-6-2-vis-network-trial.md` measured vis-network as a rejected comparison route.
|
||||
- `2026-06-19-phase-6-3-aggregation-fallback-trial.md` measured aggregation as a fallback strategy.
|
||||
- `2026-06-19-phase-6-4-global-renderer-route-decision.md` selected Sigma/Graphology as the route to integrate.
|
||||
|
||||
Those documents should not be read as current production state. This document records the production integration result.
|
||||
|
||||
## Residual Risk
|
||||
|
||||
This result is proven on the local Chromium/Playwright environment and recorded artifacts. Task 7.3 must still rerun the full final acceptance list and produce the final production-path artifact for plan closure.
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"viewport": "1440x960",
|
||||
"durationMs": 3004,
|
||||
"frames": 157,
|
||||
"idleFps": 13.6,
|
||||
"fps": 52.3,
|
||||
"minimumInteractionFps": 12,
|
||||
"transformChanged": true
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 233 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
Reference in New Issue
Block a user