pub struct ProcStatus {
pub state: ProcState,
pub ready: Option<bool>,
pub pid: Option<u32>,
pub uptime_secs: Option<u64>,
pub version: Option<String>,
pub detail: Option<String>,
pub endpoints: BTreeMap<String, String>,
pub metrics: BTreeMap<String, f64>,
}Expand description
A workload’s self-description. Only Self::state is required.
@yah:relay(R866, “Deployed-credential drift: apply-time value fingerprints reported back over the ProcStatus rail”)
@yah:at(2026-09-05T08:47:33Z)
@yah:status(open)
@yah:assignee(agent:bundle-anthropic-ashguard)
@arch:see(.yah/docs/working/W337-credential-health-and-rotation.md)
@yah:depends_on(R556-F6)
@yah:next(“THE PROBLEM. A credential used by a cloud workload is injected at yah cloud apply time from the local vault via resolve_serve_env (grep fn resolve_serve_env in app/yah/cli/src/cloud.rs — :7979 on 2026-09-05, but it has moved three times). That splits rot in two: (a) the vault copy rotted, which a local yah keys doctor probe already catches, and (b) THE DEPLOYED COPY DRIFTED FROM THE VAULT COPY — someone rotated the vault and never re-applied, or applied and the workload never restarted. In case (b) the vault probe is GREEN and the service is DOWN. This relay is (b) and only (b).”)
@yah:next(“SCOPE THE DELTA. The apply-time PRESENCE half is already built and must NOT be rebuilt: resolve_serve_env is FATAL on an empty resolution, with an error naming the slot and the yah keys set fix, so a serve process is never forked with a blank credential. What it cannot catch is a value that resolves fine and is DEAD, or one that DRIFTED after apply.”)
@yah:next(“SHAPE. At apply time store a SALTED hash of each injected value; have the workload report the hash of what it is actually running with; compare. That detects (b) without moving a secret anywhere. HARD CONSTRAINT: no secret value, and no secret LENGTH, may appear in the fingerprint path, in the reported status document, or in any log.”)
@yah:next(“USE THE EXISTING ProcStatus RAIL — do not build a bespoke per-workload health endpoint. Right here in this file: workloads publish a ProcStatus self-description document (:155), fetched by fetch_status (:234) over a ControlEndpoint that is Socket(PathBuf) OR Http(String) (:211, doc: \"for a process that already serves HTTP, including every cloud-tier workload\"), at conventional path DEFAULT_HTTP_PATH = \"/_yah/status\" (:111, overridable per-workload via [process.control] http_path). Producer side is a published two-line helper crate, oss/kamaji/crates/procctl (serve_env / serve_at / ControlServer, lib.rs:78). Riding this rail makes the feature work for EVERY procctl-conforming workload rather than mesofact alone.”)
@yah:next(“THE ONE GAP, and it is the first edit: ProcStatus has NO field a hex fingerprint fits. metrics is BTreeMap<String, f64> (numeric only), endpoints is addresses, detail is documented as ONE HUMAN LINE. Add a string-valued field — env_fingerprint, or a general free-form labels: BTreeMap<String, String>; THAT CHOICE IS A NAMING CALL, make it deliberately — carrying #[serde(default)] so workloads built before this change keep deserializing.”)
@yah:next(“SURFACE IT IN THE EXISTING TABLE, not a new command. yah cloud mirror-status already does declared-vs-observed comparison for replicas and already has a –drift filter: handle_mirror_status at app/yah/cli/src/cloud.rs:11862, row type MirrorStatusRow at :6774, –drift applied at :11929. Add a row type; do not add a command. (Older prose cites :9684 for this — that was never a mirror-status line.)”)
@yah:gotcha(“THERE IS NO LIVE CONSUMER YET, AND THAT GATES THIS RELAY — it is why depends_on(R556-F6) is set. Measured 2026-09-05: ZERO uncommented vault: declarations in any tracked TOML. All four hits are commented out — .yah/services/yah-analytics/mirrors/cloud.toml:616-618 (the #! cut-over block) and .yah/qed/gha-actions.toml:25 — so today there is nothing for an apply-time hash to hash and the reporting half would be dead code on both ends. Step (4) of R556-F6’s cut-over uncomments that block and creates the first live declaration. Confirm the field shape against what R556-T12 actually SHIPPED, not against the comment: the comment predates it and names cloudflare-r2-endpoint, a slot the vault does not have.”)
@yah:gotcha(“RIPGREP TRAP that has already cost two sessions a false reading: rg skips hidden directories by default, and every vault: declaration in this tree lives under .yah/. So rg '=\\s*\"vault:\"' --glob '*.toml' WITHOUT –hidden returns clean over a tree that is not clean. Always pass –hidden when re-measuring the trigger.”)
@yah:gotcha(“BLAST RADIUS IS WIDER THAN IT LOOKS — weigh it before starting. This touches oss/yubaba AND oss/kamaji, which are INDEPENDENT Cargo workspaces excluded from the yah root workspace (so no workspace = true inheritance from the root inside them), and procctl is a crates.io PUBLISH surface, meaning a ProcStatus field change is a wire-format change for external consumers (noisetable, in the entambi repo, is named as one in this file’s own R-notes). #[serde(default)] on the new field is not optional politeness; it is what keeps already-deployed workloads deserializing.”)
@yah:gotcha(“HISTORY: this was R856-F8, deferred unbuilt across three sessions (2026-09-03/04/05) because the trigger never fired. Operator decision 2026-09-05 re-filed it here as its own relay rather than holding R856 open — R856’s remaining work is vault-local and finished, while this spans two oss workspaces and a publish surface. R856-F8 is archived; its design record is W337 §5.”)
@yah:verify(“Rotating a vault slot without re-applying shows as drift in yah cloud mirror-status --drift, while the local yah keys doctor probe still reports Valid on the same slot”)
@yah:verify(“No secret value and no secret LENGTH appears in the fingerprint path, in the reported ProcStatus document, or in any log”)
@yah:verify(“A workload built before the new ProcStatus field still deserializes (pin it with a test that feeds the pre-change JSON through serde), so a partial fleet roll cannot break status reporting”)
@yah:verify(“cargo test –manifest-path oss/yubaba/Cargo.toml -p yah-cloud proc_control # the rail’s existing serde round-trip tests still pass (see proc_control.rs:493)”)
Fields§
§state: ProcStateLifecycle state, in kamaji’s vocabulary.
ready: Option<bool>Redundant convenience mirror of state == running, accepted from
producers that emit it. Never trusted over state — a document
claiming {"state":"starting","ready":true} is a producer bug, and
believing the optimistic half of it is how a supervisor reports a
half-booted process as up.
pid: Option<u32>Process id, when the process knows and cares to say.
uptime_secs: Option<u64>Seconds since the process considered itself started.
version: Option<String>Build/version string, for an operator staring at two of these.
detail: Option<String>One human line elaborating on state — “replaying WAL 3/7”,
“waiting for GPU”. This is the field that replaces log-grepping.
endpoints: BTreeMap<String, String>Named addresses the process serves — {"http":"http://127.0.0.1:4325"}.
A portless process may legitimately name a non-URL surface here.
metrics: BTreeMap<String, f64>Numeric gauges the process wants surfaced. Free-form on purpose: this is a status channel, not a metrics pipeline.
Implementations§
Source§impl ProcStatus
impl ProcStatus
Trait Implementations§
Source§impl Clone for ProcStatus
impl Clone for ProcStatus
Source§fn clone(&self) -> ProcStatus
fn clone(&self) -> ProcStatus
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 ProcStatus
impl Debug for ProcStatus
Source§impl<'de> Deserialize<'de> for ProcStatus
impl<'de> Deserialize<'de> for ProcStatus
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 PartialEq for ProcStatus
impl PartialEq for ProcStatus
Source§impl Serialize for ProcStatus
impl Serialize for ProcStatus
impl StructuralPartialEq for ProcStatus
Auto Trait Implementations§
impl Freeze for ProcStatus
impl RefUnwindSafe for ProcStatus
impl Send for ProcStatus
impl Sync for ProcStatus
impl Unpin for ProcStatus
impl UnsafeUnpin for ProcStatus
impl UnwindSafe for ProcStatus
Blanket Implementations§
impl<T> Allocation for T
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> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> Fruit for T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
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 more