将资源依赖图计算迁移到Rust
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 7s
Project CI / Frontend tests (pull_request) Successful in 2m50s
Project CI / Native shell tests (pull_request) Successful in 11m33s

新增只读资源依赖图模型,完成过滤、去重、环检测和任务流聚合
前端SVG仅负责几何渲染、搜索联动、选中高亮和拖动预览
补充资源图、覆盖层和工作台回归测试
同步更新工作台PRD、技术方案与项目记忆
This commit is contained in:
2026-07-31 19:09:57 +08:00
parent f582ecf032
commit 29dce59b35
14 changed files with 1874 additions and 558 deletions
@@ -153,7 +153,7 @@ P0 中 `approvalMode` 只能有效写入 `strict`;其它值只能作为不可
### 5.2 资源画布布局(P1)
实现状态(2026-07-31):本节布局合同已在独立客户端落地,dependency / type 双模式通过项目内 CAS sidecar 独立持久化;dependency 模式的前端资源依赖关系图层也已落地,但不写入布局 sidecar。资源替换、缩放 / 平移等其余 P1 能力仍按本文非目标保持未实现。
实现状态(2026-07-31):本节布局合同已在独立客户端落地,dependency / type 双模式通过项目内 CAS sidecar 独立持久化;dependency 模式由 Tauri Rust 只读构建关系拓扑、前端 SVG 派生几何,图结构和线段均不写入布局 sidecar。资源替换、缩放 / 平移等其余 P1 能力仍按本文非目标保持未实现。
```ts
type ProjectResourceCanvasLayout = {
@@ -250,14 +250,16 @@ type UpdateProjectResourceCanvasLayoutResult =
#### 5.2.5 资源依赖关系图层
- 图层只在 dependency 模式挂载;type 模式不得渲染 SVG、连线或 marker。切换 mode、切换项目或卸载工作台时必须销毁旧图层,并清理尺寸观察和窗口事件监听。
- 输入固定为当前资源投影的全部卡片坐标与前端 `ProjectResourceGraph`;输出使用原生 SVG 的 path 和箭头 marker。SVG 叠加在资源卡底层并设置 `pointer-events: none`,不得引入 D3、React Flow 等图表库,也不得阻断卡片点击和 Pointer Events 拖动。
- 输入固定为当前资源投影的全部卡片身份 / 坐标与 Tauri Rust 返回的 `ProjectResourceGraph` 只读 DTO;Rust 负责资源过滤、去重、环检测、任务流聚合和一跳连接索引,前端只负责 DTO 防御归一化、浏览器几何与原生 SVG path / marker。SVG 叠加在资源卡底层并设置 `pointer-events: none`,不得引入 D3、React Flow 等图表库,也不得阻断卡片点击和 Pointer Events 拖动。
- `asset-reference` 表示精确资源引用,使用橙色实线与连续贝塞尔曲线。`GameCreationAppAssetManifestEntry.source.referenceResourceIds` 中的外部资源 ID 必须先唯一匹配另一项资产的 `source.resourceId`,再映射为当前资源卡 ID;缺失、重复或已删除的目标均不得渲染幽灵连线。
- `task-flow` 表示任务产物流转,使用灰色圆头虚线。任务依赖按 `sourceTaskId -> targetTaskId` 聚合为一条主线,两端资源仅绘制平滑曲线分支,不得出现直角折线;禁止对上下游资源生成笛卡尔积连线。任务主线与分支可以使用不同线宽和透明度表达聚合层级,但不能改变端点或方向语义。
- 画布资产 producer 只能来自 `agent.runtime.canvas.asset_generate` 的 `assetId -> agentId` 审计且 `agentId` 必须存在于当前 manifest;External Editor `source.taskId` 属于平台生成任务命名空间,禁止当作 manifest task ID。证据缺失、冲突或有界审计读取未覆盖时不生成对应 task flow,不猜测归属。
- 图模型必须对资源引用图和完整任务依赖图做迭代式环检测,不得用无界递归遍历;参与环的可见边保留渲染并标记 cyclic,环本身不能造成重复生成或死循环。
- 资源自引用的起点与终点为同一张卡片时,必须绘制在卡片外侧的可见闭环并保留箭头,不得让路径穿过卡片后被底层 SVG 层级遮挡。
- 搜索只允许为当前可见端点生成几何;任一精确引用端点隐藏时该线隐藏,聚合任务流只保留仍可见的两端分支,任一侧没有可见资源时整条任务流隐藏。
- 选中资源后,高亮其直接上游、直接下游卡片和关联边,弱化其余边;不做跨多层递归高亮。选中 ID 已失效时按未选中处理。
- 拖动预览坐标必须直接进入 SVG 几何计算,使连线随 pointer move 实时更新;拖动结束仍只保存卡片布局坐标,不持久化 path、marker、section 原点或任何图结构。
- Pointer Move 必须按动画帧合并;基础 positions 不随每帧复制,静态 SVG 拓扑保持复用,每帧只更新当前资源局部索引关联的 path。`ResizeObserver` 在单个图层生命周期只允许构造一次。dependency section 额外提供至少 `64px` 右侧视觉 gutter,确保最右侧自环和箭头可完整滚动显示,但不得修改卡片坐标或布局 sidecar。
### 5.3 资源类型与替换兼容性(P1)
@@ -402,10 +404,11 @@ type ProjectAgentMudPointAttribution = {
4. 资源引用环和无资源产物参与的任务环都可被有限遍历识别,界面不死循环。
5. 搜索、选择和拖动分别触发端点过滤、直接上下游高亮和实时几何更新;原有点击、详情浮层与拖动保存行为不回归。
6. 切换布局模式或项目后旧 SVG、ResizeObserver 与窗口监听全部清理;图层从不写入 layout sidecar、manifest 或其它持久化。
7. 4096 资源链式 fixture 下,拖动一张卡片只更新它关联的线段;同一图层 100 次拖动期间 Observer 仍只构造一次。真实 Chromium 目标为拖动 p95 小于 `16.7ms`、不出现超过 `50ms` 的 long task,并完整显示最右侧自环与箭头。
## 8. 非目标
- 本切片仍不实现资源替换、不可变迭代版本、画板编辑状态、测试切片、数值参数或泥点归因;已实现的资源关系图只提供前端派生展示,不建立新的资源业务真相。
- 本切片仍不实现资源替换、不可变迭代版本、画板编辑状态、测试切片、数值参数或泥点归因;已实现的资源关系图只提供 Rust 只读拓扑与前端派生展示,不建立新的资源业务真相。
- 本切片不保存资源详情浮层位置、画布缩放 / 平移、搜索条件、筛选条件或当前 mode;这些状态如需持久化必须另行扩展合同,不能塞入 `game-creator-resource-layout.v1`。
- 不修改 SpacetimeDB schema。
- 不开放普通用户 Agent.md/Skill。