Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/architecture/ecs-migration-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ The dedicated stores use per-concern keying strategies:
| `widgetValueStore` | `WidgetId` (`graphId:nodeId:name`) |
| `domWidgetStore` | Widget UUID |
| `layoutStore` | Raw nodeId/linkId/rerouteId |
| `nodeOutputStore` | `"${subgraphId}:${nodeId}"` |
| `nodeOutputStore` | `"${subgraphUUID}:${nodeId}"` |
| `subgraphNavigationStore` | subgraphId or `'root'` |

ADR 0009 refines the promoted-widget target: promoted value widgets should use
Expand Down
11 changes: 6 additions & 5 deletions docs/architecture/ecs-target-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ graph LR
graphId:nodeId:name
(branded string, src/types/widgetId.ts)"]
NLID["nodeLocatorId
subgraphId:nodeId"]
subgraphUUID:nodeId"]
NID["nodeId (raw)"]
LID["linkId (raw)"]
RID["rerouteId (raw)"]
Expand All @@ -73,10 +73,11 @@ subgraphId:nodeId"]
```

`WidgetId = graphId:nodeId:name` is itself a branded string (see
`src/types/widgetId.ts`). `nodeLocatorId = subgraphId:nodeId` addresses node
outputs. `layoutStore` keys layout records by raw `nodeId` / `linkId` /
`rerouteId`. Each store enforces its own key shape; there is no single shared
entity-ID type across stores.
`src/types/widgetId.ts`). `nodeLocatorId = subgraphDefinitionUUID:nodeId` addresses node
outputs, where the first segment is the subgraph definition's UUID and the second is
the node's sequential integer ID (not a UUID). `layoutStore` keys layout records by raw
`nodeId` / `linkId` / `rerouteId`. Each store enforces its own key shape; there is no
single shared entity-ID type across stores.

Note: `graphId` is a scope identifier. It identifies which graph an entity
belongs to and forms the prefix of `WidgetId`. Subgraphs are nodes with a
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture/proto-ecs-stores.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ state, and promoted value data lives in `WidgetValueStore` keyed by the input's
| WidgetValueStore | `BaseWidget` | `graphId` | `WidgetId` (`graphId:nodeId:name`) | Plain `WidgetState` object |
| DomWidgetStore | `BaseDOMWidget` | Global | `widgetId` (UUID) | Position, visibility, z-index |
| LayoutStore | Node, Link, Reroute | Workflow-level | `nodeId`, `linkId`, `rerouteId` | Y.js CRDT maps (pos, size) |
| NodeOutputStore | Execution results | `nodeLocatorId` | `"${subgraphId}:${nodeId}"` | Output data, preview URLs |
| NodeOutputStore | Execution results | `nodeLocatorId` | `"${subgraphUUID}:${nodeId}"` | Output data, preview URLs |
| SubgraphNavigationStore | Canvas viewport | `subgraphId` | `subgraphId` or `'root'` | LRU viewport cache |
| PreviewExposureStore | Subgraph host node | host node locator | host locator + exposure name | Display-only preview state |

Expand Down Expand Up @@ -239,7 +239,7 @@ Each store owns the identity scheme that fits its concern:
| WidgetValueStore | `WidgetId` (`graphId:nodeId:name`) | branded string | Yes (`WidgetId`) |
| DomWidgetStore | Widget UUID | UUID (string) | No |
| LayoutStore | Raw nodeId/linkId/rerouteId | Mixed number types | No |
| NodeOutputStore | `"${subgraphId}:${nodeId}"` | Composite string | No |
| NodeOutputStore | `"${subgraphUUID}:${nodeId}"` | Composite string | No |

`WidgetValueStore` already keys on a branded `WidgetId` string (`src/types/widgetId.ts`),
which carries its scope and survives renames at the store layer. The remaining
Expand Down
6 changes: 3 additions & 3 deletions src/types/nodeIdentification.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,16 @@ describe('nodeIdentification', () => {
expect(isNodeLocatorId(undefined)).toBe(false)
})

it('should validate UUID format correctly', () => {
// Valid UUID formats
it('should require a valid UUID as the subgraph prefix', () => {
// Valid subgraph UUIDs (node IDs like "123" are sequential integers, not UUIDs)
expect(
isNodeLocatorId('00000000-0000-0000-0000-000000000000:123')
).toBe(true)
expect(
isNodeLocatorId('A1B2C3D4-E5F6-7890-ABCD-EF1234567890:123')
).toBe(true)

// Invalid UUID formats
// Invalid subgraph UUID prefixes
expect(isNodeLocatorId('00000000-0000-0000-0000-00000000000:123')).toBe(
false
) // Too short
Expand Down
2 changes: 1 addition & 1 deletion src/utils/graphTraversalUtil.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ describe('graphTraversalUtil', () => {
expect(found?.id).toBe('123')
})

it('should find node in subgraph using UUID format', () => {
it('should find node in subgraph using subgraph locator format', () => {
const targetUuid = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
const targetNode = createMockNode('789')
const subgraph = createMockSubgraph(targetUuid, [targetNode])
Expand Down
5 changes: 3 additions & 2 deletions src/utils/graphTraversalUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,11 @@ export function getExecutionIdFromNodeData(

/**
* Get a node by its locator ID from anywhere in the graph hierarchy.
* Locator IDs use UUID format like "uuid:nodeId" for subgraph nodes.
* For subgraph nodes, the format is `<subgraph-definition-uuid>:<node-id>` where
* the node ID is a sequential integer, not a UUID.
*
* @param rootGraph - The root graph to search from
* @param locatorId - The locator ID (e.g., "uuid:123" or "123")
* @param locatorId - The locator ID (e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890:123" or "123")
* @returns The node if found, null otherwise
*/
export function getNodeByLocatorId(
Expand Down
Loading