Skip to content

Property-graph model (Node + Edge) — M1 spike for #43#44

Merged
ecv merged 2 commits into
mainfrom
prototype/graph-model-m1
Jun 12, 2026
Merged

Property-graph model (Node + Edge) — M1 spike for #43#44
ecv merged 2 commits into
mainfrom
prototype/graph-model-m1

Conversation

@ecv

@ecv ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Prototype of the M1 changeset from RFC #43 (collapse the NetBox-inspired per-kind hierarchy into a property graph). Tracking enhancement: datum-cloud/enhancements#764.

What this is

A working, envtest-covered prototype of the graph model: typed nodes and edges, both carrying key/value attributes validated against a schema registry.

New v1alpha2 kinds (api/v1alpha2/)

  • Node — graph vertex. spec.type names the asset class (Site, Host [the former compute Node], …), spec.attributes holds its data. Type immutable.
  • Edge — directed relationship. spec.type (located-in, member-of, …) + from/to + attributes. Type immutable; endpoints distinct (CEL).
  • NodeType / EdgeType — closed attribute schemas (key/type/required/enum); EdgeType also constrains endpoint node-types.

Validation (internal/graph/)

Shared between admission webhooks and reconcilers: unknown-key reject, missing-required, Integer/Float/Boolean parse, String enum; edges check endpoint existence + endpoint-type constraints. Node DELETE is a generic delete-guard — one Edge-endpoint field indexer replaces the per-kind reference indexers of v1alpha1.

Key decision — group name

The RFC's collision is real at the CRD level: kind Node can't carry two incompatible schemas under one group without a conversion webhook. So the prototype uses group graph.inventory.miloapis.com → installs side-by-side with v1alpha1. The production migration reclaims inventory.miloapis.com once v1alpha1 is removed (per RFC, compute node → type: Host).

Tests

internal/controller/graph_controller_test.go (envtest): Node/Edge happy paths, attribute-schema rejections (unknown / missing-required / bad-type / bad-enum), edge endpoint-existence + endpoint-type-constraint rejections, and the Node delete-guard. Full suite green (63 specs).

Explicitly out of scope (M2 / follow-ups)

🤖 Generated with Claude Code

ecv and others added 2 commits June 12, 2026 13:31
Prototype of the M1 changeset from RFC #43: collapse the
NetBox-inspired per-kind hierarchy into a property graph of typed nodes and
edges, both carrying key/value attribute bags validated against a schema
registry.

New v1alpha2 kinds:
- Node     — graph vertex; spec.type names its asset class (Region, Site,
             Host [the former compute Node], ...), spec.attributes its data.
- Edge     — directed relationship; spec.type names the relationship class
             (located-in, member-of, ...), with from/to endpoints + attributes.
- NodeType — closed attribute schema for a class of nodes.
- EdgeType — closed attribute schema + endpoint-type constraints for edges.

Validation (internal/graph) is shared between admission webhooks and
reconcilers: attributes are checked against the NodeType/EdgeType schema
(unknown keys, missing-required, type/enum parsing); edges verify endpoint
existence and endpoint-type constraints. The Node DELETE webhook is a generic
delete-guard — one Edge-endpoint field indexer replaces the per-kind reference
indexers of v1alpha1.

The graph kinds use group graph.inventory.miloapis.com so the prototype
installs side-by-side with v1alpha1, whose `Node` kind would otherwise collide
at the CRD level (the very collision the RFC resolves via type: Host). The
production migration reclaims inventory.miloapis.com after v1alpha1 removal.

Not in scope for this prototype: envtest suite wiring, IAM ProtectedResource/
Roles, topology-label propagation, CR migration tooling (M2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Register the v1alpha2 scheme, graph indexers, graph reconcilers, and graph
webhooks in the controller envtest suite so the property-graph model is
exercised against a real apiserver. Adds graph_controller_test.go covering:

- Node Ready when NodeType exists and attributes validate
- Node admission rejects: missing NodeType, unknown attribute, missing
  required attribute, non-parsing Integer, out-of-enum String
- Edge Ready + EndpointsResolved when both endpoints exist
- Edge admission rejects: missing endpoint Node, endpoint-type-constraint
  violation
- Node DELETE blocked while an Edge references it (generic delete-guard)

Also fixes the Edge distinct-endpoints CEL rule: structs are not comparable
with `!=`, so compare self.from.name != self.to.name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ecv

ecv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

imma do datum-cloud/inventory#9 next

@ecv ecv changed the title [prototype] Property-graph model (Node + Edge) — M1 spike for #43 Property-graph model (Node + Edge) — M1 spike for #43 Jun 12, 2026
@ecv ecv merged commit 6aa2cb8 into main Jun 12, 2026
3 checks passed
@ecv ecv deleted the prototype/graph-model-m1 branch June 12, 2026 18:18
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.

2 participants