v0.15.4 Migration Guide

Use Keyed Concurrency Struct LiteralsSection anchor link

sparkwing.ConcurrencyLimit and client.TriggerPlanAdmission gained host-admission fields. Go permits unkeyed struct literals for exported structs, so callers using positional literals must switch to keyed literals.

Before:

group := sparkwing.NewConcurrencyGroup("build", sparkwing.ConcurrencyLimit{4, sparkwing.ScopeBox, sparkwing.Queue, 0, 0})

After:

group := sparkwing.NewConcurrencyGroup("build", sparkwing.ConcurrencyLimit{
    Capacity: 4,
    Scope:    sparkwing.ScopeBox,
    OnLimit:  sparkwing.Queue,
})

Do the same for client.TriggerPlanAdmission if you construct trigger requests directly. Most callers never construct that type by hand; spawned child runs populate it from Sparkwing-managed trigger environment.

Compose Plan-Level BudgetsSection anchor link

Repeated plan.Concurrency(...) calls now add independent whole-run gates instead of replacing the prior gate. Use separate groups for separate budgets:

land := sparkwing.NewConcurrencyGroup("land", sparkwing.ConcurrencyLimit{Capacity: 1})
memory := sparkwing.NewConcurrencyGroup("memory-gb", sparkwing.ConcurrencyLimit{
    Capacity: 64,
    Scope:    sparkwing.ScopeBox,
})

plan.Concurrency(land)
plan.Concurrency(memory, 8)

Callers that intentionally relied on replacement semantics must clear the existing gates before setting the replacement:

plan.Concurrency(nil)
plan.Concurrency(replacement)