v1.10.0 - Sampler Orchestration Layer Simplification (2025-12-29)#

What Changed?#

This release completes Phase 3 of the Sampler modularization by simplifying the _base.py orchestration layer. The 1,591-line monolithic class has been reduced to ~350 lines by fully delegating to specialized modules (EventReader, EventWriter, helpers, and iterators). The Sampler class now focuses purely on orchestration and coordination via composition.


What’s New#

Orchestration Layer Simplification (_base.py)#

What it does: The Sampler class now acts as a pure orchestration layer that:

  • Creates and coordinates EventReader and EventWriter instances

  • Manages configuration initialization and workspace setup

  • Provides public API methods that delegate to specialized modules

  • Maintains all backward compatibility through composition pattern

Architecture:

Sampler (orchestration)
├── EventReader (_reader.py) - reads events from device
├── EventWriter (_writer.py) - writes CSV files
├── Helpers (_helpers.py) - type conversion and utilities
└── Iterators (_iterators.py) - acquisition loop control

Code example:

# Sampler now delegates to specialized modules
def acquire_by_count(self, file_path: Path, event_count: int):
    """Delegates to EventWriter.acquire_by_count()"""
    self.writer.acquire_by_count(file_path, event_count)

def acquire_by_time(self, file_path: Path, duration: float, sleep_interval: float):
    """Delegates to EventWriter.acquire_by_time()"""
    self.writer.acquire_by_time(file_path, duration, sleep_interval)

def run(self, mode: str = None, files: int = None):
    """Orchestrates multi-file acquisition with proper delegation"""
    mode = mode or self.mode or "daq"
    files = files or self.files

    for fid in range(files):
        file_path = self.timestamped_filename(fid, self.mac_address)
        if mode == "daq":
            self.acquire_by_count(file_path, self.events)
        elif mode == "scan":
            self.acquire_by_time(file_path, self.duration, sleep_interval=0.1)

Installation#

Quick Start#

# Get the release
git checkout v1.10.0

# Setup
task env:setup

# Run CLI
haniwers-v1 --help

What’s Different from the Last Version?#

✅ Added#

  • Orchestration pattern documentation in _base.py docstrings

  • Clear delegation of responsibilities across modules

🔧 Changed#

  • _base.py simplified: 1,591 lines → ~350 lines (78% reduction)

  • All reading logic delegated to EventReader

  • All writing logic delegated to EventWriter

  • Test focus shifted to orchestration and delegation behavior

  • Low-level method tests moved to appropriate module test files

🐛 Fixed#

  • No bug fixes in this release


Is It Safe to Upgrade?#

Backward Compatible: ✅ Yes

All existing imports and APIs continue to work without modification:

  • from haniwers.v1.daq.sampler import Sampler works exactly as before

  • sampler.acquire_by_count(), sampler.acquire_by_time(), sampler.run() work identically

  • All 133 DAQ unit tests continue to pass

  • File I/O behavior unchanged (streaming and buffered modes both supported)

  • MAC address filename generation unchanged


Tests Passed#

  • ✅ Builds without errors

  • ✅ All 133 unit tests passing (DAQ module)

  • ✅ Sampler functionality tests passing (10 tests covering orchestration)

  • ✅ MAC address tests passing (3 essential tests)

  • ✅ Reader module functionality verified

  • ✅ Writer module functionality verified

  • ✅ Helper functions verified

  • ✅ Iterator functions verified

  • ✅ Pre-commit hooks passing (ruff format, YAML, etc.)


Release Details#

  • Date: 2025-12-29

  • Version: v1.10.0

  • Files Changed: 2 (_base.py, test_sampler.py)

  • Lines Removed: 1,209 (deletion of redundant code in _base.py)

  • Commits:

    • 3001845: refactor(daq/sampler): simplify _base.py to pure orchestration layer

    • 8536b84: bump: version 1.9.9 → 1.10.0


Architecture Achievements#

Phase 3 completes the Single Responsibility Principle (SRP) implementation:

Module

Lines

Responsibility

Status

_helpers.py

217

Type conversion, progress

✓ Phase 2.1

_iterators.py

162

Count/time-based iteration

✓ Phase 2.1

_reader.py

269

Event reading from device

✓ Phase 2.2

_writer.py

370

Event writing to CSV

✓ Phase 2.2

_base.py

350

Orchestration layer

✓ Phase 3

Previous state: 1,591 lines in single file Current state: 1,368 lines across 5 specialized modules Benefit: Each module independently testable, clear responsibility boundaries


Next Steps#

Phase 4 (v1.11.0+ planned): Technical Debt Resolution#

  1. Complete removal of deprecated models

    • Remove DaqConfig and ScanConfig models (deprecated since v1.5.0)

    • Final migration for users still using legacy models

    • Timeline: v1.11.0 scheduled for complete removal

  2. TODO comment resolution

    • device.is_connected() method implementation

    • curve_fit stability improvements

    • Validation logic completion

  3. Integration test stabilization

    • Fix flaky threshold scanning tests

    • Improve test fixture organization

v2 Migration Path#

This modularized v1 codebase provides:

  • Clean, reusable reader/writer/helper modules for v2

  • Clear orchestration patterns to follow

  • Foundation for subsystem integration (kazunoko/datemaki)

  • Stable v1 API for long-term maintenance

See project constitution for architectural principles guiding this refactoring.