- Break Phase 1 into 25 sprints with atomic tasks - Define stub-first approach for manageable complexity - Specify commit messages for each task - Include LLM optimisation notes for context management
17 KiB
Development Plan
Phase 1: Vertical Slice (MVP)
| Document ID | DEV-001 |
|---|---|
| Version | 1.0.0 |
| Status | Active |
| Author | Kai Chappell |
| Created | 2025-12-01 |
Approach
This plan follows an iterative, stub-first development strategy optimised for incremental progress:
- Interfaces First - Define protocols/interfaces before implementations
- Stubs Before Logic - Create skeleton classes that pass type checks before adding behaviour
- Bottom-Up Construction - Build foundational layers before dependent layers
- Frequent Commits - Small, atomic commits after each meaningful change
- Minimal Context - Each iteration should be completable with minimal codebase knowledge
Sprint Structure
Each sprint represents ~2-4 hours of focused work. Sprints are designed to be self-contained with clear deliverables.
Sprint 1: Project Scaffolding
Goal: Create project structure and build configuration.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 1.1 | Create pyproject.toml with project metadata and dependencies |
chore: add pyproject.toml with dependencies |
| 1.2 | Create src/thermaulate/__init__.py with version |
chore: create package structure |
| 1.3 | Create empty subpackage __init__.py files for all modules |
chore: add subpackage stubs |
| 1.4 | Create py.typed marker file |
chore: add py.typed marker for PEP 561 |
| 1.5 | Create config/default.yaml with basic structure |
chore: add default configuration file |
Deliverables
pip install -e .works- All imports resolve (empty packages)
- Type checker can be run
Sprint 2: Configuration System
Goal: Load and validate configuration.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 2.1 | Create config/models.py with Pydantic config classes |
feat(config): add Pydantic configuration models |
| 2.2 | Create config/loader.py to load YAML and return AppConfig |
feat(config): add configuration loader |
| 2.3 | Add unit tests for config loading | test(config): add configuration tests |
Deliverables
- Can load
config/default.yamlinto typed Python objects - Invalid configs raise clear errors
Sprint 3: Transport Layer (Stubs)
Goal: Define transport abstractions.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 3.1 | Create transport/base.py with Transport Protocol |
feat(transport): add Transport protocol |
| 3.2 | Create transport/tcp.py with TCPTransport stub class |
feat(transport): add TCPTransport stub |
Deliverables
- Transport interface defined
- TCPTransport class exists with NotImplementedError methods
Sprint 4: Transport Layer (Implementation)
Goal: Implement TCP transport.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 4.1 | Implement TCPTransport.connect() and disconnect() |
feat(transport): implement TCP connect/disconnect |
| 4.2 | Implement TCPTransport.write() and read() |
feat(transport): implement TCP read/write |
| 4.3 | Implement TCPTransport.query() |
feat(transport): implement TCP query |
| 4.4 | Add unit tests with mock socket | test(transport): add TCP transport tests |
Deliverables
- Can connect to TCP server and exchange messages
- Handles connection errors gracefully
Sprint 5: SCPI Parser
Goal: Parse SCPI command strings.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 5.1 | Create instruments/scpi_parser.py with SCPICommand dataclass |
feat(scpi): add SCPICommand dataclass |
| 5.2 | Implement SCPIParser.parse() method |
feat(scpi): implement SCPI parser |
| 5.3 | Add comprehensive parser tests | test(scpi): add parser tests |
Deliverables
- Can parse
*IDN?,VOLT 3.3,TEMP:SETPOINT?, etc. - Returns structured command objects
Sprint 6: Physics Engine (Stubs)
Goal: Define physics simulation interfaces.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 6.1 | Create physics/engine.py with state dataclasses |
feat(physics): add ThermalState and ElectricalState |
| 6.2 | Create PhysicsEngine class with stub methods |
feat(physics): add PhysicsEngine stub |
| 6.3 | Create physics/dut/base.py with DUTModel Protocol |
feat(physics): add DUT model protocol |
Deliverables
- Physics interfaces defined
- State objects can be instantiated
Sprint 7: Physics Engine (Thermal)
Goal: Implement thermal simulation.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 7.1 | Implement PhysicsEngine.step() thermal calculations |
feat(physics): implement thermal step |
| 7.2 | Implement PhysicsEngine.set_chamber_setpoint() |
feat(physics): implement chamber setpoint |
| 7.3 | Implement PhysicsEngine.get_thermal_state() |
feat(physics): implement thermal state getter |
| 7.4 | Add thermal simulation tests | test(physics): add thermal simulation tests |
Deliverables
- Chamber temperature ramps toward setpoint
- Case temperature follows with time constant
Sprint 8: LDO DUT Model
Goal: Implement LDO electrical model.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 8.1 | Create physics/dut/ldo.py with LDOModel class |
feat(physics): add LDO model stub |
| 8.2 | Implement temperature-dependent output voltage | feat(physics): implement LDO Vout vs temperature |
| 8.3 | Implement power dissipation calculation | feat(physics): implement LDO power dissipation |
| 8.4 | Implement quiescent current model | feat(physics): implement LDO quiescent current |
| 8.5 | Add LDO model tests | test(physics): add LDO model tests |
Deliverables
- LDO output voltage varies with temperature (TempCo)
- Power dissipation calculated correctly
Sprint 9: Physics Engine (Electrical Coupling)
Goal: Connect electrical and thermal domains.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 9.1 | Integrate LDO model into PhysicsEngine | feat(physics): integrate DUT model |
| 9.2 | Implement self-heating feedback loop | feat(physics): implement self-heating |
| 9.3 | Implement get_electrical_state() |
feat(physics): implement electrical state getter |
| 9.4 | Add coupled physics tests | test(physics): add thermal-electrical coupling tests |
Deliverables
- Higher load current causes self-heating
- Junction temperature affects output voltage
Sprint 10: Virtual Instruments (Stubs)
Goal: Define virtual instrument classes.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 10.1 | Create instruments/base.py with VirtualInstrument base class |
feat(instruments): add VirtualInstrument base |
| 10.2 | Create instruments/thermal_chamber.py stub |
feat(instruments): add ThermalChamberSim stub |
| 10.3 | Create instruments/power_supply.py stub |
feat(instruments): add PowerSupplySim stub |
| 10.4 | Create instruments/multimeter.py stub |
feat(instruments): add MultimeterSim stub |
Deliverables
- All instrument classes exist
- Common SCPI commands stubbed (IDN, RST)
Sprint 11: Thermal Chamber Simulator
Goal: Implement thermal chamber SCPI commands.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 11.1 | Implement TEMP:SETPOINT command |
feat(instruments): implement chamber TEMP:SETPOINT |
| 11.2 | Implement TEMP:ACTUAL? query |
feat(instruments): implement chamber TEMP:ACTUAL? |
| 11.3 | Implement TEMP:STAB? query |
feat(instruments): implement chamber stability query |
| 11.4 | Add thermal chamber tests | test(instruments): add thermal chamber tests |
Deliverables
- Chamber responds to SCPI commands
- Reads from physics engine state
Sprint 12: Power Supply Simulator
Goal: Implement power supply SCPI commands.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 12.1 | Implement VOLT, CURR, OUTP commands |
feat(instruments): implement PSU control commands |
| 12.2 | Implement MEAS:VOLT?, MEAS:CURR? queries |
feat(instruments): implement PSU measurements |
| 12.3 | Add power supply tests | test(instruments): add power supply tests |
Deliverables
- PSU responds to voltage/current/output commands
- Measurements reflect physics state
Sprint 13: Multimeter Simulator
Goal: Implement DMM SCPI commands.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 13.1 | Implement MEAS:VOLT:DC? query |
feat(instruments): implement DMM voltage measurement |
| 13.2 | Implement SENS:VOLT:DC:NPLC command |
feat(instruments): implement DMM NPLC setting |
| 13.3 | Add multimeter tests | test(instruments): add multimeter tests |
Deliverables
- DMM returns DUT output voltage from physics
- Integration time configurable
Sprint 14: TCP Server
Goal: Create async TCP server for instruments.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 14.1 | Create server/tcp_server.py with async server class |
feat(server): add async TCP server |
| 14.2 | Implement connection handling and command dispatch | feat(server): implement command dispatch |
| 14.3 | Create server/main.py entry point |
feat(server): add server entry point |
| 14.4 | Add server integration tests | test(server): add TCP server tests |
Deliverables
- Server listens on configured ports
- Routes commands to correct instrument
- Runs physics engine in background
Sprint 15: HAL Interfaces
Goal: Define hardware abstraction protocols.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 15.1 | Create hal/interfaces.py with all Protocol classes |
feat(hal): add HAL protocol definitions |
| 15.2 | Create hal/factory.py with InstrumentSet and stub factory |
feat(hal): add instrument factory stub |
Deliverables
- IThermalChamber, IPowerSupply, IMultimeter defined
- Factory interface established
Sprint 16: SCPI Drivers
Goal: Create client-side SCPI drivers.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 16.1 | Create drivers/base.py with common driver functionality |
feat(drivers): add driver base class |
| 16.2 | Create drivers/thermal_chamber.py |
feat(drivers): add thermal chamber driver |
| 16.3 | Create drivers/power_supply.py |
feat(drivers): add power supply driver |
| 16.4 | Create drivers/multimeter.py |
feat(drivers): add multimeter driver |
Deliverables
- Drivers send SCPI commands via transport
- Parse responses into Python types
Sprint 17: HAL Implementations
Goal: Implement HAL using drivers.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 17.1 | Create hal/impl/thermal_chamber.py |
feat(hal): implement ThermalChamberHAL |
| 17.2 | Create hal/impl/power_supply.py |
feat(hal): implement PowerSupplyHAL |
| 17.3 | Create hal/impl/multimeter.py |
feat(hal): implement MultimeterHAL |
| 17.4 | Implement InstrumentFactory.create() |
feat(hal): implement instrument factory |
| 17.5 | Add HAL integration tests | test(hal): add HAL integration tests |
Deliverables
- HAL classes wrap drivers
- Factory creates connected instrument set
Sprint 18: Test Executive (Core)
Goal: Create test execution framework.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 18.1 | Create executive/models.py with domain models |
feat(executive): add test domain models |
| 18.2 | Create executive/context.py with TestContext |
feat(executive): add test context |
| 18.3 | Create executive/logger.py with test logger |
feat(executive): add test logger |
| 18.4 | Create executive/limits.py with limit checker |
feat(executive): add limit checker |
Deliverables
- Can create test contexts
- Can log measurements
- Can evaluate limits
Sprint 19: Test Executive (Sequencer)
Goal: Implement test sequencer.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 19.1 | Create executive/sequencer.py with TestSequencer class |
feat(executive): add test sequencer |
| 19.2 | Create tests/base.py with ITest protocol |
feat(tests): add test base class |
| 19.3 | Add sequencer tests | test(executive): add sequencer tests |
Deliverables
- Sequencer runs test instances
- Manages context lifecycle
Sprint 20: TempCo Test Implementation
Goal: Implement temperature coefficient characterisation test.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 20.1 | Create tests/tempco.py with TempCoTest class |
feat(tests): add TempCo test stub |
| 20.2 | Implement temperature sweep logic | feat(tests): implement TempCo temperature sweep |
| 20.3 | Implement TempCo calculation | feat(tests): implement TempCo calculation |
| 20.4 | Add TempCo test tests | test(tests): add TempCo test coverage |
Deliverables
- Complete TempCo characterisation test
- Calculates ppm/°C result
Sprint 21: Data Persistence (Schema)
Goal: Set up data storage.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 21.1 | Create data/models.py with data models |
feat(data): add data models |
| 21.2 | Create data/migrations/001_initial.sql |
feat(data): add initial schema migration |
| 21.3 | Create data/repository.py with repository interface |
feat(data): add repository interface |
Deliverables
- SQLite schema defined
- Repository interface established
Sprint 22: Data Persistence (Implementation)
Goal: Implement data repository.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 22.1 | Implement SQLite repository for test runs | feat(data): implement test run persistence |
| 22.2 | Implement Parquet writer for measurements | feat(data): implement measurement persistence |
| 22.3 | Add repository tests | test(data): add repository tests |
Deliverables
- Test runs persisted to SQLite
- Measurements saved as Parquet files
Sprint 23: CLI (Basic)
Goal: Create command-line interface.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 23.1 | Create cli/main.py with Typer app |
feat(cli): add CLI application |
| 23.2 | Add server start command |
feat(cli): add server start command |
| 23.3 | Add test run command |
feat(cli): add test run command |
| 23.4 | Add test list command |
feat(cli): add test list command |
Deliverables
thermaulate server startlaunches simulationthermaulate test run tempcoexecutes test
Sprint 24: Streamlit Dashboard (Basic)
Goal: Create real-time monitoring dashboard.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 24.1 | Create dashboard/app.py with main Streamlit app |
feat(dashboard): add Streamlit app |
| 24.2 | Create instruments status page | feat(dashboard): add instruments page |
| 24.3 | Add real-time temperature chart | feat(dashboard): add temperature chart |
Deliverables
- Dashboard shows instrument status
- Temperature updates in real-time
Sprint 25: Integration & Polish
Goal: End-to-end testing and refinement.
Tasks
| # | Task | Commit Message |
|---|---|---|
| 25.1 | Run full TempCo test end-to-end | test: add end-to-end TempCo test |
| 25.2 | Fix any integration issues discovered | fix: resolve integration issues |
| 25.3 | Add demo script | docs: add demo script |
| 25.4 | Update README with usage instructions | docs: update README with usage |
| 25.5 | Verify 80% test coverage on core modules | test: ensure coverage targets met |
Deliverables
- Complete working vertical slice
- Demo-able system
- Documentation updated
Sprint Summary
| Sprint | Focus | Estimated Tasks |
|---|---|---|
| 1 | Project scaffolding | 5 |
| 2 | Configuration | 3 |
| 3-4 | Transport layer | 7 |
| 5 | SCPI parser | 3 |
| 6-9 | Physics engine | 16 |
| 10-13 | Virtual instruments | 14 |
| 14 | TCP server | 4 |
| 15-17 | HAL layer | 10 |
| 18-19 | Test executive | 7 |
| 20 | TempCo test | 4 |
| 21-22 | Data persistence | 6 |
| 23 | CLI | 4 |
| 24 | Dashboard | 3 |
| 25 | Integration | 5 |
Total: 25 sprints, ~91 tasks, ~91 commits
LLM Optimisation Notes
Each sprint is designed for LLM execution with:
- Minimal Context Required - Each sprint focuses on 1-2 files
- Clear Boundaries - Interfaces defined before implementations
- Testable Increments - Each sprint has verification criteria
- Atomic Commits - Small, focused changes that are easy to review
- Stub-First Approach - Type-safe placeholders before full logic
When starting a sprint:
- Read only the relevant module's existing code
- Reference interfaces/protocols, not implementations
- Complete all tasks before moving to next sprint
- Commit after each task
End of Development Plan