feat: Add always_enabled configuration option for machines - #66
Conversation
Add comprehensive documentation for Claude Code to assist with development, including common commands, architecture overview, and key implementation details. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive implementation plan for always-enabled machine feature, breaking down the work into 4 milestones with specific tasks and acceptance criteria. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 1 complete: Added always_enabled configuration option to Machine model. Changes: - Updated CONFIG_SCHEMA to include optional always_enabled boolean property - Added always_enabled attribute to Machine class with default value False - Updated Machine.as_dict property to include always_enabled field - Updated existing tests to expect always_enabled in as_dict output - Updated feature document with Milestone 1 completion status All existing tests passing (141/141). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 2 complete: Implemented always-enabled machine logic in MachineState. Changes: - Added ALWAYS_ON_DISPLAY_TEXT constant to MachineState class - Updated MachineState.update() to handle always-enabled machines: * After oops handling, check if machine.always_enabled is True * If always-enabled and not oopsed/locked: set relay on, display "Always On", green LED * Skip RFID processing for always-enabled machines - Updated unoops() method to restore always-on state when un-oopsing always-enabled machines - Updated feature document with Milestone 2 completion status All existing tests passing (141/141). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3 in progress: Added comprehensive unit tests for always-enabled machines. Changes: - Created test_machine_always_enabled.py with 5 comprehensive tests: * test_always_enabled_basic: Tests relay on and "Always On" display * test_always_enabled_oopsed: Tests oops and un-oops behavior * test_always_enabled_ignores_rfid_insert: Tests RFID insert is ignored * test_always_enabled_ignores_rfid_remove: Tests RFID remove is ignored * test_always_enabled_first_contact: Tests immediate enable on first contact - Added always-on-machine to fixtures/machines.json - Fixed test expectations for machine count (5 -> 6) - Updated Slack handler tests to include always-on-machine in status output - Partially updated Prometheus test fixtures (LED metrics complete) Status: 143/146 tests passing Remaining: Complete Prometheus test fixture updates for all metric types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 3 complete: All unit tests written and all test fixtures updated. Changes: - Fixed test_always_enabled_oopsed to use DELETE /api/machine/oops endpoint for un-oopsing - Added always-on-machine metrics to all Prometheus test fixtures - Fixed Prometheus LED metric ordering (always-on-machine after esp32test) All 146 tests passing! Test coverage: - Basic always-on behavior ✓ - Oops/un-oops behavior ✓ - RFID insert/remove ignored ✓ - Immediate enable on first contact ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Milestone 4 complete: All acceptance criteria met. Changes: - Updated CLAUDE.md with always_enabled configuration documentation - Verified 100% test coverage - Verified all nox sessions passing (tests, mypy, pre-commit, safety) - Moved feature file to docs/features/completed/ Feature Summary: Added always_enabled boolean option to machine configuration. When enabled: - Machine is always enabled without RFID authentication - Displays "Always On" on LCD - Relay is always on (unless Oopsed or Locked) - RFID card insertions/removals are ignored - Immediately enabled on first server contact Final Status: ✅ All 146 tests passing ✅ 100% code coverage ✅ All quality checks passing ✅ Full documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Pull Request Overview
This PR adds a new always_enabled configuration option for machines that allows them to be always enabled without requiring RFID authentication. Machines with this setting display "Always On" and remain on unless Oopsed or in maintenance lockout.
Key Changes
- Added
always_enabledboolean field to machine configuration schema with appropriate validation - Updated
MachineState.update()to bypass RFID processing for always-enabled machines and maintain "Always On" state - Added 5 comprehensive integration tests covering basic behavior, Oops handling, RFID ignoring, and immediate enablement
Reviewed Changes
Copilot reviewed 11 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/dm_mac/models/machine.py | Added always_enabled configuration field, constant, and state management logic; updated unoops() to restore always-on state |
| tests/views/test_machine_always_enabled.py | New test suite with 5 tests covering always-enabled functionality |
| tests/fixtures/machines.json | Added always-on-machine test fixture |
| tests/models/test_machine.py | Updated machine count assertions and as_dict expectations to include always_enabled field |
| tests/views/test_prometheus.py | Updated Prometheus metrics test fixtures to include always-on-machine entries |
| tests/test_slack_handler.py | Updated Slack handler tests to include always-on-machine in status listings |
| CLAUDE.md | Documented the new always_enabled configuration option |
| docs/features/completed/always-enabled-machine.md | Feature implementation documentation with milestones and status |
| docs/features/README.md | Feature development process documentation |
| docs/source/hardware.rst | Added M12 8-pin connector pinout image reference |
| hardware/v1_mcu/m12-8pinout.png | Binary image file for hardware documentation |
| pyproject.toml | Version bump from 0.2.3 to 0.3.0 (minor version for new feature) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Resolved all 4 Copilot review comments: 1. Updated unlock() to restore always-on state for always-enabled machines - Checks machine.always_enabled and restores appropriate state - Ensures consistent behavior after maintenance lockout 2. Updated _handle_reboot() to restore always-on state for always-enabled machines - Checks machine.always_enabled and sets appropriate state directly - No longer relies on subsequent always-enabled logic in update() 3. Fixed misleading comment in test fixture - Changed "This list is ignored" to "Not used for authentication" - Clarifies that authorizations_or is a schema requirement 4. Added last_update timestamp to always-enabled path - Ensures consistent timestamp tracking across all state change paths - Prevents stale last_update for always-enabled machines Testing: - Added 2 new integration tests: * test_always_enabled_unlock - verifies state restoration after unlock * test_always_enabled_reboot - verifies state restoration after reboot - All 148 tests passing - 100% code coverage maintained 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 11 out of 13 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Implemented RFID value tracking for always-enabled machines to support auditing while maintaining the always-on state. RFID insertions and removals are now logged with user information and session duration. Changes: - Added _handle_rfid_tracking_always_enabled() method to track RFID changes without affecting machine state - Updated always-enabled logic in update() to call tracking method when RFID value changes - Updated test_always_enabled_ignores_rfid_insert() to verify RFID values, current_user, and rfid_present_since are tracked - Updated test_always_enabled_ignores_rfid_remove() to verify RFID removal clears tracked values - Fixed test RFID values to use "8114346998" (Ashley Williams) instead of invalid "1234567890" All 148 tests passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 11 out of 13 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Adds a new
always_enabledboolean configuration option to machines that allows them to be always enabled without requiring RFID authentication. When enabled, machines display "Always On" and remain onunless Oopsed or in maintenance lockout.
Changes
Configuration
always_enabledboolean field to machine configuration schemaalways_enabled: truebypass RFID authentication entirelyCore Implementation
ALWAYS_ON_DISPLAY_TEXTconstant toMachineStateMachineState.update()to handle always-enabled logic:unoops()to restore always-on state after un-oopsingTesting
Documentation
CLAUDE.mdwith configuration detailsUsage Example
Add to
machines.json:{ "dust-collector": { "authorizations_or": ["This list is ignored when always_enabled is true"], "always_enabled": true } }The machine will:
Test Plan
Breaking Changes
None - this is a backward-compatible addition. Existing machines continue to work unchanged.
🤖 Generated with https://claude.com/claude-code