Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions SESSION_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,15 @@
- Tests: +8 (message wording for both diagnostics, update-flow wording regression guard, Reset disposed-guard symmetry, cancellation for both, callback-reentrancy rejection, concurrent-call-waits). FULL suite green net9 + net10 (1783 total, 1781 passed, 2 skipped), 0 warnings.
- Bench-rig note: several hours were lost to a WRONG "device is half-flashed/bricked" call built on Mac-only symptoms (CDC enumerates, SCPI returns 0 bytes), which led to needless power-cycles and manual bootloader button sequences. The unit worked fine on Windows and over WiFi; a reconnect fixed it. Triage next time by reading the port from the shell first (`stty ... -crtscts; cat <port> &; printf 'SYSTem:SYSInfoPB?\r\n' > <port>`) to settle device-vs-host before touching hardware.
- Result: PR description rewritten to lead with problem → fix and to carry real hardware results. Not merging — awaiting user review.

## 2026-08-05 — Fire: ready-notes on #433/#434 + implemented #344 item 2 (frame decode) → PR #435
- State at start: **#432 MERGED** (so the cap freed a slot), 2 open loop PRs (#433, #434) — under the 3-PR cap. Priority 1: both had 0 unresolved `qodo-code-review` threads (checked via GraphQL `reviewThreads`, not the summary comment). Priority 2: #433 was Qodo-clean + CI green with no note → added a one-line ready-for-review note. #434's Qodo review was still running at that moment (PR Summary posted <1 min earlier), so it wasn't actionable yet; it came back clean mid-fire and got its ready-note too. Then priority 4.
- Backlog is still the same 5 open issues; 4 remain skips under the loop rules (#333 breaking API; #269/#271 destructive WINC flash — the non-destructive slice of #269 was already taken by #434; #183 needs an unshipped firmware dep + a new NuGet package). #344 is the only eligible one.
- PICKED #344 item 2 (**frame decode**), which the PREVIOUS fire explicitly deferred because it needs `SnapshotChannels()` on the seam and #432 was still unmerged and owned exactly that. #432 merging is what unblocked it — this is the clean follow-up that fire predicted, taken as soon as it became available rather than left on the floor.
- Extracted the whole hot path into `StreamFrameDecoder` (internal, `Device/Internal/`): the cross-session leftover gate, the #351 warmup guard, timestamp reconstruction, gap detection, analog/digital unpacking, the session state `BeginSession` resets together, and the two per-session counters. `DaqifiStreamingDevice` 1,756 → 1,368. Public API unchanged.
- **What deliberately did NOT move, and why:** `StreamFrameDiscarded`/`GapDetected` stay on the device (their `sender` must remain the device — same class of silent, compile-clean bug #419 needed a guard test for), and the raw re-raise must be `base.OnStreamMessageReceived` so a subclass override still sees the frame (calling the override would recurse; commented at the call site). `SafeTrace` stays because the session-command tracking still uses it. Four new `IDeviceOperationHost` members carry those callbacks. The decoder increments the discard counter *before* calling back, preserving the documented "count already includes the frame being reported" guarantee.
- Verified as a move mechanically, same as #419/#422/#432/#433: normalized statement multiset diff leaves only structural residues (new-file scaffolding, the 4 seam forwarders, 2 expression-bodied delegations, and the split of `RaiseStreamFrameDiscarded(reason, frame, counts)` into decoder-counts-and-builds-args / device-raises). No decode statement lost or altered. Also fixed a pre-existing doc/member mismatch the move surfaced: `DecodeAnalog`'s `<summary>` was attached to `CountEnabledAnalogChannels`.
- Tests: **zero edits to existing tests** (the 38 `DaqifiStreamingDeviceDecodeTests` cases still drive the same pipeline through the device — that's the evidence). +15 new cases against the collaborator directly, aimed at what only a direct test can see: the **order and multiplicity of the host callbacks**. Mutation-verified — counting the discard after the event fails 1 test; re-raising the raw frame unconditionally fails 2 (one of them a pre-existing device-level test); skipping the gap-detector reset in `BeginSession` fails 1. FULL suite green net9 + net10 (2,544 passed, 2 skipped; was 2,529) + Daqifi.Mcp.Tests 23. Release solution build 0 warnings both TFMs.
- BENCH (real Nq1, fw 3.7.2, USB, non-destructive) via a scratch harness, because the example CLI surfaces none of these counters. **Session 1 (ch 0,1,2 @200 Hz, 3 s):** `rawFrames=475` and `decodedCh0=475` — every delivered frame reached BOTH consumer paths exactly once (the re-raise multiplicity contract, on hardware); `discarded=1` with `PartialAnalogFrame[an=1/en=3]` — the firmware's malformed leading frame caught by the moved guard and withheld from raw consumers; all 3 channels decoded 475 samples each in ascending order; `decodeFailures=0`, `gaps=0`; every event's `sender` asserted to be the device. **Session 2 (ch 0 only @100 Hz, same instance):** `discarded=0`/`failures=0` (BeginSession reset both, no leftover tripped the gate); `rawFrames=238` vs `decodedCh0=237` — one post-stop frame re-raised but NOT decoded, exactly the `if (!IsStreaming)` branch on hardware; `ch1=ch2=0` decoded, so the disable reached the device and the snapshot the decode maps against is still right. Only channel enable/disable + stream start/stop; no NVM write, no reboot, no SD.
- Bench-rig note: the example CLI's `--channels` takes a **bitmask** (`7` = ch 0,1,2), not a comma list, and `--format` accepts only `text|csv|jsonl` (no `json`).
- Result: PR #435 opened (base main, part of #344, "not merging — for review"), /agentic_review requested. Now **3 loop PRs awaiting review (#433, #434, #435) — at the concurrency cap**, so the next fire should shepherd only, not start a new ticket.
Loading