Skip to content

C23: Graph v2 mutations and validateGraph core - #897

Merged
LinuxDevil merged 4 commits into
mainfrom
fb-c23-graph-mutations
Nov 7, 2026
Merged

LinuxDevil merged 4 commits into
mainfrom
fb-c23-graph-mutations

Conversation

@LinuxDevil

Copy link
Copy Markdown
Owner

What changed

Pure, immutable graph mutations plus the single validation entry point for the canvas graph v2 (no canvas/Inspector wiring — that is the C24 cutover).

  • graph/v2/mutations.ts: NewNode, ownerForNewNode (selected agent → selected node's owner → root; root-only kinds always agent, notes null), addNode (dedupeId(baseNodeId(...)) ids; note:n<ts><counter> for notes), removeNode (root returns same reference; inline agents remove their whole owner-chain subtree plus matching emptySections/unplaced), duplicateNode (root + notes refused, KIND_RULES[kind].duplicateData ?? structuredClone, +40/+40), moveNode, setNodeData, patchNode (merges into data.item / data.fields for agents / data.step for flow / data for notes; undefined deletes the key), setCollapsed, connectNodes (canConnect refusal verbatim, then KIND_RULES[source.kind].connectFrom ?? default re-own). Node ids are never recomputed after creation — nodeIdMap rekeys at save.
  • graph/v2/reown.ts: the re-own effect (reownNode — id-stable, {x:24,y:48} entering a group, absolute position leaving one). Kept in a leaf module so kinds/*.ts connect effects can share it without an import cycle through kindRules.
  • graph/v2/kindRules.ts: ConnectResult, KindRules<K> (validate / connectFrom / duplicateData), and the KIND_RULES registry starting with agent.
  • graph/v2/kinds/agent.ts: agentRules — connectFrom = re-own target to the source agent (C03 adds validate, C04 duplicateData).
  • graph/v2/validateGraph.ts: validateGraph(graph): Problem[] — a CORE_CHECKS table (one function per row: no main agent, duplicate node id, missing owner, root-only kind on a non-root owner, duplicate mcp/subagent keys per owner, duplicate memory names, non-unique guardrail/permission/hook/trigger/abort item ids across the graph, second output on one agent) plus KIND_RULES[kind].validate per node in orderedNodes order. specPaths comes from one graphToSpec call with a tolerant mirror for graphs it cannot re-emit (duplicate record keys, second output). Order: graph-level problems first, then node walk order, errors before warnings within a node.
  • types.ts: added ROOT_ONLY_KINDS (trigger, abort, flow — derived from ROOT_ONLY_SECTIONS).

How it was tested

  • npm run typecheck --workspace apps/agent-forge — clean
  • npm test --workspace apps/agent-forge -- --run src/graph/v2 — 1444 tests pass (124 new mutation cases incl. the 100-seed mutation round-trip property, 16 validateGraph cases — one per core-check row with exact message/nodeId/fieldPath, ordering, clean worked example → [])
  • npx vitest run (apps/agent-forge) — 2412 pass · npm run typecheck:server, npm run test:server — 1121 pass · root npx tsc --noEmit — clean
  • npm run lint (root) — clean · Studio lint — 0 errors (31 pre-existing warnings, none in these files)
  • npm run test:coverage — 7246 pass; 6 failures in src/spec/v2/templates.test.ts README title checks (known CRLF line-ending environment issue, unrelated; create-lousho dist was built so its e2e passes)
  • npm run fallow — clean (no dead code/exports, no cycles, no new clones)
  • npm run docs:ratchet, npm run api:check, npm run docs:llms:check, npm run size-check — all pass

Acceptance criteria

  • Every mutation returns a new Graph and never mutates its input (deep-freeze the input in tests)
  • removeNode(g, 'agent') returns g unchanged (same reference)
  • Removing an inline subagent removes its whole subtree
  • connectNodes returns canConnect's refusal verbatim; agent → tool re-owns the tool
  • Each core check row produces its message for a minimal graph and nothing for a clean one

Generated with Devin

LinuxDevil and others added 3 commits November 5, 2026 00:27
Add the typed, agent-centred canvas graph model under
apps/agent-forge/src/graph/v2: Graph/GraphNode with 15 node kinds,
stable node-id helpers (toolNodeName, skillNodeName, childPrefix,
baseNodeId, dedupeId, nextItemId, uniqueName) and the connection-rule
table plus ordered instance refusals (canConnect). specTypes.ts is the
single seam to the SDK spec types; AbortListenerSpec and EvalGateSpec
are forward-declared there until their spec sections land.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@LinuxDevil
LinuxDevil changed the base branch from fb-c02-graph-roundtrip to main November 7, 2026 12:59
# Conflicts:
#	apps/agent-forge/src/graph/v2/types.ts
@LinuxDevil
LinuxDevil merged commit 487aa73 into main Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant