apply_update_decky now discriminates three sub-cases: * services list changed → diff old vs new and call _materialise_decky_services_diff (compose up -d for added, stop + rm -f for removed). Mirrors services_live's pattern but doesn't import it — mutator-routed mutations carry a different bus surface (mutation.applied) than the direct API path (decky.<name>.service_added). * forwards_l3 flipped → port publishing changes, which docker can only apply at container-create time. Gated on payload['force'] is true; default raises MutationError so a half-thinking operator can't stomp a live decky. When force=true, _materialise_decky_recreate_base does compose up -d --no-deps --force-recreate. Pre-checked BEFORE the DB write so a refused mutation leaves zero side-effects. * coord-only (x/y) → DB only, no docker work. Ships tests/mutator/test_ops_materialisation.py with focused coverage for every new helper: add_decky/remove_decky/attach_decky/ detach_decky/update_decky/update_lan paths against an active topology, with compose primitives + docker SDK mocked at the source modules so the helpers' lazy imports pick up the stubs. Also covers the pending-topology skip and the force-flag gating.
10 KiB
10 KiB