yggvault ratatoskr-space connected via regular web
Color theme
also available via yggdrasil mesh http://[203:b338:2a84:a18f:986:47ae:1a4:d8d3]/pkg/ruview/v1326
vault / ruview / v1326

ruview @ v1326

integrity

size
60.0 MiB
downloaded
last checked
source https://github.com/ruvnet/RuView · available · github

release notes

Automated release from CI pipeline

Changes: feat(adr-124): SENSE-BRIDGE — @ruvnet/rvagent MCP server + 6 sensing tools (v0.1.0) (#791)

Iter 4. Lands the central wire-format primitive: complete frames with header + arbitrary-length payload, protected by CRC-32/ISO-HDLC.

Added:

Test config:

ADR-119 ACs progressed:

Out of scope (next iter):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 5. Implements ADR-119 §2.2 payload layout: 4-byte LE length prefix followed by section bytes, in this fixed order:

compressed_angle_matrix ‖ amplitude_proxy ‖ phase_proxy ‖ snr_vector ‖ csi_delta (iff flags.bit0) ‖ vendor_extension (length 0 allowed)

Added:

tests/payload_sections.rs (8 named tests, all green): payload_roundtrip_with_csi_delta payload_roundtrip_without_csi_delta wire_len_matches_to_bytes_length empty_payload_has_five_zero_length_sections parser_rejects_buffer_shorter_than_first_length_prefix parser_rejects_section_body_running_past_buffer_end parser_rejects_trailing_bytes_after_vendor_extension csi_delta_flag_mismatch_with_payload_is_detectable_via_trailing_bytes

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 6. Connects the typed payload parser (iter 5) to the framed wire format (iter 4): the CRC32 now covers the section-prefixed payload bytes per ADR-119 §2.2 ("CRC32 covers all section bytes including length prefixes").

Added:

tests/frame_payload_integration.rs (7 named tests, all green): from_payload_then_parse_payload_is_identity from_payload_autosets_has_csi_delta_flag from_payload_clears_has_csi_delta_flag_when_csi_absent (verifies the flag is cleared when csi_delta is None even if caller pre-set the bit; other flag bits like PRIVACY_MODE are preserved) frame_crc_covers_section_prefixed_bytes (mutating a byte inside section body trips CRC, not magic/length) frame_crc_covers_section_length_prefixes (mutating a section length-prefix byte trips CRC before parser ever runs) empty_typed_payload_roundtrips end_to_end_wire_roundtrip_via_bytes (BfldPayload -> from_payload -> to_bytes -> from_bytes -> parse_payload is the identity function modulo flag auto-set)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 7. First structural enforcement of ADR-118 invariant I2 — the identity embedding is in-RAM-only and cannot be serialized, cloned, or copied. Lands the type itself; ring-buffer lifecycle is next.

Added:

tests/identity_embedding.rs (5 named tests, all green): from_raw_preserves_values_through_as_slice l2_norm_is_correct debug_output_redacts_raw_values (asserts the formatted output does NOT contain decimal text of values) embedding_is_not_clonable (runtime witness; compile-time assertion lives in src/embedding.rs) drop_overwrites_storage_with_zeros (Drop runs without panic; bit-level zeroization is asserted by the black_box-guarded loop. Unsafe peek-after-free is intentionally avoided.)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 8. Lands the lifecycle half of ADR-120 §2.5: a bounded, in-place, no_std-compatible ring of IdentityEmbeddings. Insertion is O(1); when full, push evicts the oldest entry, whose Drop runs and zeroizes the f32 storage. drain() clears the ring on the coherence-gate Recalibrate action (ADR-121 §2.4).

Added:

Uses [const { None }; RING_CAPACITY] (stable since 1.79) to initialize the slot array for a non-Copy element type.

tests/embedding_ring.rs (9 named tests, all green): new_ring_is_empty default_constructor_matches_new push_below_capacity_returns_none iter_yields_in_insertion_order push_at_capacity_evicts_oldest_and_returns_it (verifies eviction reports the FIRST pushed value, not the last) push_beyond_capacity_keeps_last_n_entries (after 74 pushes into a 64-slot ring, the surviving 64 are positions 10..74) drain_empties_the_ring_and_returns_count drain_on_empty_ring_returns_zero ring_can_be_refilled_after_drain (post-drain push lands cleanly at index 0; iter yields exactly that entry)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 9. Lands ADR-120 §2.4 — the only operation that can lower a frame's information content. Demote is monotonic by construction (Result::Err on non-monotone target), strips payload sections per the target class table, and re-syncs header.privacy_class + CRC32.

Added:

Note: demote does NOT zero the original Vec capacity that the heap allocator may still hold — the buffers we own are zeroed and cleared, but the intermediate Vec passed back to BfldFrame::from_payload reallocates anew. For strict heap zeroization in regulated deployments, a follow-up iter can substitute zeroize::Zeroizing<Vec>.

tests/privacy_gate_demote.rs (7 named tests, all green): demote_to_same_class_is_identity demote_derived_to_anonymous_strips_compressed_angle_matrix (also asserts csi_delta dropped, snr_vector and amplitude_proxy preserved) demote_derived_to_restricted_strips_amplitude_and_phase_too (snr_vector and vendor_extension survive at class 3) demote_anonymous_to_derived_is_rejected (asserts InvalidDemote { from: 2, to: 1 }) demote_to_raw_is_rejected_from_any_higher_class (parameterized over Derived, Anonymous, Restricted as sources) demote_preserves_frame_crc_consistency_through_wire_roundtrip (post-demote frame survives to_bytes -> from_bytes with no CRC error) demote_clears_has_csi_delta_flag_bit

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 10. Lands the stateless half of ADR-121 §2.2–§2.4: the multiplicative risk-score formula and the 4-band gate classifier. Hysteresis + 5s debounce (stateful CoherenceGate) land in iter 11.

Added (no_std-compatible):

tests/identity_risk_score.rs (12 named tests, all green): all_ones_yields_one any_zero_factor_collapses_score_to_zero (4 single-factor variants) score_is_monotonic_non_decreasing_in_single_factor out_of_range_inputs_are_clamped_to_unit_interval nan_inputs_treated_as_zero (verifies privacy-conservative NaN handling) known_score_matches_hand_calculation (0.80.90.85*0.95 to 1e-6) from_score_classifies_each_band (8 boundary-condition checks) threshold_constants_match_documented_values nan_score_maps_to_accept_conservatively allows_publish_partitions_actions_correctly drops_event_inverts_allows_publish (parameterized over all 4 actions) requires_recalibrate_is_unique_to_recalibrate

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 11. Wraps the stateless GateAction classifier from iter 10 with two stabilizing mechanisms per ADR-121 §2.5:

Added (no_std-compatible):

tests/coherence_gate.rs (13 named tests, all green): fresh_gate_starts_in_accept_with_no_pending low_score_stays_in_accept_with_no_pending score_just_past_boundary_but_within_hysteresis_does_not_pend (0.52: above 0.5 but inside hysteresis envelope — no pending) score_clearly_past_hysteresis_starts_pending (0.6: past 0.55 hysteresis edge — pending PredictOnly registered) pending_action_promotes_after_full_debounce pending_action_does_not_promote_before_debounce (verified at DEBOUNCE_NS - 1) returning_to_current_band_cancels_pending changing_pending_target_resets_the_debounce_clock (PredictOnly pending at t=0, then Recalibrate at t=1s — clock resets, must wait until t=1s+DEBOUNCE_NS before Recalibrate is current) downward_transitions_also_require_hysteresis (from PredictOnly, 0.48 stays put; 0.44 pends Accept) spike_to_one_then_back_to_zero_never_promotes_to_recalibrate (transient spike + return to baseline produces no transition) boundary_value_with_hysteresis_does_not_promote (0.5+0.05-epsilon) boundary_value_at_hysteresis_exact_does_pend (0.5+0.05) nan_score_stays_in_current_action_with_no_pending

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 12. Wires the ADR-121 §2.6 Recalibrate exemption: when an enrolled person_id matches the current high-separability cluster, the gate downgrades the would-be Recalibrate to PredictOnly. The high score is the intended outcome of a Soul Signature match, not an attacker-grade sniffer arrival — so site_salt rotation is suppressed.

Added (no_std-compatible):

tests/soul_match_oracle.rs (8 named tests, all green): null_oracle_matches_default_evaluate_behavior (parameterized over 5 score points; oracle-aware and oracle-free gates produce identical trajectories) match_outcome_downgrades_recalibrate_to_predict_only (score=0.95 pends PredictOnly instead of Recalibrate) match_exemption_promotes_predict_only_after_debounce_not_recalibrate (after DEBOUNCE_NS, current is PredictOnly — never Recalibrate) match_outcome_does_not_affect_lower_actions (Reject pending stays Reject; oracle only intercepts Recalibrate) suppressed_outcome_does_not_exempt_recalibrate (Suppressed is functionally equivalent to NotEnrolled at the gate) not_enrolled_outcome_does_not_exempt_recalibrate match_outcome_carries_person_id null_oracle_default_constructor_works

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 13. Lands ADR-121 §2.1 (output event) + ADR-122 §2.1 (field-gating policy). BfldEvent collapses the GateAction-driven sensing pipeline into the canonical wire-format publishable on MQTT.

Added:

tests/event_privacy_gating.rs (9 named tests, all green): anonymous_event_retains_identity_risk_and_hash restricted_event_strips_identity_fields (class 3 → None) apply_privacy_gating_is_idempotent event_type_is_always_bfld_update (parameterized over 3 classes) json::json_round_trip_emits_type_field_first_or_last_but_present json::anonymous_json_includes_identity_fields json::restricted_json_omits_identity_fields_entirely (asserts the JSON string does NOT contain identity_risk_score or rf_signature_hash, verifying skip_serializing_if works as intended) json::privacy_class_serializes_to_lowercase_name json::zone_id_none_is_omitted_from_json

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 14. Wires every iter-1..13 primitive into a single ADR-118 §2.1 pipeline: per-frame sensing inputs go in, a privacy-gated BfldEvent (or None) comes out. First time every constituent is exercised together.

Added (gated on feature = "std"):

tests/emitter_pipeline.rs (7 named tests, all green): emitter_emits_event_under_low_risk emitter_drops_event_under_sustained_high_risk (debounce honored) emitter_drains_ring_on_recalibrate (fills ring to 5, then Recalibrate-grade score → ring_len() == 0) restricted_class_strips_identity_fields_in_emitted_event (class 3: identity_risk_score AND rf_signature_hash both None) with_zone_sets_default_zone_id_on_event embedding_is_pushed_to_ring_even_when_event_dropped (privacy gating drops the event but the ring still observes the embedding so subsequent separability calculations remain valid) ring_unchanged_when_no_embedding_supplied

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 15. Lands ADR-120 §2.3 — the cryptographic foundation of invariant I3 ("cross-site identity correlation is impossible"). rf_signature_hash is now derived from a per-site secret and a daily epoch, so two nodes observing the same physical person produce uncorrelated 256-bit digests.

Added (no_std-compatible):

tests/signature_hasher.rs (8 named tests, all green): deterministic_under_identical_inputs different_site_salts_produce_different_hashes different_day_epochs_rotate_the_hash different_features_produce_different_hashes output_length_is_32_bytes day_epoch_from_unix_secs_matches_floor_division (covers 0, 86_399, 86_400, and the 1.7e9 modern timestamp) compute_at_matches_compute_with_derived_day cross_site_hamming_distance_is_statistically_high *** ADR-120 §2.7 AC2 acceptance test *** Runs 100 trials with distinct (salt_a, salt_b) pairs observing identical features, computes per-trial Hamming distance, asserts mean >= 120 bits and min >= 80 bits. Empirically lands at ~128 bits mean (the expected value for two independent 256-bit hashes), with no trial below 80 bits — i.e., zero suspicious near-collisions.

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 16. End-to-end ADR-120 §2.3 wiring: BfldEmitter now produces rf_signature_hash derived from (site_salt, day_epoch, features), with the IdentityEmbedding bytes as the preferred feature source. Closes the gap from iter 15 — the hasher is now reachable from the pipeline.

Added (in src/emitter.rs):

tests/emitter_hasher.rs (6 named tests, all green): no_hasher_passes_caller_supplied_hash_through installed_hasher_overrides_caller_supplied_hash same_emitter_same_inputs_produce_same_hash (determinism through emitter) different_site_salts_produce_different_hashes_end_to_end *** cross-site isolation proven via the BfldEmitter API, not just via the SignatureHasher direct API (iter 15) *** no_embedding_falls_back_to_risk_factor_bytes fallback_hash_differs_from_embedding_hash (embedding-based and fallback-based hashes are distinct paths)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 17. Lands the BFLD JSON wire spec format for rf_signature_hash — a "blake3:" prefix followed by 64 lowercase hex chars. Replaces the default serde array-of-integers encoding which was unusable for downstream consumers (HA, Matter, MQTT).

Added (in src/event.rs):

tests/json_hash_format.rs (5 named tests, all green): rf_signature_hash_serializes_as_blake3_prefixed_lowercase_hex (expected hex built programmatically via format!("{b:02x}")) hex_string_is_always_64_chars_when_present (parses the JSON, isolates the hash substring, asserts exact 64 chars and lowercase-only — catches case-folding regressions) hash_field_omitted_entirely_when_none end_to_end_emitter_hasher_to_json_emits_blake3_hex_hash *** Cross-iter integration test: BfldEmitter::with_signature_hasher → SensingInputs.rf_signature_hash = None → emit derives via BLAKE3 → BfldEvent::to_json → contains "blake3:" prefix. Spans iters 13, 14, 15, 16, 17 in a single assertion. *** end_to_end_restricted_class_omits_hash_even_with_hasher_set (class 3: even with hasher installed, JSON omits the hash)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 18. Consolidates the embedding-vs-risk-factor hashing-input selection behind a single typed API. Replaces the two ad-hoc paths that lived in emitter.rs through iter 17:

Added (gated on feature = "std"):

Refactor:

tests/identity_features_encoder.rs (9 named tests, all green): embedding_canonical_length_is_dim_times_four risk_factor_canonical_length_is_sixteen_bytes embedding_canonical_bytes_match_manual_flatten risk_factor_canonical_bytes_match_explicit_le_layout write_canonical_bytes_appends_to_existing_buffer compute_hash_matches_direct_hasher_invocation embedding_and_risk_factors_produce_different_hashes iter_16_wire_compat_embedding_path *** backward-compat regression *** iter_16_wire_compat_risk_factor_path *** backward-compat regression *** These two tests assert that the refactored encoder produces bit-identical hashes to iter 16's inline path. Existing deployed nodes upgrading to iter 18 see no rf_signature_hash flip.

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 19. Public lib.rs entry point per ADR-118 §2.1. Thin facade over BfldEmitter that adds a config-driven builder and a privacy_mode toggle for emergency demote-to-Restricted without rebuilding the gate/ring/hasher state.

Added (gated on feature = "std"):

Design note: the privacy_mode override is applied post-emission, NOT by rebuilding the emitter. This preserves gate state (current action, pending transitions), ring contents, and hasher salt across the toggle — critical for incident response where the operator needs to keep detecting anomalies while temporarily redacting the public surface.

tests/pipeline_facade.rs (9 named tests, all green): config_defaults_to_anonymous_no_zone_no_hasher config_builder_methods_chain fresh_pipeline_is_not_in_privacy_mode pipeline_process_returns_anonymous_event_under_low_risk enable_privacy_mode_demotes_published_events_to_restricted (verifies BOTH identity_risk_score AND rf_signature_hash become None) disable_privacy_mode_restores_baseline_class (round-trip: enable → demoted → disable → restored to Anonymous) privacy_mode_overrides_derived_baseline_too (research-mode operator can still flip the emergency switch) pipeline_with_hasher_emits_derived_rf_signature_hash zone_is_threaded_from_config_to_event

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 20. Adds the wire-bytes companion to BfldPipeline::process so callers needing BfldFrame (for ESP-NOW, UDP, file dump, witness bundles, etc.) don't have to drop down to BfldEmitter + manual BfldFrame construction.

Added (in src/pipeline.rs):

tests/pipeline_to_frame.rs (6 named tests, all green): process_to_frame_emits_frame_under_low_risk (timestamp_ns + privacy_class correctly propagated from pipeline) process_to_frame_returns_none_under_sustained_high_risk (gate Reject path: two consecutive high-risk calls → None) process_to_frame_round_trips_through_bytes (frame.to_bytes() → BfldFrame::from_bytes() → parse_payload() identity) process_to_frame_overrides_class_in_privacy_mode (enable_privacy_mode → frame.header.privacy_class = Restricted byte) process_to_frame_preserves_header_template_identity_fields (ap_hash, sta_hash, session_id, channel from template survive) process_to_frame_uses_input_timestamp_not_template_timestamp (template.timestamp_ns = 12345 is overridden by inputs.timestamp_ns)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 21. Lands ADR-122 §2.2 topic shape + class-gated routing as a pure function. No broker dep yet — that lands in iter 22 with tokio + rumqttc behind an mqtt feature. This iter is the routing policy, separated for testability.

Added (gated on feature = "std"):

Payload encoding:

tests/mqtt_topic_routing.rs (10 named tests, all green): topic_format_is_ruview_node_bfld_entity_state anonymous_class_publishes_six_topics_with_zone (6 = presence/motion/count/conf/zone/identity_risk) anonymous_class_without_zone_omits_zone_activity_topic (5 topics) restricted_class_omits_identity_risk_topic (class 3 → 5 topics, no risk) raw_and_derived_classes_publish_nothing *** structural enforcement of "raw stays local" at the topic layer *** presence_payload_is_lowercase_json_bool motion_payload_is_fixed_precision_decimal person_count_payload_is_bare_integer zone_payload_is_json_string_with_quotes identity_risk_payload_is_fixed_precision_decimal

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 22. Abstracts the MQTT publish boundary without pulling in tokio or rumqttc yet. The trait is sync (callers can hold &mut self without an async runtime); the production rumqttc-backed impl in iter 23 will drive a tokio task internally and present the same sync surface here.

Added (in src/mqtt_topics.rs, gated on feature = "std"):

tests/mqtt_publish_loop.rs (7 named tests, all green): capture_publisher_records_every_message publish_returns_zero_for_raw_and_derived_events (parameterized — class 0 and class 1 both produce zero publishes, reinforcing the invariant I1 surface enforcement from iter 21) published_topics_match_render_events_ordering (stable per-event topic sequence for MQTT consumers) restricted_class_publishes_no_identity_risk_topic anonymous_without_zone_publishes_five_messages (5 = no zone_activity) publisher_error_short_circuits_publish_event (FailingPublisher fails on 3rd publish; publish_event surfaces the error AND leaves the first two messages durably published) capture_publisher_error_type_is_infallible (compile-time witness that CapturePublisher cannot panic the loop)

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 23. Production Publish trait impl using rumqttc 0.24 (same crate version + use-rustls feature pinning as wifi-densepose-sensing-server, so both publishers can share broker connection posture).

Added:

tests/rumqttc_publisher_smoke.rs (7 named tests, all green, gated on mqtt): rumqttc_publisher_constructs_without_broker (uses 127.0.0.1:1 — reserved port refuses immediately; no hang) with_retain_builder_yields_a_publisher publish_queues_message_without_blocking_on_broker_state *** Critical property: rumqttc's sync Client::publish queues into an unbounded channel; publish_event returns Ok without round- tripping to the (offline) broker. The queued packet only sends if a thread iterates Connection::iter(). *** restricted_event_publishes_four_messages_through_rumqttc (class 3 + no zone: presence/motion/count/confidence — 4 topics) publisher_trait_object_is_constructible (Box<dyn Publish<Error = rumqttc::ClientError>> works) direct_publish_call_through_trait_object default_qos_is_at_least_once_via_connect

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 24. Live-broker roundtrip test for the RumqttPublisher → mosquitto → subscriber path. CI-safe: silently skips when BFLD_MQTT_BROKER is unset; opt-in locally with:

scoop install mosquitto
mosquitto -v -c mosquitto-allow-anon.conf &
BFLD_MQTT_BROKER=tcp://localhost:1883 cargo test \
    -p wifi-densepose-bfld --features mqtt --test mosquitto_integration

Added (gated on feature = "mqtt"):

Test discipline (per the workspace memory):

When BFLD_MQTT_BROKER is unset:

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Iter 25. Single-call operator surface: spawn() takes a BfldPipeline and a Publish impl, returns a handle whose send() enqueues sensing inputs into a worker thread. The worker drives pipeline.process() then publish_event() per input. Drop or shutdown() joins cleanly.

Added (gated on feature = "std"):

tests/pipeline_handle_worker.rs (8 named tests, all green): handle_publishes_single_input (5 topics for Anonymous + no zone) handle_publishes_multiple_inputs_in_order (3 × 5 = 15 topics) handle_send_after_shutdown_errors (compile-time witness: shutdown(self) consumes the handle so post-shutdown send() is structurally impossible) handle_drop_without_explicit_shutdown_joins_worker_cleanly (validates the Drop path completes without hanging) handle_honors_privacy_mode_toggle_via_pipeline_state (4 topics for Restricted; identity_risk absent) handle_drops_event_when_gate_rejects (5 topics from first Accept-state input + 0 from Reject) handle_with_zone_threads_through_to_published_topics (zone_activity payload = ""kitchen"") class_3_pipeline_baseline_produces_four_topics_per_input

Test publisher pattern: Arc<Mutex> lets the test thread read out the worker thread's publish log post-shutdown without needing custom channel plumbing per test.

ACs progressed:

Test config:

Out of scope (next iter target):

Co-Authored-By: claude-flow ruv@ruv.net

Land the rvAgent (vendor/ruvector/crates/rvAgent/) integration research dossier and update both the Claude Code and Codex plugins so future operators have a discoverable entry point for prototyping agentic flows on top of RuView's existing sensing pipeline + RVF cognitive containers.

Added:

Modified:

No code changes; no test impact.

Co-Authored-By: claude-flow ruv@ruv.net

Iter 26. Lands ADR-122 §2.1 HA-DISCO config-message generator. Counterpart to iter 21's state-topic router: this produces the homeassistant//<unique_id>/config messages HA reads on startup to auto-create the six BFLD entities as a single device.

Discovery payloads are intended to be published once per node session with retain = true (so HA finds them on subsequent starts). The RumqttPublisher from iter 23 already exposes with_retain(true) for this purpose; the state-topic loop must keep retain = false to avoid stale-state flapping.

Added (gated on feature = "std"):

tests/ha_discovery.rs (10 named tests, all green): raw_and_derived_classes_produce_no_discovery_payloads anonymous_class_produces_six_discovery_payloads restricted_class_omits_identity_risk_discovery discovery_topic_format_matches_ha_convention (validates all six homeassistant/.../config topics exist) presence_payload_carries_occupancy_device_class motion_payload_marked_as_diagnostic person_count_payload_carries_unit_of_measurement every_payload_contains_unique_id_and_state_topic_p…

Docker Image: ghcr.io/ruvnet/RuView:a91004e7b10b30c3a3cb96349a4ecd3f00e15a89

download

unix · zip
curl -fL -o v1326.zip https://ratatoskr.space/pkg/ruview/v1326.zip
                    printf '%s  %s\n' 'd6217606fc752f9fdd9ce8f8a9daa8112e3cab6475f819065ff13f67a16055ec' 'v1326.zip' | sha256sum -c -
windows · zip
$url = "https://ratatoskr.space/pkg/ruview/v1326.zip"
$out = "v1326.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "d6217606fc752f9fdd9ce8f8a9daa8112e3cab6475f819065ff13f67a16055ec") { throw "sha256 mismatch" }
unix · tar.gz
curl -fL -o v1326.tar.gz https://ratatoskr.space/pkg/ruview/v1326.tar.gz
                    printf '%s  %s\n' '332690f12b0cd03761aa22c3ef7718ddaac495f6f6688f2af9259732d039755b' 'v1326.tar.gz' | sha256sum -c -
windows · tar.gz
$url = "https://ratatoskr.space/pkg/ruview/v1326.tar.gz"
$out = "v1326.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "332690f12b0cd03761aa22c3ef7718ddaac495f6f6688f2af9259732d039755b") { throw "sha256 mismatch" }
download via yggdrasil mesh
unix · zip
curl -fL -o v1326.zip http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.zip
                    printf '%s  %s\n' 'd6217606fc752f9fdd9ce8f8a9daa8112e3cab6475f819065ff13f67a16055ec' 'v1326.zip' | sha256sum -c -
windows · zip
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.zip"
$out = "v1326.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "d6217606fc752f9fdd9ce8f8a9daa8112e3cab6475f819065ff13f67a16055ec") { throw "sha256 mismatch" }
unix · tar.gz
curl -fL -o v1326.tar.gz http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.tar.gz
                    printf '%s  %s\n' '332690f12b0cd03761aa22c3ef7718ddaac495f6f6688f2af9259732d039755b' 'v1326.tar.gz' | sha256sum -c -
windows · tar.gz
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.tar.gz"
$out = "v1326.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "332690f12b0cd03761aa22c3ef7718ddaac495f6f6688f2af9259732d039755b") { throw "sha256 mismatch" }
artifact format size hashes
v1326.zip zip 60.0 MiB
blake3-24 fe139a30329e13151cdb8a45f13e57455082348e8d315ed4
sha256 d6217606fc752f9fdd9ce8f8a9daa8112e3cab6475f819065ff13f67a16055ec
sha1 7f71ca574fdda030fc0d9ee4e6510f3970f0c264
v1326.tar.gz tar.gz 58.4 MiB
blake3-24 8f0c1fb74769283c71abf5f0ac2ad11394d6ae2766274336
sha256 332690f12b0cd03761aa22c3ef7718ddaac495f6f6688f2af9259732d039755b
sha1 c282f2b4afee65835b76734ecbb5df13c8eca28b

install

bazel
http_archive(
    name = "ruview",
    urls = ["https://ratatoskr.space/pkg/ruview/v1326.tar.gz"],
    integrity = "sha256-MyaQ8SsM0DdhqiLD73cY3arElfb2aI8q+SWXMtA5dVs=",
    strip_prefix = "ruview-v1326",
)
zig
.url = "https://ratatoskr.space/pkg/ruview/v1326.tar.gz",
install via yggdrasil mesh
bazel
http_archive(
    name = "ruview",
    urls = ["http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.tar.gz"],
    integrity = "sha256-MyaQ8SsM0DdhqiLD73cY3arElfb2aI8q+SWXMtA5dVs=",
    strip_prefix = "ruview-v1326",
)
zig
.url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v1326.tar.gz",
← v1327v1316 →