Skip to content

Direct-engine reconcile classification fixes - #5816

Merged
radakam merged 3 commits into
mainfrom
fix/direct-reconcile-classification
Jul 6, 2026
Merged

Direct-engine reconcile classification fixes#5816
radakam merged 3 commits into
mainfrom
fix/direct-reconcile-classification

Conversation

@radakam

@radakamradakam commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Why

Fuzzing the direct engine found fields that UC/serving GET responses either compute or never echo back. They weren't classified, so bundle plan showed a permanent update after deploy and redeploy could fail with 400 ... Nothing to update.

Changes

bundle/direct/dresources/resources.yml:

  • catalogs: skip UC-injected properties['unity.catalog.managed.*'] as backend_defaults (mirrors existing schemas fix).
  • registered_models: browse_onlyignore_remote_changes (output-only, backend-computed, not in update surface).
  • model_serving_endpoints: config.served_entities[*].burst_scaling_enabled + all external-model *_plaintext secrets → ignore_remote_changes (input-only, accepted on write but never returned on GET).

These aren't annotated in the OpenAPI spec, so they're declared manually (absent from resources.generated.yml).

libs/testserver/:

  • catalogs.go / registered_models.go: inject the computed values, scoped to dedicated names (catalog_managed_defaults, model_browse_only).
  • serving_endpoints.go: strip *_plaintext secrets on read (burst_scaling_enabled already wasn't round-tripped).

Tests

New direct-engine acceptance tests asserting no-op plan + no update call on redeploy:

  • acceptance/bundle/resources/catalogs/drift/managed_properties
  • acceptance/bundle/resources/registered_models/drift/browse_only
  • acceptance/bundle/resources/model_serving_endpoints/drift/write_only

@radakam
radakamtemporarily deployed to test-trigger-is July 3, 2026 09:12 — with GitHub Actions Inactive
@radakam
radakamtemporarily deployed to test-trigger-is July 3, 2026 09:12 — with GitHub Actions Inactive
… fields
Several fields returned (or intentionally not returned) by UC/serving GET
responses were not classified, so `bundle plan` reported a perpetual Update
after deploy and could hard-fail with "Nothing to update" on redeploy.
- catalogs: skip UC-injected `unity.catalog.managed.*` properties as
backend defaults (mirrors the existing schemas handling).
- registered_models: treat backend-computed `browse_only` as output-only.
- model_serving_endpoints: ignore remote changes for `burst_scaling_enabled`
and the write-only external-model `*_plaintext` secrets, none of which are
echoed on GET.
The testserver is extended to reproduce each drift (scoped catalog/model
names, and stripping serving secrets on read) and new acceptance tests under
each resource's `drift/` dir lock in the no-op plan and redeploy behavior.
@radakam
radakamforce-pushed the fix/direct-reconcile-classification branch from c01de9a to f4ed131CompareJuly 3, 2026 09:19
@radakam
radakamtemporarily deployed to test-trigger-is July 3, 2026 09:20 — with GitHub Actions Inactive
@radakam
radakamtemporarily deployed to test-trigger-is July 3, 2026 09:20 — with GitHub Actions Inactive
@radakam
radakam marked this pull request as ready for review July 3, 2026 09:21
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 94729f7

Run: 28817024291

Env💚​RECOVERED🙈​SKIP✅​pass🙈​skipTime
💚​aws linux4423010595:01
💚​aws windows4423210576:17
💚​aws-ucws linux443149775:25
💚​aws-ucws windows443169756:00
💚​azure linux4423010585:12
💚​azure windows4423210566:12
💚​azure-ucws linux443169747:24
💚​azure-ucws windows443189726:17
💚​gcp linux4422910604:54
💚​gcp windows4423110586:06
8 interesting tests: 4 RECOVERED, 4 SKIP
Test Nameaws linuxaws windowsaws-ucws linuxaws-ucws windowsazure linuxazure windowsazure-ucws linuxazure-ucws windowsgcp linuxgcp windows
💚​TestAccept💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
🙈​TestAccept/bundle/invariant/no_drift🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/ssh/connection🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
💚​TestFetchRepositoryInfoAPI_FromRepo💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
💚​TestFetchRepositoryInfoAPI_FromRepo/root💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
💚​TestFetchRepositoryInfoAPI_FromRepo/subdir💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
Top 10 slowest tests (at least 2 minutes):
durationenvtestname
5:18azure-ucws windowsTestAccept
5:16gcp windowsTestAccept
5:14azure windowsTestAccept
5:06aws-ucws windowsTestAccept
5:03aws windowsTestAccept
3:00aws linuxTestAccept
2:56azure linuxTestAccept
2:51gcp linuxTestAccept
2:51azure-ucws linuxTestAccept
2:49aws-ucws linuxTestAccept

reason: output_only
- field: updated_by
reason: output_only
# Backend-computed; the user never sets it. Not annotated output_only in the spec.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably annotate browse_only as output-only (or drop it from the create request) in the universe OpenAPI spec so the regenerated SDK stops surfacing it as a writable field.

# Accepted on write but not returned by GET.
- field: config.served_entities[*].burst_scaling_enabled
reason: input_only
# Write-only secrets: the backend stores them and returns the reference field, not the plaintext.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we wild-card match these? there will be more as more models are added

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about that, wildcards can't match *_plaintext, and broader wildcards would also ignore legitimate GET fields. It might be better to mark these fields as write-only in the OpenAPI spec so they're generated automatically, like browse_only, what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on second look there's quite a few different patterns here (I was hoping it'd just be

(?<model>)_config.\1_api_key_plaintext

but that won't work and won't be fun to implement/maintain)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be great if you can fix it upstream 🙌

resources:
catalogs:
catalog1:
name: catalog_managed_defaults

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have acceptance/bundle/invariant/configs/catalog.yml.tmpl why did not it catch this?

Is it because fuzz testing was against dogfood which adds these fields but our test env does not?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly -- the testserver wasn't populating these fields (dogfood does), so there was no drift to catch. I also added that to the testserver so it's now reproducible.

# Accepted on write but not returned by GET.
- field: config.served_entities[*].burst_scaling_enabled
reason: input_only
# Write-only secrets: the backend stores them and returns the reference field, not the plaintext.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on second look there's quite a few different patterns here (I was hoping it'd just be

(?<model>)_config.\1_api_key_plaintext

but that won't work and won't be fun to implement/maintain)

# Accepted on write but not returned by GET.
- field: config.served_entities[*].burst_scaling_enabled
reason: input_only
# Write-only secrets: the backend stores them and returns the reference field, not the plaintext.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be great if you can fix it upstream 🙌

@radakam
radakam enabled auto-merge July 6, 2026 13:08
@radakam
radakamtemporarily deployed to test-trigger-is July 6, 2026 13:12 — with GitHub Actions Inactive
@radakam
radakam disabled auto-merge July 6, 2026 13:28
@radakam
radakamtemporarily deployed to test-trigger-is July 6, 2026 19:17 — with GitHub Actions Inactive
@radakam
radakamtemporarily deployed to test-trigger-is July 6, 2026 19:17 — with GitHub Actions Inactive
@radakam
radakam added this pull request to the merge queueJul 6, 2026
Merged via the queue into main with commit f5640afJul 6, 2026
23 checks passed
@radakam
radakam deleted the fix/direct-reconcile-classification branch July 6, 2026 20:09
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: f5640af

Run: 28820038626

Env❌​FAIL🟨​KNOWN🔄​flaky💚​RECOVERED🙈​SKIP✅​pass🙈​skipTime
💚​aws linux4452999244:46
🔄​aws windows644480100561:49
❌​aws-ucws linux4263297980788:36
❌​aws-ucws windows4264292082597:06
💚​azure linux4452399344:38
🔄​azure windows334478100659:17
❌​azure-ucws linux4244288683883:00
❌​azure-ucws windows4244282885692:33
💚​gcp linux4451499844:03
🔄​gcp windows334469101152:06
23 interesting tests: 12 flaky, 4 FAIL, 3 RECOVERED, 2 KNOWN, 2 SKIP
Test Nameaws linuxaws windowsaws-ucws linuxaws-ucws windowsazure linuxazure windowsazure-ucws linuxazure-ucws windowsgcp linuxgcp windows
🟨​TestAccept💚​R💚​R🟨​K🟨​K💚​R🔄​f🟨​K🟨​K💚​R🔄​f
🔄​TestAccept/bundle/generate/pipeline_and_deploy✅​p🔄​f🔄​f🔄​f✅​p🔄​f🔄​f🔄​f✅​p🔄​f
🔄​TestAccept/bundle/generate/pipeline_and_deploy/DATABRICKS_BUNDLE_ENGINE=direct✅​p🔄​f🔄​f✅​p✅​p🔄​f🔄​f🔄​f✅​p✅​p
🔄​TestAccept/bundle/generate/pipeline_and_deploy/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p✅​p🔄​f✅​p✅​p✅​p✅​p✅​p🔄​f
🔄​TestAccept/bundle/generate/python_job_and_deploy✅​p🔄​f✅​p🔄​f✅​p✅​p🔄​f🔄​f✅​p✅​p
🔄​TestAccept/bundle/generate/python_job_and_deploy/DATABRICKS_BUNDLE_ENGINE=direct✅​p✅​p✅​p✅​p✅​p✅​p🔄​f🔄​f✅​p✅​p
🔄​TestAccept/bundle/generate/python_job_and_deploy/DATABRICKS_BUNDLE_ENGINE=terraform✅​p🔄​f✅​p🔄​f✅​p✅​p✅​p✅​p✅​p✅​p
❌​TestAccept/bundle/invariant/migrate🙈​s🙈​s❌​F❌​F🙈​s🙈​s❌​F❌​F🙈​s🙈​s
❌​TestAccept/bundle/invariant/migrate/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=volume_path_job_ref.yml.tmpl❌​F❌​F❌​F❌​F
🟨​TestAccept/bundle/invariant/no_drift🙈​S🙈​S🟨​K🟨​K🙈​S🙈​S🟨​K🟨​K🙈​S🙈​S
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=volume_path_job_ref.yml.tmpl/READPLAN=❌​F❌​F❌​F❌​F
❌​TestAccept/bundle/invariant/no_drift/DATABRICKS_BUNDLE_ENGINE=direct/INPUT_CONFIG=volume_path_job_ref.yml.tmpl/READPLAN=1❌​F❌​F❌​F❌​F
🔄​TestAccept/bundle/resources/clusters/lifecycle-started✅​p🔄​f✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct✅​p🔄​f✅​p✅​p✅​p✅​p✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/change-name✅​p✅​p🔄​f🔄​f✅​p✅​p✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/dashboards/change-name/DATABRICKS_BUNDLE_ENGINE=terraform✅​p✅​p🔄​f🔄​f✅​p✅​p✅​p✅​p✅​p✅​p
🔄​TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name🙈​S🙈​S🔄​f💚​R🙈​S🙈​S💚​R💚​R🙈​S🙈​S
🔄​TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name/DATABRICKS_BUNDLE_ENGINE=direct🔄​f✅​p✅​p✅​p
🙈​TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/ssh/connection🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
💚​TestFetchRepositoryInfoAPI_FromRepo💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
💚​TestFetchRepositoryInfoAPI_FromRepo/root💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
💚​TestFetchRepositoryInfoAPI_FromRepo/subdir💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R💚​R
Top 50 slowest tests (at least 2 minutes):
durationenvtestname
14:24aws windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
14:05azure windowsTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
12:48gcp windowsTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
11:45gcp linuxTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
11:45azure-ucws linuxTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
9:35gcp windowsTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
9:35azure-ucws windowsTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
9:28aws linuxTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=terraform
8:57aws linuxTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:37aws linuxTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=direct
8:28gcp linuxTestAccept/bundle/resources/clusters/deploy/local_ssd_count/DATABRICKS_BUNDLE_ENGINE=direct
8:24azure linuxTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:59aws linuxTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:55aws-ucws linuxTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:42azure windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
7:37azure linuxTestAccept/bundle/resources/clusters/deploy/data_security_mode/DATABRICKS_BUNDLE_ENGINE=direct
7:34azure windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
7:33gcp linuxTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
7:32aws windowsTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:27gcp windowsTestAccept/bundle/resources/clusters/deploy/local_ssd_count/DATABRICKS_BUNDLE_ENGINE=direct
7:24aws windowsTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:23aws-ucws linuxTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:16aws-ucws windowsTestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:06gcp windowsTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=direct
7:04azure-ucws windowsTestAccept/bundle/resources/apps/lifecycle-started-omitted/DATABRICKS_BUNDLE_ENGINE=direct
7:01azure linuxTestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
6:53aws-ucws windowsTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:52azure-ucws linuxTestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=terraform
6:51azure-ucws windowsTestAccept/bundle/resources/apps/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
6:50gcp linuxTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:40aws-ucws linuxTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=direct
6:39azure-ucws linuxTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:33aws linuxTestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
6:18aws windowsTestAccept/bundle/resources/clusters/deploy/simple/DATABRICKS_BUNDLE_ENGINE=direct
6:17aws-ucws linuxTestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=terraform
5:52aws-ucws linuxTestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:50azure-ucws windowsTestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
5:46azure linuxTestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
5:36aws-ucws linuxTestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=direct
5:33gcp linuxTestAccept/bundle/resources/clusters/deploy/simple/DATABRICKS_BUNDLE_ENGINE=direct
5:29azure-ucws windowsTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
5:28gcp windowsTestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:23azure linuxTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
5:23aws windowsTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=terraform
5:20gcp linuxTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=terraform
5:19aws windowsTestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:10azure-ucws windowsTestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
5:09aws windowsTestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=direct
5:00gcp linuxTestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
4:59azure windowsTestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct

Sign up for freeto 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.

4 participants

@radakam@eng-dev-ecosystem-bot@denik@janniklasrose