fix(rufield): simulated source now feeds /api/field, honestly - #1720
Open
fallen-pc wants to merge 1 commit into
Open
fix(rufield): simulated source now feeds /api/field, honestly#1720fallen-pc wants to merge 1 commit into
fallen-pc wants to merge 1 commit into
Conversation
Two joined bugs, both in the RuField P3 live surface:
1. `--source simulated` (the project's own "no hardware" quick start)
never populated node_states, the map engine_bridge.observe_cycle
reads to produce a trust class. Without a class, emit_rufield_event
is a no-op by design ("no class => nothing honest to stamp"), so
/api/field and /ws/field silently returned zero events forever
under Docker demo mode - not documented anywhere as a limitation.
2. Once wired, the fix would have made things worse: the
wifi-densepose-rufield bridge hardcoded synthetic: false and
vendor: "esp32" on every event, an assumption that held only
because real ESP32 UDP was previously the sole caller. Simulated
cycles would have been signed and shipped indistinguishable from
real hardware - the exact dishonesty this crate's own docs (ADR-262
Sec0/Sec6) exist to prevent.
Fixes both: simulated_data_task now mirrors its frame into node_states
under a synthetic node id and drives the same governed cycle +
emit_rufield_event call as the real ESP32 path; SensingSnapshot grows
a `synthetic` field threaded through build_snapshot ->
emit_rufield_event -> snapshot_to_field_event, so a simulated cycle is
labelled synthetic: true / vendor: "simulated" end to end.
Live-verified: /api/field now returns real signed FieldEvents under
`--source simulated`, correctly self-labelled.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two joined bugs in the RuField P3 live surface (
/api/field,/ws/field).1. The wiring gap.
--source simulated— the project's own documented "no hardware" quick start — never populatednode_states, the mapengine_bridge.observe_cyclereads to produce a trust class.emit_rufield_eventis a deliberate no-op without a class ("no class ⇒ nothing honest to stamp"), so/api/field//ws/fieldsilently returned zero events forever under Docker demo mode. Not documented anywhere as a limitation — traced this while wiring uprufield-viewer --source liveagainst a local server and gettingevents: []no matter how long I waited.2. The honesty gap the wiring fix would have introduced. Once wired,
wifi-densepose-rufield's bridge (snapshot_to_field_event) unconditionally hardcodedsynthetic: falseandvendor: "esp32"on every emitted event — an assumption that only held because real ESP32 UDP ingestion was previously the sole caller. Simply wiring the simulated path through would have shipped simulated data signed and labeled indistinguishable from real hardware — exactly the dishonesty this crate's own docs (ADR-262 §0/§6) exist to prevent.Change
simulated_data_tasknow mirrors its per-tick frame intonode_statesunder a synthetic node id (SIMULATED_NODE_ID), and drives the same governed cycle (engine_bridge.observe_cycle) +emit_rufield_eventcall the real ESP32 UDP path already uses.SensingSnapshotgrows asynthetic: boolfield, threaded throughbuild_snapshot→emit_rufield_event→snapshot_to_field_event, so a simulated cycle is labeledsynthetic: true/vendor: "simulated"/simulated_node_Nend-to-end, and a real cycle stayssynthetic: false/vendor: "esp32"exactly as before.gate_synthetic_flag_passes_through_honestlyinwifi-densepose-rufieldproves the flag isn't hardcoded either direction.Test plan
cargo test -p wifi-densepose-rufield -p wifi-densepose-sensing-server --no-default-features— all passing (22 + 8 rufield-related tests, no regressions)npx @ruvnet/ruview claim-checkon this PR body — PASS--source simulatedand a realWDP_RUFIELD_SIGNING_SEED. Before the fix:GET /api/field→events: []forever,/api/v1/status→effective_class: nullforever. After: real signedFieldEvents flowing, e.g.event_id: "ruview-simulated_node_1-...",provenance.synthetic: true,sensor.vendor: "simulated", valid ed25519 signature,dev_signing_key: false.