Skip to content

Split Gen1 and Gen2 handling into per-generation strategies - #56

Merged
jfmlima merged 5 commits into
mainfrom
refactor/generation-seam
Jul 29, 2026
Merged

Split Gen1 and Gen2 handling into per-generation strategies#56
jfmlima merged 5 commits into
mainfrom
refactor/generation-seam

Conversation

@jfmlima

@jfmlima jfmlima commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Purpose

Cut the generation seam: restore and capture get per-generation strategies, the Gen1 wire knowledge moves to a pure domain service, and the three ad hoc generation representations collapse into one domain value.

Context

Follow-on refactor to #51 (design doc: the generation-seam plan reviewed after PR #53). restore_device_config.py owned two complete protocols in ~950 lines, the Gen1 wire tables lived inside a use case whose job is orchestration, and generation was reconciled inline in three shapes (device gen int, backup label string, missing /shelly field). The contract is zero behavior change: every existing test passes with only import moves and fixture relocation, and the literal Gen1 wire-param pins now run against the pure translation service with no mocks. Reviewed commit by commit it reads as code moved and names introduced.

Notes

The legacy mapper now declares component actions as a first-class available_actions list on its payload instead of the private attrs key the domain entity used to reach into; nothing in the repo consumed the old shape. Two independent adversarial reviews (Codex plus a fresh agent) found no behavior drift in any runtime flow.

@jfmlima jfmlima self-assigned this Jul 29, 2026
jfmlima added 5 commits July 29, 2026 16:36
Move the Gen1 wire knowledge (settable-param allowlists, GET-vs-setter renames, section layout) out of RestoreDeviceConfig into the pure domain service gen1_settings_translation, exposing restorable_params and wifi_subresources. The literal wire-param pinning tests move with it and now run against the pure functions with no mocked gateway.
RestoreDeviceConfig keeps orchestration only: backup lookup, identity and generation checks, selection and ordering, unknown-key surfacing, aggregation, and the reboot-if-applied rule. The Gen2 path (SetConfig/PutCode/Schedule.Replace, read-only strip) and the Gen1 path (raw-settings replay, mode pre-phase, WiFi fan-out, legacy reboot) move unchanged into ComponentRestoreStrategy implementations under use_cases/restore_strategies.

Strategies are constructed per restore run from the injected gateway: the Gen1 strategy holds the loaded settings between prepare and the component loop, and the use case is a container singleton, so a shared strategy instance would leak state across concurrent restores. The public constructor keeps its signature; the mode timing kwargs are forwarded to the Gen1 strategy.
The generation reached the code in three raw shapes reconciled ad hoc at each site: the integer gen a device status reports, the gen1/gen2 labels stored on backups, and the missing-gen shape of a Gen1 /shelly response. The Generation value object now owns all three constructions; backup capture, restore reconciliation and strategy selection, the bulk-export divert, and the AP detector's Gen1 refusal all go through it. GEN2 covers the whole RPC family since Gen2+ devices share one surface; provisioning keeps the literal int where it reports gen 2 vs 3.
export_bulk_config keeps the export envelope and the per-device loop; how one generation's component configs are captured (Gen2 GetConfig/GetCode/Schedule.List vs the Gen1 mapped-config copy plus raw /settings fetch) moves unchanged into ComponentCaptureStrategy implementations under use_cases/capture_strategies.

LEGACY_SETTINGS_KEY moves to the device_backup entity: it names part of the snapshot format, which capture and restore now both consume from the same home.
DeviceStatus.from_raw_response reached into the legacy mapper's private attrs key to merge Gen1 actions into available_actions, so the domain entity knew the mapper's internals. The mapper now declares each component's actions as a first-class available_actions list on its payload, and the entity merges any declared list generically with the actions derived from the RPC method list. attrs keeps only the gateway-private routing keys.
@jfmlima
jfmlima force-pushed the refactor/generation-seam branch from c7d2bb2 to 9645b1f Compare July 29, 2026 15:37
@jfmlima
jfmlima marked this pull request as ready for review July 29, 2026 15:41
@jfmlima
jfmlima merged commit 01df08d into main Jul 29, 2026
18 checks passed
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.

1 participant