Node

A Node is a single vertex in a Graph. It is an immutable, frozen dataclass — you cannot mutate it in place. Instead, use Node.evolve() to produce an updated copy.

Immutability and Versioning

Every time you call evolve(), the version counter increments and updated_at is refreshed. This makes change history traceable.

from knowledge_platform.core.node import Node
from knowledge_platform.core.identifiers import new_graph_id

graph_id = new_graph_id()

# Create a fresh node
node = Node.create(graph_id, "OutlineItem", {"title": "Introduction"})
print(node.version)  # 1

# Produce an updated copy — the original is unchanged
updated = node.evolve(title="Chapter 1: Introduction", content="Body text here")
print(updated.version)          # 2
print(updated.attributes)       # {"title": "Chapter 1: Introduction", "content": "Body text here"}
print(node.attributes["title"]) # "Introduction" (original unchanged)

Attribute Payload

The attributes dict can hold any JSON-serialisable values. The semantic meaning and allowed keys are defined by the NodeSchema registered on the graph's GraphType. It is the responsibility of GraphService.add_node() to validate attributes before they reach the core.

Identity and Ownership

Field Type Meaning
id NodeId Globally unique identifier (UUID v4)
graph_id GraphId The owning graph
type_name str Semantic type (e.g. "OutlineItem")
version int Incremented on every evolve() call

API Reference

knowledge_platform.core.node.Node dataclass

A single vertex in a :class:~knowledge_platform.core.graph.Graph.

Nodes are immutable value-objects. Mutations produce new instances via :meth:evolve, which increments the version counter.

Attributes:

Name Type Description
id NodeId

Unique identifier for this node.

graph_id GraphId

Owning graph identifier.

type_name str

Semantic type string, resolved by the active :class:~knowledge_platform.domain.graph_type.GraphType.

attributes dict[str, object]

Arbitrary key-value payload; must be JSON-serialisable.

version int

Monotonically increasing change counter (starts at 1).

created_at datetime

Timestamp of initial creation (UTC).

updated_at datetime

Timestamp of the most recent update (UTC).

Source code in src/knowledge_platform/core/node.py
@dataclass(frozen=True)
class Node:
    """A single vertex in a :class:`~knowledge_platform.core.graph.Graph`.

    Nodes are immutable value-objects.  Mutations produce new instances via
    :meth:`evolve`, which increments the *version* counter.

    Attributes:
        id: Unique identifier for this node.
        graph_id: Owning graph identifier.
        type_name: Semantic type string, resolved by the active
            :class:`~knowledge_platform.domain.graph_type.GraphType`.
        attributes: Arbitrary key-value payload; must be JSON-serialisable.
        version: Monotonically increasing change counter (starts at 1).
        created_at: Timestamp of initial creation (UTC).
        updated_at: Timestamp of the most recent update (UTC).
    """

    id: NodeId
    graph_id: GraphId
    type_name: str
    attributes: dict[str, object] = field(default_factory=dict)
    version: int = 1
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    @classmethod
    def create(
        cls,
        graph_id: GraphId,
        type_name: str,
        attributes: dict[str, object] | None = None,
    ) -> "Node":
        """Factory method that generates a fresh node with a new identity.

        Args:
            graph_id: The owning graph.
            type_name: Semantic type registered on the graph's
                :class:`~knowledge_platform.domain.graph_type.GraphType`.
            attributes: Optional initial attribute payload.

        Returns:
            A new :class:`Node` with version ``1``.
        """
        now = datetime.now(timezone.utc)
        return cls(
            id=new_node_id(),
            graph_id=graph_id,
            type_name=type_name,
            attributes=attributes or {},
            version=1,
            created_at=now,
            updated_at=now,
        )

    def evolve(self, **attribute_updates: object) -> "Node":
        """Return a new :class:`Node` with merged *attribute_updates*.

        The *version* is incremented and *updated_at* is refreshed.

        Args:
            **attribute_updates: Attribute keys/values to merge.

        Returns:
            Updated immutable :class:`Node`.
        """
        merged = {**self.attributes, **attribute_updates}
        return replace(
            self,
            attributes=merged,
            version=self.version + 1,
            updated_at=datetime.now(timezone.utc),
        )

    def __repr__(self) -> str:  # pragma: no cover
        return f"Node(id={self.id!r}, type={self.type_name!r}, v{self.version})"

Functions

create classmethod
create(
    graph_id: GraphId,
    type_name: str,
    attributes: dict[str, object] | None = None,
) -> "Node"

Factory method that generates a fresh node with a new identity.

Parameters:

Name Type Description Default
graph_id GraphId

The owning graph.

required
type_name str

Semantic type registered on the graph's :class:~knowledge_platform.domain.graph_type.GraphType.

required
attributes dict[str, object] | None

Optional initial attribute payload.

None

Returns:

Type Description
'Node'

A new :class:Node with version 1.

Source code in src/knowledge_platform/core/node.py
@classmethod
def create(
    cls,
    graph_id: GraphId,
    type_name: str,
    attributes: dict[str, object] | None = None,
) -> "Node":
    """Factory method that generates a fresh node with a new identity.

    Args:
        graph_id: The owning graph.
        type_name: Semantic type registered on the graph's
            :class:`~knowledge_platform.domain.graph_type.GraphType`.
        attributes: Optional initial attribute payload.

    Returns:
        A new :class:`Node` with version ``1``.
    """
    now = datetime.now(timezone.utc)
    return cls(
        id=new_node_id(),
        graph_id=graph_id,
        type_name=type_name,
        attributes=attributes or {},
        version=1,
        created_at=now,
        updated_at=now,
    )
evolve
evolve(**attribute_updates: object) -> 'Node'

Return a new :class:Node with merged attribute_updates.

The version is incremented and updated_at is refreshed.

Parameters:

Name Type Description Default
**attribute_updates object

Attribute keys/values to merge.

{}

Returns:

Type Description
'Node'

Updated immutable :class:Node.

Source code in src/knowledge_platform/core/node.py
def evolve(self, **attribute_updates: object) -> "Node":
    """Return a new :class:`Node` with merged *attribute_updates*.

    The *version* is incremented and *updated_at* is refreshed.

    Args:
        **attribute_updates: Attribute keys/values to merge.

    Returns:
        Updated immutable :class:`Node`.
    """
    merged = {**self.attributes, **attribute_updates}
    return replace(
        self,
        attributes=merged,
        version=self.version + 1,
        updated_at=datetime.now(timezone.utc),
    )