Every release since v2 has been additive at the call site. The notes below cover what changes if you assert exact object shapes.
For the full per-release record, see the changelog.
No existing admission call-site changes are required. Successful admission
results, tokens, run contexts, and admit / release events gain immutable
resources. Stats gain active-LLM and borrowed-concurrency-abandon counters
(including a borrowedConcurrencyAbandonedByCause split), and LLMEventType
gains borrowedConcurrencyAbandon; exhaustive shape and event switches should
account for these additive fields. Listener and
LLMBorrowedConcurrencyAbandonCause are new entry-point type exports.
Use borrowedConcurrencyDeadlineMs only for a wall-clock lease on class
concurrency borrowed from shared capacity. Expiry now has its own
LLMBorrowedConcurrencyDeadlineError; it is not an admission rejection. The
local slot returns immediately, while the token hold and drain() remain live
until the callback settles. This does not prove remote provider reclamation.
That split lifecycle is observable in shutdown behavior. After
abandonBorrowedConcurrency(), drain() without timeoutMs waits for the
matching token settlement even though base concurrency is already available.
A manual acquire() caller must still call release(); omitting it leaves an
unbounded drain pending. A bounded drain instead resolves with
drained: false and the unsettled admission in inFlight. Existing callers
that do not use the new abandonment API retain their previous lifecycle.
No admission call-site changes are required. Instrumented admit and
admission-decision reject events gain two optional integer nanosecond fields:
decisionDurationNs and queueWaitNs. Code that asserts exact event object
shapes should allow these additive fields.
queueWaitNs is exactly 0 for precheck rejection and otherwise measures the
complete awaited concurrency-acquire span. decisionDurationNs excludes that
await. Deduplication-follower rejections and observe-mode bypasses are not
admission decisions and therefore do not carry admission timing.
No admission call-site changes are required. Configure protectedConcurrent
and/or protectedInFlightTokens only when a class needs a strict local
guarantee. The sum of floors must fit inside the corresponding global limit.
Floors are not automatically lent while idle; a control plane must adjust them
with applyLimits() to implement demand-aware lending.
stats().admissionClasses gains shared, protected/borrowed usage fields,
and cumulative borrowing counters. Rejection capacity details may now use
constraint: 'admission_class_protection' and include sharedCapacity. Code
that exhaustively asserts these additive object or union shapes must be
updated. Omitting both floor fields preserves v3.14 admission behavior.
No existing call-site changes are required. admissionClasses is opt-in and
all new lifecycle fields are optional when the feature is disabled. Code that
exhaustively asserts event, stats, limit-snapshot, token, run-context, usage,
or rejection-detail shapes should account for the additive class fields.
Gateways should pass only trusted, bounded policy-class IDs. Admission class
automatically partitions in-flight deduplication, while dedupScope remains
required for tenant-level isolation inside a shared class.
No code changes are required. Update the dependency to v3.11.1 and regenerate your lockfile. The patch keeps the v3.11 API unchanged, replaces the conflicting v3.11.0 package artifact, updates the development dependency lockfile, and corrects the strict capacity-snapshot test expectation.
No admission call-site changes are required. Successful acquire results,
admission tokens, run contexts, usage reports, lifecycle events, and rejection
capacity details gain limitRevision. Code that uses exact deep equality on
these objects must add the field. Gateways should read the captured revision
from the result, token, context, event, or rejection detail instead of calling
limits() after the decision.
Existing admission calls require no changes. stats() gains a limits block,
LLMEventType gains "reconfigure", and setBudget() now advances the local
revision. Code that exhaustively enumerates event types should add the new
case. Control-plane integrations should move from setBudget() to complete
applyLimits() snapshots.
No call-site changes are required. admit and release event payloads gained
additional fields, and usage is a new event type. Code that exhaustively
enumerates LLMEventType should add the new usage case.
Update stats access from top-level fields to the bulkhead block:
const s = bulkhead.stats();
// v2
s.inFlight;
s.pending;
// v3
s.bulkhead.inFlight;
s.bulkhead.pending;
LLM-layer counters are now available separately:
const s = bulkhead.stats();
s.llm.admitted;
s.llm.rejected;
s.llm.rejectedByReason?.budget_limit;
See the changelog for the v2 migration guide.