Problem
_RunConfig.save() uses dataclasses.asdict() to serialize the run configuration to JSON. asdict() internally calls copy.deepcopy() on every field value, including the callbacks list. Any callback with non-copyable runtime state (e.g. threading.Event, threading.Thread, file handles, connections) will crash with a TypeError during save.
This affects any callback that maintains runtime state beyond simple config values — for example SystemMetricsMonitor which uses a background thread and a threading.Event for coordination.
Expected behavior
Saving a run config should serialize only the callback's configuration, not its runtime state. The serialization path should not require deepcopy of live objects.
Resolution
Merging #54 (unified serialization layer) should address this by replacing asdict() with serialize(), which uses the __getstate__ protocol as the serialization boundary rather than recursively deepcopying internal state.
Problem
_RunConfig.save()usesdataclasses.asdict()to serialize the run configuration to JSON.asdict()internally callscopy.deepcopy()on every field value, including thecallbackslist. Any callback with non-copyable runtime state (e.g.threading.Event,threading.Thread, file handles, connections) will crash with aTypeErrorduring save.This affects any callback that maintains runtime state beyond simple config values — for example
SystemMetricsMonitorwhich uses a background thread and athreading.Eventfor coordination.Expected behavior
Saving a run config should serialize only the callback's configuration, not its runtime state. The serialization path should not require
deepcopyof live objects.Resolution
Merging #54 (unified serialization layer) should address this by replacing
asdict()withserialize(), which uses the__getstate__protocol as the serialization boundary rather than recursively deepcopying internal state.