Documentation
¶
Overview ¶
Package fingerprint extracts a structured cluster identity from a snapshot's collector measurements and compares it against a recipe's criteria.
A Fingerprint records the cluster-identity dimensions used to bind a snapshot to a recipe — service (eks/gke/aks/oke/kind/lke/bcm), accelerator (h100/h200/gb200/b200/a100/l40/rtx-pro-6000), OS (ubuntu/rhel/cos/amazonlinux/talos plus raw VERSION_ID), Kubernetes server version, region, total node count, and GPU node count. Each dimension records the resolved value plus an optional source string identifying which collector signal produced it (e.g., "k8s.node.provider", "gpu.hardware.model").
FromMeasurements builds a Fingerprint from a snapshot's measurement slice without taking a dependency on pkg/snapshotter, so the snapshotter can hold a *Fingerprint field and the verifier and bundler packages can consume the type without pulling collectors.
Fingerprint.Match compares a Fingerprint against a recipe.Criteria and returns a structured per-dimension diff with three states: matched, mismatched, or unknown. "Unknown" covers criteria fields the cluster cannot reveal (intent, platform); the overall MatchResult.Matched flag is true so long as no dimension is mismatched, leaving unknown dimensions for human review.
This package is the foundation for ADR-007 verifiable recipe test evidence. The fingerprint and per-dimension diff are recorded in the evidence bundle's predicate body so a maintainer reviewing a contribution can confirm the cluster the recipe was tested on actually matched the recipe's declared criteria.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ParseGPUSKU ¶
ParseGPUSKU normalizes a raw nvidia-smi ProductName (e.g. "NVIDIA H100 80GB HBM3") or NFD topology label (e.g. "NVIDIA-L40S") to the matching recipe.CriteriaAccelerator enum value (e.g. "h100"). The model is upper-cased and split into tokens on whitespace and hyphens, then matched against gpuSKURegistry on contiguous token sequences. Returns "" when the model matches no known SKU; callers treat the empty string as "fingerprint did not detect this dimension."
Types ¶
type Dimension ¶
type Dimension struct {
// Value is the resolved dimension value, normalized to the
// matching recipe.Criteria enum where applicable (e.g. "eks",
// "h100", "ubuntu"). Empty string means the dimension was not
// captured.
Value string `json:"value" yaml:"value"`
// Source names the collector signal that produced Value, for
// audit and debugging (e.g. "k8s.node.provider"). Empty when the
// dimension was not captured.
Source string `json:"source,omitempty" yaml:"source,omitempty"`
// Note carries a short audit hint when Value is empty for a
// reason other than missing data — e.g. "multi-region" for a
// region dimension that detected disagreeing labels across
// nodes. The verifier surfaces this in its Markdown rendering so
// "value not captured" and "value deliberately not collapsed"
// stay distinguishable.
Note string `json:"note,omitempty" yaml:"note,omitempty"`
}
Dimension is a single fingerprint dimension. Forward-compatible with ADR-007 V2 extensions: signals[] and confidence are reserved for the follow-on per-signal provenance work and would be added as additional optional fields without a schema break.
type DimensionDiff ¶
type DimensionDiff struct {
// Dimension is the typed dimension name (service, accelerator,
// etc.). Lets consumers filter or look up by name without magic
// strings.
Dimension DimensionName `json:"dimension" yaml:"dimension"`
// RecipeRequires is the criteria value the recipe declares, or
// empty / "any" when the recipe is generic in this dimension.
RecipeRequires string `json:"recipeRequires,omitempty" yaml:"recipeRequires,omitempty"`
// FingerprintProvides is the value the fingerprint resolved for
// this dimension. Empty when the dimension was not captured.
FingerprintProvides string `json:"fingerprintProvides,omitempty" yaml:"fingerprintProvides,omitempty"`
// Match is the three-way outcome.
Match DimensionMatch `json:"match" yaml:"match"`
}
DimensionDiff is a single criteria dimension's comparison outcome.
type DimensionMatch ¶
type DimensionMatch string
DimensionMatch is the three-way per-dimension outcome of Match.
"unknown" means the criteria specifies a value but the fingerprint could not determine it (e.g., recipe intent or platform are recipe-author choices not detectable from cluster state). Unknowns surface in MatchResult.PerDimension for human review without counting as a contradiction in the overall MatchResult.Matched flag.
const ( DimensionMatched DimensionMatch = "matched" DimensionMismatched DimensionMatch = "mismatched" DimensionUnknown DimensionMatch = "unknown" )
type DimensionName ¶
type DimensionName string
DimensionName is a typed criteria dimension key.
const ( DimensionService DimensionName = "service" DimensionAccelerator DimensionName = "accelerator" DimensionOS DimensionName = "os" DimensionIntent DimensionName = "intent" DimensionPlatform DimensionName = "platform" DimensionNodes DimensionName = "nodes" )
DimensionName enumerated values — the criteria dimensions Fingerprint.Match compares. Order here defines the order MatchResult.PerDimension entries are emitted.
type Fingerprint ¶
type Fingerprint struct {
// Service is the Kubernetes service / cloud platform
// (eks, gke, aks, oke, kind, lke, bcm). Sourced from
// k8s.node.provider (parsed from spec.providerID).
Service Dimension `json:"service" yaml:"service"`
// Accelerator is the recipe-supported GPU SKU used for criteria
// matching (h100, h200, gb200, b200, a100, l40, rtx-pro-6000). It is
// intentionally limited to the pkg/recipe accelerator enum: a GPU that
// AICR does not have recipe coverage for is left empty here (see
// GPUModel for the descriptive identity). Sourced from the GFD
// nvidia.com/gpu.product label or the PCI device ID.
Accelerator Dimension `json:"accelerator" yaml:"accelerator"`
// GPUModel is the descriptive accelerator SKU detected on the node
// (e.g. "l40s", "t4", "a800"), independent of whether AICR supports it
// for recipe matching. It is informational only — Match and ToCriteria
// never read it — and exists so the snapshot records the real hardware
// even for SKUs outside the Accelerator enum. Sourced from the PCI
// device ID via the GPU "hardware" subtype.
GPUModel Dimension `json:"gpuModel,omitempty" yaml:"gpuModel,omitempty"`
// OS is the worker node operating system, with the raw
// VERSION_ID retained for audit. Sourced from
// os.release.{ID,VERSION_ID}.
OS OSDimension `json:"os" yaml:"os"`
// K8sVersion is the Kubernetes server version with the leading
// "v" stripped (e.g., "1.33.4"). Sourced from k8s.server.version.
K8sVersion Dimension `json:"k8sVersion" yaml:"k8sVersion"`
// Region is the cluster region (e.g., "us-west-2"). Sourced from
// the topology.kubernetes.io/region node label aggregated by the
// topology collector. Omitted when the cluster has no consistent
// region label or spans multiple regions.
Region Dimension `json:"region,omitempty" yaml:"region,omitempty"`
// NodeCount is the total number of cluster nodes including
// control-plane and worker nodes. Sourced from
// nodeTopology.summary.node-count. For "how many GPU workers"
// see GPUNodeCount.
NodeCount IntDimension `json:"nodeCount" yaml:"nodeCount"`
// GPUNodeCount is the number of nodes carrying the GPU operator's
// nvidia.com/gpu.product label (the canonical "this node has a
// GPU" signal). Zero on clusters without the GPU operator
// installed. Sourced from the topology label subtype.
GPUNodeCount IntDimension `json:"gpuNodeCount" yaml:"gpuNodeCount"`
}
Fingerprint is the structured cluster identity at snapshot time. Per ADR-007 it is the input the verifier uses to confirm a recipe's criteria matched the cluster on which validate ran.
func FromMeasurements ¶
func FromMeasurements(measurements []*measurement.Measurement) *Fingerprint
FromMeasurements builds a Fingerprint from a snapshot's measurement slice. Dimensions whose source signal is missing keep their zero value (empty string for Dimension/OSDimension, 0 for IntDimension); callers compare those against criteria using Match, which treats missing fingerprint values as "unknown" rather than "mismatched."
func (*Fingerprint) Match ¶
func (f *Fingerprint) Match(c *recipe.Criteria) MatchResult
Match compares the fingerprint against a recipe's criteria and returns a per-dimension diff plus an overall Matched flag.
Per-dimension semantics:
- Recipe value is empty / "any" → matched (recipe is generic).
- Recipe value is specific, fingerprint did not capture → unknown (the fingerprint cannot prove a match, but cannot disprove one either).
- Recipe value is specific, fingerprint captured the same value → matched.
- Recipe value is specific, fingerprint captured a different value → mismatched.
Overall Matched is true when no dimension is mismatched. Unknown dimensions surface in PerDimension for human review without flipping the overall outcome.
Criteria fields that the cluster cannot reveal — Intent and Platform — are reported as unknown when the recipe declares a specific value, and matched when the recipe is generic. The fingerprint deliberately does not attempt to fabricate them.
A nil criteria pointer is treated as a fully-generic recipe: every dimension is matched and the overall result is matched=true.
func (*Fingerprint) ToCriteria ¶
func (f *Fingerprint) ToCriteria(reg *recipe.CriteriaRegistry) *recipe.Criteria
ToCriteria projects the fingerprint into a recipe.Criteria, resolving each enum value against reg so non-OSS values contributed by a `--data` overlay are honored. A nil reg falls back to a fresh ephemeral registry (only the hardcoded OSS fast-path values will validate); callers that need overlay values to flow through should pass the registry bound to their Client (via Client.CriteriaRegistry).
Intent and Platform are recipe-author choices the cluster cannot reveal, so they always come back as "any"; callers wanting to drive recipe selection by intent or platform must layer that on top of ToCriteria from the CLI flag side.
type IntDimension ¶
type IntDimension struct {
// Value is the resolved integer value. Zero indicates the
// dimension was not captured.
Value int `json:"value" yaml:"value"`
// Source names the collector signal that produced Value.
Source string `json:"source,omitempty" yaml:"source,omitempty"`
}
IntDimension is a fingerprint dimension whose resolved value is an integer (e.g., node count).
type MatchResult ¶
type MatchResult struct {
Matched bool `json:"matched" yaml:"matched"`
PerDimension []DimensionDiff `json:"perDimension" yaml:"perDimension"`
}
MatchResult is the structured outcome of Fingerprint.Match.
Matched is true when no dimension is Mismatched. Unknown dimensions (e.g., criteria.intent / criteria.platform when the fingerprint does not capture them) do not flip Matched to false: they surface in PerDimension for the maintainer to evaluate, but the fingerprint itself cannot disprove a match it does not capture.
PerDimension is an ordered slice so iteration is deterministic and serialization is stable. Use Find for lookup by name.
func (MatchResult) Find ¶
func (r MatchResult) Find(name DimensionName) (DimensionDiff, bool)
Find returns the diff for the named dimension. The second return is false when no entry exists for that dimension (impossible today; future evolutions might add or omit dimensions).
type OSDimension ¶
type OSDimension struct {
Value string `json:"value" yaml:"value"`
Version string `json:"version,omitempty" yaml:"version,omitempty"`
Source string `json:"source,omitempty" yaml:"source,omitempty"`
}
OSDimension extends Dimension with the raw OS version string. Value is the criteria-aligned OS kind (ubuntu, rhel, cos, amazonlinux, talos); Version carries the unmodified VERSION_ID from /etc/os-release for audit purposes (recipe.Criteria has no version field, so Version does not participate in Match).