Files
git.stella-ops.org/docs/modules/workflow/slot-lattice.md
master 7943cfb3af chore(docs+devops): cross-module doc sync + sprint archival moves + compose updates
Bundled pre-session doc + ops work:
- docs/modules/**: sync across advisory-ai, airgap, cli, excititor,
  export-center, findings-ledger, notifier, notify, platform, router,
  sbom-service, ui, web (architectural + operational updates)
- docs/features/**: updates to checked excititor vex pipeline,
  developer workspace, quick verify drawer
- docs top-level: README, quickstart, API_CLI_REFERENCE, UI_GUIDE,
  code-of-conduct/TESTING_PRACTICES updates
- docs/qa/feature-checks/: FLOW.md + excititor state update
- docs/implplan/: remaining sprint updates + new Concelier source
  credentials sprint (SPRINT_20260422_003)
- docs-archived/implplan/: 30 sprint archival moves (ElkSharp series,
  misc completed sprints)
- devops/compose: .env + services compose + env example + router gateway
  config updates

File-level granularity preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:06:39 +03:00

3.1 KiB

ElkSharp — Node Slot Lattice (per-kind port metadata)

Status: Introduced by Sprint 20260420.013 (BK Phase A — port-slot lattice). Consumers: ElkOrthogonalRouter (Sprint 16+), future ElkBrandesKopfPlacement (Sprint 14+). Source: src/__Libraries/StellaOps.ElkSharp/ElkNodeSlotLattice.cs.

What is the lattice?

For every ElkNode.Kind that the Stella Ops workflow engine emits, the lattice declares a fixed set of slots on the node's boundary. Each slot is a tuple (face, fractionAlongFace, direction) where:

  • face — one of NORTH, SOUTH, EAST, WEST.
  • fractionAlongFace0.0 .. 1.0 position along the face.
  • directionIncomingOnly, OutgoingOnly, or Either.

The lattice is static per kind. Slot counts, positions, and direction restrictions are hard-coded; no per-instance configuration. Unknown kinds fall through to the rectangular default.

Per-kind declarations

Kind Faces & slots Direction
Start 1 slot on SOUTH, centred (0.5) OutgoingOnly
End 1 slot on NORTH, centred (0.5) IncomingOnly
Task, SetState, BusinessReference, TransportCall, ServiceCall, Timer, Repeat 3 slots each on E/W faces (0.25, 0.5, 0.75); 5 slots each on N/S faces (0.17, 0.33, 0.5, 0.67, 0.83) Either
Decision (diamond) N tip (0.5) incoming; S tip (0.5) outgoing; E tip (0.5) and W tip (0.5) incoming-only mixed (see column)
Fork, Join (hexagon) 2 slots per N face (0.25, 0.75); 2 slots per S face (0.25, 0.75); E/W closed Either
Dummy point — 1 slot on every face at 0.5 Either

API surface

// Fetch all declared slots for a kind.
IReadOnlyList<ElkNodeSlot> ElkNodeSlotLattice.GetSlots(string kind);

// Resolve a slot to an absolute (x, y) point on a positioned node.
ElkPoint ElkNodeSlotLattice.ResolveSlotPoint(
    ElkPositionedNode node,
    ElkNodeSlot slot);

// Pick the best slot for an edge given its direction toward the other
// endpoint. Respects direction restrictions (IncomingOnly vs OutgoingOnly).
ElkNodeSlot? ElkNodeSlotLattice.ResolveSlotForEdge(
    ElkPositionedNode node,
    ElkPoint edgeDirection,
    bool isIncoming);

Consumer contract

  • ElkOrthogonalRouter.TryRoute uses ResolveSlotForEdge to pick exit/entry slots on the source and target's primary-end / primary-start faces.
  • When the lattice returns no admissible slot, callers fall back to the legacy face-centre heuristic.
  • Multiple edges landing on the same slot are expected: the router's per-group spread heuristic spaces them apart.

Design notes

  • Slot sets are the minimum viable count for the current workflow set. Denser faces can be added without breaking the contract (the lattice API is additive).
  • Direction restrictions on Decision tips encode the flow-control semantics of diamond gateways: the south tip is the sole outgoing anchor so the downstream branches radiate from a single point.
  • Fork / Join use 2-slot N/S faces because parallel/merge branches are inherently binary-clustered in Stella Ops workflow semantics.