Expand description
Fleet engine for keyspace-v2 tooling (issue #15).
The shared core of zenctl and zengui: everything a bus explorer needs
that is not presentation, in five layers — see The map below. The
RFC 05 §2.1 fan-in discipline lives in exactly one place
(bus::query::fleet_get, moved verbatim from zenctl — target All,
consolidation None, attribution by the reply’s own key); the liveliness
roster, registry-slice sets, and the schema-aware decode seam build on it.
Sessions opened here are deliberately un-namespaced (RFC 09 §5): an explorer sees the wire as it really is, full keys included — that is what lets it spot a leak. Do not “fix” this by setting a namespace.
§The map
Five strata, and the arrow between them only ever points one way. A sample enters at the top and leaves at the bottom as something a frontend can draw:
bus/ holds a session → observations
model/ holds values → meaning
judge/ holds meaning → verdicts
report/ the serialized shapes every layer above hands out
tape/ traffic as a thing: captured, replayed, manufactured, timed-
bus— everything whose job needs a live session.session,query,monitor,write,serve,admin,scout,seed,blob,roster,discover,producer,body. The RFC 05 §2.1 fan-in discipline lives here exactly once, inbus::query::fleet_get(moved verbatim from zenctl — targetAll, consolidationNone, attribution by the reply’s own key), and everything in the layer that asks the fleet a question goes through it. This layer returns observations and never a verdict about one.Its event sources are
Streams (#343), not onlyrecvloops:EventStream::into_stream,SeededSubscriber(a direct impl),RosterWatch::changes, and astream()onScoutStream,Responder,MockResponderandMatchingEvents. The last four borrow rather than consume, because the&selfreceiver is what lets a query be answered while its stream is held and a scout be stopped after one; a blanketimpl Streamwould have taken&mut selfand spent that. Therecv/nextmethods stay — a loop is still the clearer shape for a drain that also selects on something else, and every consumer in this workspace does.watchdogis the one that is not aStreambut aStraw(#397): it yields transitions and returns aWatchdogSummary, with the acknowledged monitor teardown between the two. That is a shapeStreamhas no room for, and the only reason this crate speaks a second streaming vocabulary at all. -
model— everything that can do its job from values already in hand.facts,registry,project,stats,tree,skeleton,diff,decode,retain, plus the two mechanisms every long-running projection shares (bounded,examples). Nothing here takes a session, and that is load-bearing: it is what lets a frontend replay a.zrecthrough the same projections it runs live. -
judge— everything that takes a position.doctor,expect,condition,field,why,cutover,retired,budget, andjudge::commonfor the vocabulary they share. The honesty rules (RFC 13, v1.24) bite hardest here, so the layer states them once. -
report— every serde-pinned wire shape in the crate, split by domain. Its module doc carries the placement rule, which is the answer to “where does this struct go?” whenever the struct has aSerializeon it. -
tape— traffic as a thing rather than an event.record,ingest,generate,synth,bench. It sits beside the others rather than under them because it both reads from the bus and writes back to it.
Placing a new module. Ask, in order: does it need a session
(bus/), can it answer from values in hand (model/), does it say
whether something is wrong (judge/), does it turn a stream into a
recording or back (tape/)? A new serde-pinned struct is not a module
question at all — it goes to report, by the rule stated there.
What is deliberately not here: configuration. Where the operator
keeps their connection contexts is zenkey-explorer-config’s job; this
crate has no stratum for ~/.config, and forcing dirs and toml on a
library consumer so two binaries could read a TOML file was the tell.
Re-exports§
pub use bus::body::BodySource;decodepub use bus::body::PrepareMode;decodepub use bus::body::PrepareSpec;decodepub use bus::body::PreparedBody;decodepub use bus::body::encode_encoding;decodepub use bus::body::prepare_publish;decodepub use bus::body::prepare_request;decodepub use judge::condition::CondWindow;decodepub use judge::condition::Condition;decodepub use judge::condition::DoctorWatch;decodepub use judge::condition::Eval;decodepub use judge::condition::RuleState;decodepub use judge::condition::WatchdogSpec;decodepub use judge::condition::watchdog;decodepub use judge::doctor::DoctorSpec;decodepub use judge::doctor::run_doctor;decodepub use judge::expect::ExpectSpec;decodepub use judge::expect::QosCheck;decodepub use judge::expect::run_expect;decodepub use judge::field::DeclaredPaths;decodepub use judge::field::FieldObservation;decodepub use judge::field::FieldSpec;decodepub use judge::field::KeyFieldContext;decodepub use judge::field::KeyFields;decodepub use judge::field::PathStats;decodepub use judge::field::run_field;decodepub use model::decode::DEFAULT_MAX_PRODUCERS;decodepub use model::decode::DecodedSample;decodepub use model::decode::DescribedSchema;decodepub use model::decode::Rendering;decodepub use model::decode::SchemaStore;decodepub use model::decode::Sealed;decodepub use model::decode::StoreBounds;decodepub use model::decode::decode_sample;decodepub use model::decode::prewarm;decodepub use model::decode::schema_drift;decodepub use model::decode::schema_dump;decodepub use model::decode::schemas_for_type;decodepub use model::decode::totality_gaps;decodepub use tape::generate::GenPattern;decodepub use tape::generate::GenSpec;decodepub use tape::generate::MockProducer;decodepub use tape::generate::build_plan;decodepub use tape::generate::run_gen;decodepub use tape::generate::serve_describe;decodepub use tape::generate::synthetic_marker;decodepub use tape::synth::Synth;decodepub use bus::admin::AdminEntry;pub use bus::admin::admin_doc_omits_loopback;pub use bus::admin::admin_get;pub use bus::admin::admin_get_within;pub use bus::admin::declared_entities;pub use bus::admin::mesh_links;pub use bus::admin::origin_attachments;pub use bus::admin::render_dot;pub use bus::admin::routers;pub use bus::admin::state_coverage;pub use bus::admin::storages;pub use bus::admin::topology;pub use bus::blob::BlobFetchSpec;blobpub use bus::blob::FETCH_PRIORITY;blobpub use bus::blob::blob_fetch;blobpub use bus::blob::blob_probe;blobpub use bus::blob::blob_tree_index;blobpub use bus::blob::BlobTarget;pub use bus::blob::blob_list;pub use bus::blob::declared_by;pub use bus::discover::AliveToken;pub use bus::discover::discover_bases;pub use bus::monitor::EventStream;pub use bus::monitor::FleetEvent;pub use bus::monitor::Monitor;pub use bus::monitor::MonitorCore;pub use bus::monitor::MonitorSpec;pub use bus::monitor::SampleSource;pub use bus::monitor::SampleView;pub use bus::monitor::StampProvenance;pub use bus::monitor::StreamItem;pub use bus::monitor::WatchId;pub use bus::producer::BringUp;pub use bus::producer::LiveProducer;pub use bus::producer::ReservedError;pub use bus::producer::Responder;pub use bus::query::Answer;pub use bus::query::DEFAULT_MAX_REPLIES;pub use bus::query::FetchOutcome;pub use bus::query::FetchSpec;pub use bus::query::FetchedValue;pub use bus::query::FleetAnswer;pub use bus::query::GetOpts;pub use bus::query::RepeatingQuery;pub use bus::query::RepeatingRegistry;pub use bus::query::ServedSlice;pub use bus::query::StateSample;pub use bus::query::declare_repeating;pub use bus::query::declare_repeating_any;pub use bus::query::fetch_stored;pub use bus::query::fetch_value;pub use bus::query::fleet_get;pub use bus::query::fleet_registry;pub use bus::query::fleet_registry_by_origin;pub use bus::query::fleet_registry_raw;pub use bus::query::state_snapshot;pub use bus::roster::BridgeMatch;pub use bus::roster::RosterChange;pub use bus::roster::RosterWatch;pub use bus::roster::apply_token;pub use bus::roster::bridge_resolve;pub use bus::roster::node_info;pub use bus::roster::node_rows;pub use bus::roster::roster;pub use bus::roster::token_identity;pub use bus::scout::ScoutStream;pub use bus::scout::scout;pub use bus::seed::SeedItem;pub use bus::seed::SeedPolicy;pub use bus::seed::SeededSubscriber;pub use bus::seed::seed_subscribe;pub use bus::serve::MockResponder;pub use bus::serve::ServedQuery;pub use bus::serve::declare_responder;pub use bus::session::Fleet;pub use bus::session::OPEN_TIMEOUT;pub use bus::session::OpenFailure;pub use bus::session::open;pub use bus::session::open_reporting;pub use bus::session::open_reporting_within;pub use bus::session::open_with_config;pub use bus::write::CallSpec;pub use bus::write::CallTarget;pub use bus::write::MatchingEvents;pub use bus::write::Publication;pub use bus::write::RetireClass;pub use bus::write::call;pub use bus::write::check_retire;pub use bus::write::declare_publication;pub use judge::budget::BudgetObservation;pub use judge::budget::join_budget;pub use judge::common::EXPANSION_CAP;pub use judge::common::data_plane_scopes;pub use judge::common::new_prefix;pub use model::bounded::DEFAULT_MAX_KEYS;pub use model::facts::ClassKind;pub use model::facts::OriginKind;pub use model::facts::SubjectFacts;pub use model::facts::V1Facts;pub use model::registry::SliceSource;pub use model::registry::UnionOutcome;pub use model::skeleton::DeclRef;pub use model::skeleton::Evidence;pub use model::skeleton::NodeStats;pub use model::skeleton::SkeletonChunk;pub use model::skeleton::SkeletonCoverage;pub use model::skeleton::SkeletonNode;pub use model::skeleton::merge;pub use model::tree::TreeNode;pub use model::tree::TreeRow;pub use model::tree::TreeRows;pub use model::decode::OBSERVE_LIMIT;decodepub use model::decode::structural;decodepub use model::decode::structural_value;decodepub use tape::record::rfc3339_now;pub use judge::condition::SilenceEvidence;decodepub use judge::condition::TickEvidence;decodepub use judge::condition::judge_doctor_check;decodepub use judge::condition::judge_origin_down;decodepub use judge::retired::EntryEvidence;pub use error::BoxedCause;pub use error::Error;pub use error::Result;pub use error::one_line;pub use judge::field::DEFAULT_MAX_PATHS;decodepub use judge::why::is_cause;decodepub use judge::cutover::run_cutover;pub use judge::cutover::scope_note as cutover_scope_note;pub use judge::retired::run_retired;pub use judge::retired::scope_note as retired_scope_note;pub use judge::why::StoredLookup;pub use judge::why::StoredValue;pub use judge::why::WhyInputs;pub use judge::why::WhySpec;pub use judge::why::WireWatch;pub use judge::why::run_why;pub use model::diff::ByteDiff;pub use model::diff::Change;pub use model::diff::ValueDiff;pub use model::diff::byte_diff;pub use model::diff::diff as value_diff;pub use model::facts::FactsCache;pub use model::facts::KeyDescription;pub use model::facts::KeyFacts;pub use model::facts::KeyShape;pub use model::facts::Registration;pub use model::facts::describe_key;pub use model::registry::SliceSet;pub use model::retain::RetentionBudget;pub use model::retain::RetentionStats;pub use model::skeleton::MergedNode;pub use model::skeleton::NodeStatus;pub use model::skeleton::Skeleton;pub use model::stats::KeyStats;pub use model::stats::StampClass;pub use model::stats::StatsTable;pub use model::tree::KeyTreeSnapshot;pub use report::BenchReport;pub use report::CallReport;pub use report::CollapsedProducer;pub use report::Coverage;pub use report::CoverageRow;pub use report::CutoverReport;pub use report::DeclaredEntities;pub use report::DeclaredEntity;pub use report::DiscoveredBase;pub use report::DoctorReport;pub use report::DriftVerdict;pub use report::EntityKind;pub use report::ExpectReport;pub use report::Fault;pub use report::FieldReport;pub use report::Freshness;pub use report::GenPlanEntry;pub use report::GenReport;pub use report::HelloView;pub use report::Judgement;pub use report::LatencyReport;pub use report::LatencySummary;pub use report::MeshLink;pub use report::NodeInfo;pub use report::OriginAttachment;pub use report::ProducerInfo;pub use report::RecordReport;pub use report::ReplayReport;pub use report::RetiredReport;pub use report::RouterInfo;pub use report::Rung;pub use report::RungAnswer;pub use report::SampleRow;pub use report::SchemaDrift;pub use report::SchemaServer;pub use report::SeedCoverage;pub use report::StorageInfo;pub use report::TopologyEdge;pub use report::TopologyNode;pub use report::TopologyReport;pub use report::TotalityGap;pub use report::ValueSource;pub use report::WhyReport;pub use report::WhyVerdict;pub use report::ZrecHeader;pub use report::judgement_exit_code;pub use report::CondState;decodepub use report::Transition;decodepub use report::WatchdogSummary;decodepub use tape::bench::BenchSpec;pub use tape::bench::run_bench;pub use tape::ingest::IngestRow;pub use tape::ingest::StreamLine;pub use tape::ingest::parse_row;pub use tape::ingest::parse_stream_line;pub use tape::record::RecordBounds;pub use tape::record::ReplayEvent;pub use tape::record::ReplaySpec;pub use tape::record::ReplayTarget;pub use tape::record::ZREC_VERSION;pub use tape::record::ZrecItem;pub use tape::record::ZrecReader;pub use tape::record::ZrecSink;pub use tape::record::ZrecSource;pub use tape::record::ZrecWriter;pub use tape::record::record;pub use tape::record::replay;pub use zblob;blob
Modules§
- bus
- Layer 1 — the bus. Everything that holds a session and talks to Zenoh.
- error
- The engine’s failure surface — one type, classified by what a caller can do about it.
- judge
- Layer 3 — the judges. Where an observation becomes a verdict.
- model
- Layer 2 — the model. What the observations mean, without asking the bus anything.
- report
- Typed reports — the shared contract between the engine and every frontend.
- tape
- Layer 4 — the tape. Traffic as a thing: captured, read back, manufactured, measured.
Structs§
- Sender
- The traits
watchdogis driven through (#397), re-exported so a consumer needs them in scope without taking a direct dependency onsipper— and so the version this engine speaks is the one it hands out. A sender used to notify the progress of someSipper.
Enums§
- NotValidated
decode - The #159 conformance verdict, re-exported so frontends never reach around the engine for it. Why a payload was not validated. A reason is not a failure: most of these are ordinary states of a live bus (O4 — “not asked” is not “no”).
- Verdict
decode - The #159 conformance verdict, re-exported so frontends never reach around the engine for it. Did the payload conform to its declared schema?
Constants§
- DECLARE_
TIMEOUT - How long a declaration may take before this crate calls it a failure.
Traits§
- Sipper
- The traits
watchdogis driven through (#397), re-exported so a consumer needs them in scope without taking a direct dependency onsipper— and so the version this engine speaks is the one it hands out. A sipper is both aStreamthat produces a bunch of progress and aFuturethat produces some final output. - Straw
- The traits
watchdogis driven through (#397), re-exported so a consumer needs them in scope without taking a direct dependency onsipper— and so the version this engine speaks is the one it hands out. AStrawis aSipperthat can fail.