feat: MIDI, bring-up machine, oscillator/i2c/cloud-sync, serial-read fix + node diagnostics - #93
Merged
Merged
Conversation
Single Midi node handling both directions: - browser via Web MIDI (MidiPerformer, the twin of the desktop MidiManager) - desktop via midir (runtime/midi.rs on the actor thread) - Arduino via serial MIDI.h codegen Adds midi_wiring/collect_midi_listeners (no per-topic reconcile — every matching listener receives every message), a MidiSend CloudRequestKind intercepted by each host before the cloud performer, and the NodeEmission shared_declarations/setup/loop dedup primitive for codegen. Validate warns that the serial-MIDI emitter claims the board's primary UART. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lift the bring-up POLICY (probe -> flash-if-missing -> connect -> reconnect, and the disconnected/connecting/flashing/connected/error transitions) into microflow_core::bringup, shared by both hosts. Desktop (hardware/mod.rs) and browser (board-controller.ts) become thin adapters that feed the machine Web-Serial/serial events and perform the actions it returns. web-serial.ts is reduced to transport primitives (probeFirmata / probeAfterFlash); the wasm BringUpMachine binding exposes the machine to the browser. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both waveforms use the same sin-hash lattice in the live runtime and the generated sketch, so the device matches the live preview sample-for-sample. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the I2C reply fold arithmetic into one shared ByteDecode descriptor in config::i2c_device (fold_bytes); the runtime interprets it and the sketch emitter transcribes it to C++, with codegen/parity.rs pinning the two. No behavioural change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hide the stepperPosition template: flashed StandardFirmata has no AccelStepper support, so the motor never moves. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace use-llm-sync/use-mqtt-sync with a single cloud-capability-sync module reading one HostSnapshot (brokers/providers/figma); provider status now lives on the store. The FlowUpdateDispatcher reads the shared snapshot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add flow-access/flow-role routers (per-flow access checks) and extract getSession/getCustomerState helpers on the auth client, wiring them through the flow/login/profile routes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The single-threaded runtime actor owns the FlowRuntime and the serial port. Its loop drained ALL queued ActorMsgs before reading the port once, and each outbound write blocked on flush() (macOS tcdrain). With a 60fps oscillator arming a _tick every ~16ms, per-wake processing exceeded the tick period, so the message queue never emptied, pump_port() never ran, and feed_bytes was never called — every input (buttons, I2C, NFC) went silent while outbound flooded. Fix: read the port after each handled message (no message volume can starve reads), and drop the per-write flush (write_all sends in order; synchronous drain isn't needed). Note: mid-debug — buttons recover but I2C streaming is still under investigation; kept as its own commit for easy revert/iteration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire the desktop MidiManager (runtime/midi.rs) into the actor's module tree. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The MIDI node pulls midir, whose Linux backend (alsa-sys) needs the ALSA headers to build. All three Linux CI jobs (clippy, test, build-tauri) failed on `failed to run custom build command for alsa-sys`; add the dev package alongside the existing libudev-dev. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI clippy (rust 1.97) is stricter than local (1.95): - backtick FortySevenEffects in the midi emitter doc (doc_markdown) - if let/else over a two-arm match in the midi step sequencer (single_match) - allow many_single_char_names on the noise-lattice fns (conventional t/i/f/a/b) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The alsa fix let CI clippy compile the desktop crate on Linux for the first time, surfacing one more pedantic lint (must_use_candidate) that macOS/local builds also have but CI now enforces workspace-wide. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Branch bundle of several subsystems plus a runtime-fault-surfacing feature. Split into logical commits; each subsystem is independent, so review by commit.
Features
midir), and Arduino (serialMIDI.h).randomwalk+perlinwaveforms (device matches live sample-for-sample).Fixes
flush()starved every input (buttons/I2C/NFC). Fixed by pumping the port after each message + dropping the per-writeflush.libasound2-devon Linux foralsa-sys(midir); satisfy rust-1.97 clippy pedantic lints.Node diagnostics (new runtime→UI health channel)
A NACKing I2C sensor used to fail silently (monitor stuck at 0). Root cause: the board streams an empty
I2C_REPLY+ "I2C: Too few bytes received", and the codec dropped the empty reply (len < 8), so the node never saw the fault.len >= 7) so the fault reaches the target node (routed by address+register).Effects.node_diagnostics→ compile-forcedEffectsSink::report_diagnostichook in both hosts (ADR-0008/0009 pattern). Nodes raise viaRuntimeContext::report_diagnostic/clear_diagnostic.NodeContainererror/warning badge — the I2C node shows "No response from 0x29: got 0 of 8 bytes. Check wiring…". Works identically on desktop (Taurinode-diagnostic) and in-browser (reactor).Verification
590 core tests pass (incl. a new raise→dedup→clear test); workspace clippy clean (
-D warnings -W pedantic); wasm runtime compiles; frontendtscclean; browser effects-sink conformance test updated + passing.🤖 Generated with Claude Code