fix(scope_definition): remove ignore_changes masking a redundant depends_on drift bug#438
Merged
sebastiancorrea81 merged 4 commits intoJul 15, 2026
Merged
Conversation
added 3 commits
July 14, 2026 16:11
…lly drift
service_specification.attributes: the API silently persists a `values = {}`
key that the rendered template never sets, causing perpetual drift on every
plan. Mirror it in config via merge() instead of hiding the diff.
service_specification.name/type, scope_type.status, action_specification.
name/annotations/parameters/results/retryable/icon: verified via repeated
plan+apply+plan cycles to never actually drift; removed from ignore_changes
so real changes are no longer masked.
scope_type.provider_type and action_specification.type: confirmed root
cause via forced-drift testing — both are populated from a data.external
keyed on service_specification.id, so ANY pending change on
service_specification (even unrelated ones, like the attributes fix above)
replans them as (known after apply). Since both are ForceNew, this forces
a phantom destroy+recreate — of scope_type, and of every
action_specification instance at once. These two must stay ignored.
…place data.external.scope_type and data.external.action_specs each carried an explicit `depends_on = [nullplatform_service_specification.from_template]` that was already redundant — both implicitly depend on that resource via SERVICE_SPECIFICATION_ID (derived from its .id). The explicit whole-resource depends_on made OpenTofu defer the entire data read to apply-time whenever service_specification had ANY pending change, marking their results `(known after apply)`. Since provider_type/type are ForceNew, that phantom unknown forced a destroy+recreate of scope_type and of every action_specification instance. Removing the redundant depends_on eliminates the cascade at the source: confirmed via forced-drift testing that scope_type and action_specification show zero diff even while service_specification has a real pending change. This makes the previous ignore_changes=[provider_type]/[type] workaround unnecessary — removed along with the comments explaining it.
source/type on nullplatform_notification_channel had no explicit resource-level depends_on and no cascade risk (their inputs come from already-known module output variables from scope_definition, which no longer produces phantom unknowns after the earlier fix). Verified via repeated plan+apply+plan cycles, including forcing a real drift upstream in service_specification, that neither field ever drifts or cascades. replace_triggered_by on terraform_data.api_key_trigger is untouched — it's a deliberate mechanism to rotate the notification channel when api_key changes, unrelated to this drift investigation.
agustincelentano
approved these changes
Jul 15, 2026
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.
Summary
nullplatform_service_specification.attributes: the API silently persists avalues = {}key that the rendered template never sets. Now mirrored viamerge({ values = {} }, ...)instead of masking it withignore_changes.provider_type(scope_type) andtype(action_specification) "phantom replace" issue:data.external.scope_typeanddata.external.action_specseach carried a redundant, explicitdepends_on = [nullplatform_service_specification.from_template], on top of the implicit dependency already created viaSERVICE_SPECIFICATION_ID. That explicit whole-resourcedepends_ondeferred the entire data read to apply-time wheneverservice_specificationhad any pending change, markingprovider_type/typeas(known after apply)— and since both areForceNew, this forced a phantom destroy+recreate ofscope_typeand of everyaction_specificationinstance at once.ignore_changesonscope_type,action_specification, andnullplatform_notification_channel(inscope_definition_agent_association) — all verified field-by-field to never actually drift.How this was verified
ignore_changesone at a time, thenplan→apply→planto confirm no drift.attributesdrift while thedepends_onwas still in place) — confirmedscope_typeand all 15action_specificationinstances showedmust be replaced.depends_onand re-ran the same forced-drift scenario — confirmed zero diff onscope_type/action_specificationeven with a real pending change onservice_specification.destroy→init→validate→plan(21 to add) →apply(21 added) →planagain —No changes, confirming no drift even from a fresh create, with zeroignore_changesleft in either module.Test plan
tofu validateclean, no warnings (previously had a "Redundant ignore_changes element" warning onstatus)tofu planshows no changes against existing statescope_type/action_specification