Affinity

@Serializable
sealed interface Affinity

A location-eligibility predicate — the "can I execute here" question, riding the opaque task envelope (H8, design §14.6, Model A).

An Affinity is a small serializable expression over the capability tokens a peer advertises in its CapSet. It rides the TaskDescriptor the same way H6's Lane does: warp core carries it and evaluates it with matches, but assigns the tokens no meaning and depends on no module that interprets them. Placement then consistent-hashes over the eligible subset of the roster — the peers whose advertised CapSet satisfies this predicate — rather than the whole roster (see TaskRing.owner). Every peer computes the same eligible set from the same convergent capability view, so determinism holds for the same reason the ring does.

Eligibility is independent of entitlement: this type lives in :kuilt-warp and names no :kuilt-heddle type. It composes with a lane (a task may carry both an Affinity and a Lane) but does not live inside one — eligibility answers where, a lane answers how much.

Because it is serializable it cannot capture a Kotlin lambda; instead it is a closed algebra of leaf predicates (Has, Attr) and combinators (And, Or, Not), with Anywhere as the no-requirement default. Build predicates fluently:

val where = Affinity.has("GPU") and Affinity.attr("region", "us-east")

Samples

// "must run on a GPU node in us-east" — a composable predicate, not a lambda (it rides the wire).
val where = Affinity.has("GPU") and Affinity.attr("region", "us-east")

val gpuUsEast = CapSet(tokens = setOf("GPU"), attributes = mapOf("region" to "us-east"))
val cpuUsWest = CapSet(tokens = setOf("CPU"), attributes = mapOf("region" to "us-west"))
check(where.matches(gpuUsEast))       // eligible
check(!where.matches(cpuUsWest))      // not eligible
check(Affinity.Anywhere.matches(cpuUsWest)) // the default requires nothing

// Tag a task with the requirement; placement then hashes over only the eligible peers.
val task = TaskDescriptor(OpId("train"), byteArrayOf(1, 2, 3)).where(where)
check(task.affinity == where)

Inheritors

Types

Link copied to clipboard
@Serializable
data class And(val terms: List<Affinity>) : Affinity

Satisfied when every term is satisfied. An empty terms is vacuously true.

Link copied to clipboard
@Serializable
data object Anywhere : Affinity

The no-requirement default: every peer is eligible, so placement is over the whole roster — warp's pre-H8 behaviour, bit-for-bit. This is the TaskDescriptor.affinity default; a descriptor that never sets an affinity is byte-for-byte identical on the wire to a pre-H8 descriptor (CBOR omits a field at its default).

Link copied to clipboard
@Serializable
data class Attr(val key: String, val value: String) : Affinity

Satisfied when the peer advertises keyed capability key with exactly value.

Link copied to clipboard
object Companion
Link copied to clipboard
@Serializable
data class Has(val token: String) : Affinity

Satisfied when the peer advertises boolean capability token (caps.has(token)).

Link copied to clipboard
@Serializable
data class Not(val term: Affinity) : Affinity

Satisfied when term is not satisfied.

Link copied to clipboard
@Serializable
data class Or(val terms: List<Affinity>) : Affinity

Satisfied when any term is satisfied. An empty terms is vacuously false.

Functions

Link copied to clipboard
infix fun Affinity.and(other: Affinity): Affinity

Conjunction: a and b is satisfied when both this and other are.

Link copied to clipboard
abstract fun matches(caps: CapSet): Boolean

Whether a peer advertising caps satisfies this predicate. Pure and deterministic.

Link copied to clipboard
infix fun Affinity.or(other: Affinity): Affinity

Disjunction: a or b is satisfied when either this or other is.