Collapse expand-on-read reference keys before writing them back - #31
Merged
Merged
Conversation
GET expands references that PUT expects as bare ids or names, so a read-modify-write handed the read shape straight back. The variable override collapse also dropped the value for every source other than context_entity_field and automation_variable — a specific_value override round-tripped as an override with no value, while roundtrip reported clean. Overrides now collapse per value_source through an explicit map, and an unrecognised source raises rather than silently emitting a payload missing its value. Confirmed live: six overrides across five sources survive a GET -> PUT -> GET byte-identical.
annaliu-kizen
approved these changes
Sep 4, 2026
jbedient-kizen
changed the base branch from
feat/permission-group-update
to
main
September 4, 2026 16:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GET expands references that PUT expects narrow —
change_field_value.fields_to_clearcomes back as full field objects, andstart_automation.automation_variable_overridesas a flat list with every reference expanded. The translator handed that read shape straight back to PUT.Because a PUT is a full replace, any automation containing either key 400'd on every write verb —
activate,deactivate,steps add|edit|remove,roundtrip --execute— including on steps nobody touched.automations activateis the flow the spec docs explicitly recommend, and it could not complete on such an automation.Solution
fields_to_clearcollapses to bare field UUIDs.automation_variable_overridescollapses into the write dialect's grouped-by-target-automation shape, narrowing each reference: field references to bare UUIDs, variable references to bare names,specific_valuethrough as-is.The collapse is keyed by payload key, not by
value_source. Which key holds the value is observable on any entry; thevalue_sourcestring that selects it is only knowable from a capture that exercises it. Driving off the key means an override whosevalue_sourcethis code has never seen still round-trips — which is what keeps an automation editable, sinceactivate/deactivate/stepsall PUT the whole automation back and a step nobody touched has to survive the trip.Testing
bin/check.sh— all five steps pass:1468 passed, 4 skipped(+12).Verified live against a disposable tenant on a real automation carrying six overrides across five sources: GET -> PUT -> GET came back byte-identical.
An earlier build of this fix carried through only two keys and silently dropped the override's value whenever
value_sourcewasspecific_value— caught live against a realboolean-typed override, which collapsed to a payload with no value at all whileroundtripstill reported clean. That is why the fixture in this PR is a real capture rather than a synthetic one.Design notes / tradeoffs
An earlier revision raised on an unrecognised
value_source. That was wrong: it would strand an automation Kizen itself accepted, on operations that never touch the override. Carrying the value across is strictly better than both raising and dropping. If the server rejects a carried key, that surfaces as a 400 at write time — which tells you something true about that automation, where refusing to try tells you nothing.automations roundtrip(without--execute) now also says plainly that its validation is client-side only and does not prove the PUT will succeed, rather than reporting "translated + validated" unqualified.Last of six stacked branches.