Conversation
Per-decoder independent activation decisions (threshold + sustain latch, multi-active) over the Phase 2 probability stream. Dense decisions.csv + decision_config.jsonl timeline; engine as a sibling consumer of prediction_ready; apply-gated, thread-safe live config changes. Hardcoded defaults first, optional YAML override last.
Pure-Python building blocks for the per-decoder decision layer (plan A1): DecisionConfig (hardcoded defaults + per-decoder threshold fallback), ThresholdCriterion (instantaneous gate), and SustainGate (per-decoder, independent both-edge debounce latch). No Qt, no I/O.
process_batch consumes a prediction_ready batch and threads SustainGate state across boundaries, returning a DecisionResult of per-sample latches (plan A2). set_pending_config stages a config that the next batch applies at its boundary — bumping the version, resetting counters, keeping latches, and stamping a ConfigChange with the batch's first timestamp for the logger.
Opt-in decision logging (plan A3): on_decisions appends a dense decisions.csv (one bool column per decoder + config_version) and, on a config change carried in the result, a full snapshot to decision_config.jsonl — version 0 written at construction, manifest gains decision_schema_version/initial_config/n_samples. Adds episodes_from_decisions to recover on/off intervals by diffing the columns.
…map)
Decisions use one global threshold shared by every decoder — decoders still
latch independently via the sustain gate, they just share the threshold value.
Removes DecisionConfig.thresholds / threshold_for and the per-decoder expansion
in the logged config (now {"threshold": ...}). Simpler config, one chart line,
one settings control; a per-decoder threshold was unused clutter.
Predictions and decisions are already per-timepoint, so seconds + target_sfreq was an unnecessary round-trip. DecisionConfig now carries integer sustain_timepoints/release_timepoints (counts of predictions); the engine drops target_sfreq and the seconds_to_samples conversion, counting timepoints directly. Removes the rounding/step-size ambiguity of a seconds field.
…_ready Phase B: DecisionBinding, a thin QObject wrapping the pure engine, joins the pipeline like the logger does — connected to worker.prediction_ready (DirectConnection), re-emitting each batch's DecisionResult on decision_ready. StreamWorker is untouched. AppSession builds the engine from hardcoded defaults (target_sfreq from the preprocessor) and, when logging, seeds the logger's version-0 config and connects decision_ready -> on_decisions. LiveStreamSession owns the binding, resets it on start(), forwards decision_ready, and exposes update_decision_config(). Decisions are computed on every run, logged or not.
DecisionPanel: a single row of per-decoder status tiles (name · latest probability · ACTIVE/IDLE). An active tile is highlighted in the decoder's own colour; idle tiles are muted. Multiple tiles light at once — the multi-active model made visible. Phase2Screen wires live.decision_ready -> _on_decision (QueuedConnection) for on/off and feeds probabilities from the prediction stream; resets on Start. DecisionResult is read duck-typed (no backend import).
…se C4)
Replaces the sidebar placeholder with apply-gated decision settings: a threshold
slider + editable spinbox (synced), an integer sustain-timepoints stepper, and
Apply/Reset (enabled only while the draft differs from the applied config, with
distinct enabled/disabled styling and horizontal -/+ steppers). Apply moves both
chart threshold lines (live + event-locked) and, when a run is live, stages the
new config on the engine; the values also seed the next run built from Start.
Contract kept: the panel emits plain {threshold, sustain_timepoints}; AppSession
builds the DecisionConfig (decision_config_defaults / update_decision_config /
build decision_params). Chart/FrozenEventChart gain set_threshold. Folds in C2
(live threshold line). C3 history strip stays deferred.
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
Adds the live decision-rules stack on top of the raw probability stream: a
DecisionEnginethat turns per-decoder probabilities into sustained on/off decisions, session logging of dense decisions + config timeline, wiring into the live stream, and the Phase 2 UI (live decision panel + settings controls with a threshold line on the chart).Commits (10)
debfc5cdocs(plan): decision rules for live decoding9feeb95feat(online): decision primitives — config, threshold, sustain gatef66b6d0feat(online): DecisionEngine batched per-decoder decisions65e33dffeat(online): log dense decisions + config timeline in LiveSessionLogger0360d6crefactor(online): single global threshold (drop per-decoder override map)4ded0acrefactor(online): measure sustain/release in timepoints, drop frequencyc301632chore(online): default decision settings to threshold 0.80, sustain 3 timepoints34449b1feat(online): wire DecisionEngine as a sibling consumer of prediction_ready14f9840feat(frontend): live decision panel (Phase C1)59368e5feat(frontend): decision settings controls + live threshold line (Phase C4)Notes
dev(no divergence, no conflicts).decision_engine.py,decision_binding.py, extendedsession_logger.py+session.py.decision_panel.py, extendedsettings_panel.py,phase2_screen.py,live_probability_chart.py.@