Skip to content

refactor(zwave): extract schedules and configuration templates#4731

Draft
AlCalzone wants to merge 23 commits into
alcalzone-backend-refactor-hass-lifecyclefrom
alcalzone-backend-refactor-schedules-templates
Draft

refactor(zwave): extract schedules and configuration templates#4731
AlCalzone wants to merge 23 commits into
alcalzone-backend-refactor-hass-lifecyclefrom
alcalzone-backend-refactor-schedules-templates

Conversation

@AlCalzone

@AlCalzone AlCalzone commented Jul 11, 2026

Copy link
Copy Markdown
Member

Extracts schedule and configuration-template behavior behind the ZwaveClient facade.

  • Preserves dynamic API results, slot mutation semantics, cancellation behavior, and template identity.
  • Keeps restart-driven driver swaps behind live ports.
  • Review focus: write verification, missing-user-code behavior, and exact update payloads.

Part of #4722. Stacked on #4730.

@coveralls

coveralls commented Jul 11, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 29571819291

Warning

No base build found for commit 68413f5 on alcalzone-backend-refactor-hass-lifecycle.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 49.323%

Details

  • Patch coverage: 35 uncovered changes across 3 files (340 of 375 lines covered, 90.67%).

Uncovered Changes

File Changed Covered %
api/lib/ZwaveClient.ts 40 9 22.5%
api/lib/zwave/ScheduleService.ts 142 139 97.89%
api/lib/zwave/ConfigurationTemplateService.ts 192 191 99.48%
Total (4 files) 375 340 90.67%

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 7277
Covered Lines: 3753
Line Coverage: 51.57%
Relevant Branches: 4612
Covered Branches: 2111
Branch Coverage: 45.77%
Branches in Coverage %: Yes
Coverage Strength: 33.16 hits per line

💛 - Coveralls

@AlCalzone
AlCalzone marked this pull request as draft July 11, 2026 21:11
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-hass-lifecycle branch 2 times, most recently from 7b7c46f to 0209976 Compare July 16, 2026 13:33
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-schedules-templates branch from 89a3ab8 to d09a565 Compare July 16, 2026 14:19
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-hass-lifecycle branch from 0209976 to 331f854 Compare July 16, 2026 19:48
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-schedules-templates branch from d09a565 to 978a891 Compare July 16, 2026 20:12
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-hass-lifecycle branch from 331f854 to 68413f5 Compare July 17, 2026 09:23
AlCalzone and others added 20 commits July 17, 2026 11:50
… services

Extract port interfaces and re-exported types for ScheduleService and
ConfigurationTemplateService into api/lib/zwave/ports.ts. Ports use
lazy closures to resolve current driver/nodes/store across restarts.

- ScheduleDriverPort, ScheduleNodeStorePort, ScheduleUtilsPort
- TemplateDriverPort, TemplateNodeStorePort, TemplatePersistencePort
- TemplateUtilsPort, ServiceLogger
- Re-export schedule/template types from ZwaveClient

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move all schedule locking/cancel sequencing and Schedule Entry Lock CC
interactions into a focused, strict-clean ScheduleService.

Public API (exact signatures preserved):
- getSchedules, cancelGetSchedule, setSchedule, setEnabledSchedule

Internal state:
- _lockGetSchedule, _cancelGetSchedule (restart-safe via port closures)

Static helper:
- _pushSchedule (slot insert/update/remove)

0 strict-mode errors in new file (-51 total strict errors).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move template collection, CRUD, content hashing, auto-apply logic,
firmware matching, and persistence into ConfigurationTemplateService.

Public API (exact signatures preserved):
- getConfigurationTemplates, getDeviceConfigurationParams
- createConfigurationTemplate, updateConfigurationTemplate
- deleteConfigurationTemplate, applyConfigurationTemplate
- importConfigurationTemplates, checkConfigurationTemplates

Static helper: _generateContentHash (exposed for testing)
Internal: _cleanupAppliedHashes, _getMatchingTemplates, _autoApplyToNodes

0 strict-mode errors in new file. Uses getErrorMessage() for lint-safe
error stringification.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…vices

Replace inline schedule/template code with thin one-line delegations
to _scheduleService and _configTemplateService. Services are constructed
in init() with port closures that resolve current state across restarts.

- All 110 allowedApis entries preserved in exact order
- All public signatures unchanged (including underscore APIs)
- callApi behavior unchanged
- ZwaveClient LOC: 9002 → 8185 (-817 lines, -9.1%)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
90 deterministic tests across two new test files:

ScheduleService.test.ts (28 tests):
- Construction, cancel flag, CC not supported, lock contention
- getSchedules: cached data, cancellation, null userCodes, mode filtering
- setSchedule: types (weekly/daily/yearly), readback verify/mismatch, delete
- setEnabledSchedule: single/all users, enable/disable, no userCodes
- _pushSchedule: add/update/remove paths

ConfigurationTemplateService.test.ts (62 tests):
- CRUD: create from CC112/custom values, propertyKey, edge cases
- Update: hash recalculation, auto-apply trigger
- Delete: hash cleanup, not found
- Apply: success/error/dead node/force/undefined values
- Import: new IDs, legacy migration, duplicate handling
- checkConfigurationTemplates: auto-apply, firmware range, catch handler
- _autoApplyToNodes: skip non-ready, skip already-applied, error logging
- _generateContentHash: deterministic, firmware range, null normalization

Per-file coverage:
- ScheduleService.ts: 96% stmts, 89% branches, 100% funcs, 98% lines
- ConfigurationTemplateService.ts: 91% stmts, 88% branches, 93% funcs, 93% lines

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Treat null/undefined getSupportedUsersCached result as zero iterations
instead of early-returning. The service still populates supported slot
counts, builds the schedule structure, sets userCodes state, emits the
node update, and returns node.schedule — matching the base flow exactly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Replace invalid dayOfWeek/weekday fields with production-valid
  upstream types: weekday (ScheduleEntryLockWeekday) for weekly,
  weekdays[] for daily repeating schedules
- Remove all as-any casts from schedule payloads; use proper
  ScheduleEntryLockSlotId & schedule type intersections
- Assert exact upstream CC method/call arguments for each schedule mode
- Explicitly assert other mode readers/writers are NOT called
- Add regression tests for undefined/null userCodes: assert result,
  slot counts, emission order, and zero iterations

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Assert exact writeValue arguments in order (nodeId, CC, endpoint,
  property, propertyKey, value) including partial-failure sequences
- Add getDeviceConfigurationParams test with mocked ConfigManager:
  assert lookupDevice ordering (manufacturer, productType, productId)
  and exact output mapping including bitmask propertyKey, readOnly,
  options/states, and newValue
- Assert zero writes for max-firmware and missing-firmware exclusions
- Assert exact warning level and message for partial failure (distinct
  from info log); assert exact error level for rejected auto-apply
- Force applyConfigurationTemplate to reject via spy and verify outer
  catch handler logs error with expected message
- Remove all as-any casts; use proper type imports

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove module-level JSDoc headers that narrate extraction history,
section-divider comment blocks, inline comments that restate code or
assertion intent, and changelog-style remarks. Retain non-obvious
why-comments (slot mutation semantics, re-export rationale) and
lint-disable directives. Rewrite one comment to action-first form.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove tests whose subject was internal state or private helpers:
- ScheduleService: delete 'construction and initial state',
  direct 'cancelGetSchedule' flag test, and '_pushSchedule (static)' tests
- ConfigurationTemplateService: delete '_generateContentHash (static)'
  and 'templates accessor' live-array identity test

Replace with production-contract tests through public API:
- getSchedules slot management: add/replace/remove cached slots observed
  through returned schedule structure
- Recovery behavior: subsequent getSchedules succeeds after rejection
- Cancellation: observed through undefined return + recovery, not flags
- contentHash invariants: deterministic 12-char hex, firmware range effect,
  null/undefined propertyKey normalization tested via create/import

Retain minimal getter assertions only where they represent consumer-
observable state (lock indicator during in-flight request, cancel flag
during active cancellation).

Reviewed-by: cross-stack-audit

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep schedule and template tests focused on observable production behavior and remove restating comments introduced during the helper-test rewrite.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Drop unused schedule state and template collection accessors after moving their coverage to observable service contracts.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Match the pre-extraction node-update fields and missing-user-code behavior for schedule enablement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Restore comments that convey genuine domain/protocol facts the
surrounding code cannot show: port closure semantics for driver
restart survival, Z-Wave supervision readback rationale, Schedule
Entry Lock single-active-mode constraint, and deviceId format
parsing/reorder quirk in the test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…serCodes

The setEnabledSchedule all-users path previously manufactured a
TypeError to preserve a raw crash. Replace with a guard that skips
the bulk enable/disable when node.userCodes is undefined, matching
the single-user path's optional chaining behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…lateService

Replace module-level ConfigManager singleton with a
TemplateConfigManagerPort injected through the constructor.
ZwaveClient wires the production instance. Tests pass a narrow mock
directly instead of spying on ConfigManager.prototype.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Derive the injected port from ConfigManager and remove broad casts and invalid fixtures from service tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the CommandClasses.Configuration enum instead of the hardcoded
numeric literal 112 in getDeviceConfigurationParams return values
and ID construction.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…e tests

- Replace raw commandClass 112 with CommandClasses.Configuration
- Replace raw userIdStatuses 1 with UserIDStatus.Enabled
- Rename describe/it labels that referenced private helpers
  (_getMatchingTemplates, _autoApplyToNodes) or raw CC numbers
- Replace ReturnType<typeof vi.fn> casts with vi.mocked()
- Remove undocumented hash-format assertions (12-char hex length)
  while keeping determinism test
- Drop implementation-detail suffixes from test names

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
AlCalzone and others added 3 commits July 17, 2026 11:50
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@AlCalzone
AlCalzone force-pushed the alcalzone-backend-refactor-schedules-templates branch from 978a891 to ed906c3 Compare July 17, 2026 09:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants