Spot Schedule Provider Contract¶
Status: Stable contract, Accepted in ADR 0006. The
CapitalMarketsSchedulereference provider ships in-repo (see the provider guide). This page is the authoritative specification a provider author implements against — implement thestatuscontract below and 5-Spot will consume your provider.
A spot-schedule provider is any Kubernetes custom resource in the
spotschedules.5spot.finos.org API group that tells 5-Spot whether a
ScheduledMachine should be active (its machine should exist) or
inactive (its machine should be torn down) right now.
5-Spot owns where the decision lives (status.active); the provider owns
how the decision is computed — an exchange calendar, a PromQL expression, a
change-freeze window, or a plain manual toggle. 5-Spot never reads the
provider spec and never writes the provider object.
This is the same duck-typed contract pattern Cluster API uses for
infrastructureRef / bootstrap.configRef.
Referencing a provider¶
Every ScheduledMachine references exactly one provider object in its own
namespace via the required spec.schedule:
apiVersion: 5spot.finos.org/v1beta1
kind: ScheduledMachine
metadata:
name: trading-floor-rack-7
namespace: capital-markets
spec:
# spec.schedule is a required provider reference.
schedule:
apiVersion: spotschedules.5spot.finos.org/v1alpha1
kind: CapitalMarketsSchedule
name: nyse-equities-session # must live in namespace: capital-markets
apiVersion— the group must bespotschedules.5spot.finos.org(CEL-enforced at admission; any served version is accepted, see Versioning). Other groups are rejected.kind— the provider kind (e.g.CapitalMarketsSchedule).name— the provider object, same namespace as theScheduledMachine. Cross-namespace references are not supported.
The status contract a provider must satisfy¶
5-Spot reads only the provider's status:
status field |
Required | Type | Meaning |
|---|---|---|---|
active |
yes | bool | The decision. true ⇒ the referencing machine should be up; false ⇒ it should be down. |
conditions[type=Ready] |
recommended | condition | Provider health. A present Ready whose status is not True ⇒ 5-Spot treats the reference as unresolved, not inactive (see Unresolved behavior). An absent Ready ⇒ status.active is taken as authoritative. Set Ready=True when your active is current, and Ready=False to say "don't trust my active right now" without flapping the machine. |
observedGeneration |
recommended | int64 | The metadata.generation the status reflects; lets 5-Spot detect stale status. |
lastTransitionTime |
recommended | RFC 3339 string | When active last flipped; used for observability and flap detection. |
A minimal conformant status:
status:
active: true
observedGeneration: 4
lastTransitionTime: "2026-06-13T13:30:00Z"
conditions:
- type: Ready
status: "True"
reason: SessionOpen
message: "NYSE equities regular session open"
lastTransitionTime: "2026-06-13T13:30:00Z"
observedGeneration: 4
5-Spot keys off only status.active and the Ready condition's status
field ("True" / "False" / "Unknown"). The condition reason / message
are free-form and surfaced for observability; pick any CamelCase reason. The
observedGeneration is recommended for your own staleness detection but 5-Spot
does not currently reject stale status on it.
The provider verdict, spec.enabled, and killSwitch¶
There is no composition: the single referenced provider's status.active is
the activation decision. Two switches sit above it. spec.enabled (default
true) is the administrative master switch — setting it false holds the
machine in the Disabled lifecycle phase regardless of what the provider says.
spec.killSwitch is a terminal teardown and always wins. Precedence, highest
first:
Unresolved behavior¶
A reference is Unresolved when the provider CRD is not installed, the named
object is absent, it exposes no status.active, or it carries a Ready
condition whose status is not True (an absent Ready is not
unresolved — active is then authoritative). On Unresolved, 5-Spot:
- sets a
SpotScheduleResolved=Falsecondition on theScheduledMachinewith a precise reason (ProviderCRDNotInstalled,ProviderNotFound,StatusActiveMissing,ProviderNotReady), - emits
fivespot_spot_schedule_resolution_errors_total, and - holds the last known resolved state — a running machine is not torn down because its provider briefly went unreadable. If the reference has never resolved, the fail-safe default is inactive.
A provider that misbehaves (or is compromised) can only flap the machines that
reference it — the same blast radius as editing spec.enabled —
and only within its own namespace. See the
threat model.
Versioning¶
Per ADR 0007, provider CRDs are
multi-version-capable: a CRD may serve several versions
(v1alpha1, later v1beta1/v1) with exactly one storage version and
conversion.strategy: None. 5-Spot resolves providers by group + kind, not
a pinned apiVersion, so any served version of a referenced provider works.
Contract evolution is additive-only while conversion is None: new
optional status fields may be added; an existing status field is never
renamed, retyped, or removed without a superseding ADR (which would introduce a
conversion webhook). Providers should therefore tolerate unknown fields and not
rely on 5-Spot reading anything beyond the table above.
Reference providers¶
The default, first-party provider is TimeBasedSpotSchedule — the reified
former inline schedule, computing status.active from daysOfWeek /
hoursOfDay / timezone windows. It is the provider most ScheduledMachines
reference. See the
TimeBasedSpotSchedule provider guide.
The in-repo CapitalMarketsSchedule reference implementation reconciles a
declarative exchange calendar (sessions, statutory holidays, early closes,
timezone) into status.active, requeuing at the next session/holiday boundary
(event-driven — a single timed requeue at the calendar transition, not a poll
loop). See the
CapitalMarketsSchedule provider guide
for install + authoring, and
examples/capitalmarketsschedule.yaml.
Implementing your own provider¶
The entire contract is status.active plus an optional Ready condition — any
namespaced CRD in the spotschedules.5spot.finos.org group whose controller
writes that status is a valid provider. For a complete, copy-pasteable
walkthrough (CRD, controller, RBAC, deploy, reference, verify) building a minimal
ManualSchedule toggle, see the
Create Your Own Provider guide. The
CapitalMarketsSchedule
controller is the same shape with a calendar instead of a toggle.
See also¶
- Create Your Own Provider — build a provider step by step
- TimeBasedSpotSchedule provider guide — the default first-party provider
- CapitalMarketsSchedule provider guide — the reference provider
- ADR 0006 — Pluggable spot-schedule provider contract
- ADR 0007 — CRD multi-version + conversion
ScheduledMachineAPI reference- Threat model