feat(task): emit_trial fans out to writer + relay; guaranteed teardown - #79
Merged
Conversation
Make `TaskRunner.emit_trial` the single per-trial seam: it durably writes the scored trial through the injected `TrialDataWriter` and, when a `relay=` event is passed, dispatches that flat monitor event to the LogAgent relay queue best-effort (a down monitor never interrupts the task). This lets a task persist + relay in one call instead of hand-rolling both. Also run `TaskProcess.exit_safely()` from a `finally` in `__exit__`, so the trial-data writer is flushed and hardware torn down even if a post-hook or the acquisition finalise raises — a session can no longer end with its df unflushed or a device left open. Minor bump (feat).
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.
PR A of the emit_trial convergence (
docs/plans/PLAN_task_isolation_emit_trial.md§7). The framework-guarantee piece: makeemit_trialthe single per-trial seam and ensure teardown always runs, so no task can end a session with unpersisted data. Prompted by an audit that found the bareperiodic_triggerprotocol writes no.msw.df.jsonlat all because each task hand-rolls its own write + relay.What
TaskRunner.emit_trial(trial, *, relay=None)— one call now (a) durably writes the scored trial through the injectedTrialDataWriter, and (b) if arelay=event is given (the task's flat monitor event, a different shape from the stored trial), dispatches it to the LogAgent relay queue best-effort (contextlib.suppress— a down/full monitor never interrupts the task). Migrated tasks stop hand-rollingput_nowaitboilerplate; the write and relay can't drift apart.TaskProcess.__exit__now callsexit_safely()from afinally, so the trial-data writer is flushed (close()whentrial_count > 0) and hardware is torn down even if a post-hook orfinalize_acquisition_in_sessionraises. Previously a raise there skipped teardown, so a session could end with its df unflushed or a device left open.Compatibility
Fully additive:
relaydefaults toNone(existingemit_trial(dict)callers unchanged), and un-migrated tasks that still write their own file are untouched. No task-boundary change. The finalize error still propagates — teardown is guaranteed to run, but a real finalize failure is not swallowed.Tests
tests/test_emit_trial.py: relay dispatched only whenrelay=is passed; the full dict is written while the flat event is relayed; a raising relay queue is swallowed; and teardown (writerclose()+ clear) runs even whenfinalize_acquisition_in_sessionraises. Full msw-core suite green.Next
PR B (msw-tasks-lab) migrates the trigger family onto this seam and fixes
periodic_trigger; PR C migrates the remaining tasks; PR D adds the two-payload canonical record shared with control-plane §T8.