pub struct PoolStatus {
pub phase: PoolPhase,
pub phase_since: Option<DateTime<Utc>>,
pub ready_count: u32,
pub allocated_count: u32,
pub spawning_count: u32,
pub returning_count: u32,
pub members: Vec<PoolMember>,
pub message: Option<String>,
pub conditions: Vec<PoolCondition>,
}Expand description
EphemeralPool.status — observed pool population state.
Fields§
§phase: PoolPhasePool lifecycle phase.
phase_since: Option<DateTime<Utc>>When the pool entered the current phase.
ready_count: u32Number of members currently in Free state (ready for allocation).
allocated_count: u32Number of members currently Allocated.
spawning_count: u32Number of members currently Spawning (not yet Attested).
returning_count: u32Number of members currently Returning (reset or replace
in progress).
members: Vec<PoolMember>Member ledger — one entry per pool slot.
message: Option<String>Operator-visible message (e.g., “scaled down to floor”).
conditions: Vec<PoolCondition>Standard Kubernetes Conditions.
Implementations§
Source§impl PoolStatus
impl PoolStatus
Sourcepub fn observed(
phase: PoolPhase,
members: Vec<PoolMember>,
now: DateTime<Utc>,
) -> Self
pub fn observed( phase: PoolPhase, members: Vec<PoolMember>, now: DateTime<Utc>, ) -> Self
Substrate constructor for the observed PoolStatus seed:
composes the (phase, phase_since, ready/allocated/spawning /returning counts, members, message, conditions) 9-slot record
every pool-reconciler status-patch site restated by hand pre-
lift. The four counters ride a SINGLE closed-set-driven fold
over the members list (one pass rather than four independent
filter-and-count passes); the message + conditions slots
stay at their invariant None / vec![] defaults every pre-
lift caller stamped verbatim, and phase_since is derived from
the caller-supplied now timestamp so the constructor stays
clock-injectable rather than implicitly reading wall time.
Pre-lift the 11-line
PoolStatus {
phase,
phase_since: Some(Utc::now()),
ready_count: count_state(&members, MemberState::Free),
allocated_count: count_state(&members, MemberState::Allocated),
spawning_count: count_state(&members, MemberState::Spawning),
returning_count: count_state(&members, MemberState::Returning),
members: members.clone(),
message: None,
conditions: vec![],
}incantation was hand-authored at TWO sites past the ★★ PRIME-
DIRECTIVE ≥ 2 duplication threshold in
tatara-pool-reconciler::controller_pool::reconcile_inner,
both restating the same 4-slot count fanout + defaults:
- The
desired > 0path — status patch after the convergence-action loop when the operator drives the pool through the R11 desired-count invariant. - The legacy allocation-driven path (
desired == 0) — status patch after the [crate::pool::PoolDecision] apply loop.
Both sites walked the SAME 4-slot count fanout on the SAME
four MemberState variants (Free/Allocated/Spawning/Returning)
and stamped the SAME defaults (message: None, conditions: vec![]), even though the four counters walked the members list
four independent times pre-lift when a single pass suffices.
Post-lift both callers write
PoolStatus::observed(phase, members, Utc::now()) and share
ONE substrate owner; a future counter slot (e.g., a
warming_count for a MemberState::Warming variant between
Spawning and Free) plugs into the fold at ONE match arm and
both status-patch sites inherit the new slot mechanically.
The Failed variant is deliberately absent from the fold — no
PoolStatus slot counts failed members (they surface via
pool_phase_from_members’s PoolPhase::Degraded transition
instead), and the closed-set match on
MemberState pins that a future variant which SHOULD count
toward one of the four buckets triggers the compiler’s
exhaustiveness check at this fold rather than silently sinking
into Failed’s no-op arm.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the 11-line status-seed incantation recurred at two hand-
authored sites past the ★★ PRIME-DIRECTIVE ≥ 2 duplication
trigger, and is lifted to ONE owner here). THEORY.md §II.1
invariant 5 (composition preserves proofs — the pins bind the
4-slot count fanout + the closed-set exhaustiveness on
MemberState + the invariant defaults, so a regression that
dropped a counter slot or swapped a variant surfaces at
tests::pool_status_observed_* rather than as silent operator-
facing skew between the two status-patch sites on the SAME
pool).
Sourcepub fn observed_now(phase: PoolPhase, members: Vec<PoolMember>) -> Self
pub fn observed_now(phase: PoolPhase, members: Vec<PoolMember>) -> Self
Wall-clock-anchored peer of Self::observed — the ONE
substrate owner of the 4-arg PoolStatus::observed(phase, members, Utc::now()) composition every pool-reconciler
status-patch site that reads the wall clock at tick-time
hand-authored pre-lift.
§Why it exists
Pre-lift the 4-arg PoolStatus::observed(phase, members.clone(), chrono::Utc::now()) chain was hand-authored at TWO sites past the
★★ PRIME-DIRECTIVE ≥ 2 duplication threshold in
tatara-pool-reconciler::controller_pool::reconcile_inner, each
pairing the 3-arg Self::observed composer with a
chrono::Utc::now() third argument at the status-patch stamp:
- The
desired > 0path — status patch after the convergence-action loop when the operator drives the pool through the R11 desired-count invariant. - The legacy allocation-driven path (
desired == 0) — status patch after the [crate::pool::PoolDecision] apply loop.
Both sites walked the SAME 4-arg call with the SAME
chrono::Utc::now() third argument — the wall-clock projection
had no per-callsite variation. Post-lift both consumers share ONE
substrate owner for the wall-clock-at-tick projection; a future
clock swap (a monotonic clock cross-check, a per-reconciler
injected time source, a test-only override at the production
callsite via feature flag) lands at ONE substrate function and
every pool-reconciler status-patch site inherits the upgrade
mechanically.
The 3-arg Self::observed peer stays load-bearing for test
callers — the injected-now shape is what unit tests use to
drive the clock deterministically (every
PoolStatus::observed(phase, members, seeded_now) in this
module’s own test suite reads that surface). This peer is
production-only: pinning the wall-clock at the substrate site
means no test can accidentally consume it without the
deterministic-clock injection that makes the test meaningful.
Sibling of
crate::lifetime_clock::evaluate_now on the (typed
pure-fn, wall-clock-anchored peer) axis — both primitives own
the “read the wall clock at tick-time” projection on a peer
clock-injectable primitive so the workspace’s timed-decision
family stays uniform across EphemeralLifetime TTL expiry and
PoolStatus observed-state stamp.
§Invariants
- Same shape: returns the SAME
PoolStatusthe 3-argSelf::observedreturns when passedchrono::Utc::now()as the third argument. This is a delegation, not a re-implementation. - Wall-clock read once:
Utc::now()is called exactly ONCE per invocation, at the primitive’s body, so a future consumer that chains twoobserved_nowcalls back-to-back still sees monotonicnowreads (each call reads a fresh instant, not a cached one) — matches the pre-lift shape where each of the two status-patch sites computed its ownchrono::Utc::now()at its own line.
§#[must_use]
Every consumer feeds the returned PoolStatus into
tatara_process::patch::merge_status(&pool_api, &name, &<status>)
or a peer status-patch call. Dropping the return means the
observation composed for no observable reason — the attribute
surfaces that as a warning at every call site.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the 4-arg call with chrono::Utc::now() as the third argument
recurred at 2 hand-authored sites past the ★★ PRIME-DIRECTIVE
≥ 2 duplication trigger, lifted onto the ONE workspace-wide
substrate owner here). THEORY.md §II.1 invariant 5 (composition
preserves proofs — the wall-clock projection lives at ONE site
so a future clock swap reaches both consumers through one edit).
Sourcepub fn observed_from(pool: &EphemeralPool, members: Vec<PoolMember>) -> Self
pub fn observed_from(pool: &EphemeralPool, members: Vec<PoolMember>) -> Self
Compound composer peer of Self::observed_now that derives
the PoolPhase from (pool, members) via the typed
projection crate::pool::EphemeralPool::observed_phase_from
— the ONE substrate owner of the (phase-compute + observed_now
wall-clock stamp) 2-link chain every pool-reconciler status-
patch site walked pre-lift.
§Why it exists
Pre-lift the 2-link let phase = pool_phase_from_members(&pool, &members); PoolStatus::observed_now(phase, members.clone())
chain was hand-authored at TWO sites past the ★★ PRIME-
DIRECTIVE ≥ 2 duplication threshold in
tatara-pool-reconciler::controller_pool::reconcile_inner,
both keyed against the same (pool, members) observations:
- The
desired > 0path — status patch after theapply_convergence_actionswalk when the operator drives the pool through the R11 desired-count invariant. - The legacy allocation-driven path (
desired == 0) — status patch after the [crate::pool::PoolDecision] apply loop.
Both sites walked the SAME 2-link chain — compute the observed
phase from the (tombstone-first, empty, floor, supply-vs-
desired) gate ladder against the borrowed (pool, members)
pair, then hand the produced phase + owned members clone to
the wall-clock-anchored Self::observed_now composer. Both
keyed the SAME projection through a repo-internal free
function (pool_phase_from_members) that shadowed the natural
substrate owner. Post-lift each callsite reads
PoolStatus::observed_from(&pool, members.clone()) and the
compose+dispatch sink lives at ONE substrate owner —
crate::pool::EphemeralPool::observed_phase_from +
Self::observed_now compose here, at the exact substrate
site where the pool + status types both live.
§Invariants
- Same shape: returns the SAME
PoolStatusthe 2-link chainobserved_now(pool.observed_phase_from(&members), members)returns. This is a delegation, not a re- implementation — the underlying wall-clock stamp still lives atSelf::observed_nowand the phase projection still lives atcrate::pool::EphemeralPool::observed_phase_from. - Members ride through by owned value: the members
Vecis consumed bySelf::observed_nowverbatim (no defensive.clone()at the composer boundary); the phase projection borrows the same slice through&members[..]inside the delegation so the underlying single-pass fold incrate::pool::MemberState::counts_toward_supply-family composers still gets the same borrowed view it did pre-lift. - Wall-clock read once:
Utc::now()is called exactly ONCE per invocation (inherited fromSelf::observed_now), preserving the pre-lift shape where each of the two status- patch sites computed its ownchrono::Utc::now()at its own line.
§#[must_use]
Every consumer feeds the returned PoolStatus into
tatara_process::patch::merge_status(&pool_api, &name, &<status>) or a peer status-patch call. Dropping the return
means the observation composed for no observable reason — the
attribute surfaces that as a warning at every call site.
Sibling of Self::observed_now on the (pure phase argument,
pool-derived phase) axis pair: both compose atop the 3-arg
Self::observed primitive, differing only in whether the
caller has already computed the phase (observed_now) or
hands the pool + members observations to the composer to
derive the phase in one shot (observed_from). Peer of
crate::pool::EphemeralPool::observed_phase_from on the
(pure typed projection, compound-composer) axis.
Theory anchor: THEORY.md §VI.1 (generation over composition —
the 2-link pool_phase_from_members + observed_now chain
recurred at 2 hand-authored sites past the ★★ PRIME-DIRECTIVE
≥ 2 duplication trigger, and is lifted to ONE substrate owner
here). THEORY.md §II.1 invariant 5 (composition preserves
proofs — the compound composer inherits the two component
composers’ invariants mechanically, so a regression at either
component surfaces at the pinned tests here rather than as
silent skew at either status-patch site).
Trait Implementations§
Source§impl Clone for PoolStatus
impl Clone for PoolStatus
Source§fn clone(&self) -> PoolStatus
fn clone(&self) -> PoolStatus
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PoolStatus
impl Debug for PoolStatus
Source§impl Default for PoolStatus
impl Default for PoolStatus
Source§fn default() -> PoolStatus
fn default() -> PoolStatus
Source§impl<'de> Deserialize<'de> for PoolStatus
impl<'de> Deserialize<'de> for PoolStatus
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for PoolStatus
impl JsonSchema for PoolStatus
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl Freeze for PoolStatus
impl RefUnwindSafe for PoolStatus
impl Send for PoolStatus
impl Sync for PoolStatus
impl Unpin for PoolStatus
impl UnsafeUnpin for PoolStatus
impl UnwindSafe for PoolStatus
Blanket Implementations§
impl<T> AppData for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
impl<T> AppDataResponse for Twhere
T: OptionalSend + OptionalSync + 'static + OptionalSerde,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> OptionalSend for T
impl<T> OptionalSync for T
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);